面试题64. 求1+2+…+n

题目: 求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例:

输入: n = 3
输出: 6

解题思路

    • 一、不符合系统要求的解法
      • (一)循环累加
      • (二)递归求解
      • (三)求和公式
    • 二、符合系统要求的解法
      • (一)【递归终止角度】逻辑运算符短路求解
      • (二)【循环角度】调用构造函数求解

一、不符合系统要求的解法

求1+2+…+n 有很多种办法,但题目给出了我们限制条件,这就使得我们最常使用的办法不能使用了,我们来看看那些不能用了。

(一)循环累加

这个是大多数人看到这个题的第一个想法,思路也很简单,就是循环累加:

//1.循环
int sumNums(int n) 
{
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=i;
	}
	return sum;
}

但是题目说了不呢使用for ,所以这个办法不能用。

(二)递归求解

for和递归可以转换,这个题目递归解决的思路,也很简单:

  • 递归跳出条件n==1时,return 1;
  • 递归内容:n+=sumNums(n-1),最后返回n即可。

为了理解递归内容我们画个图举例 ,当n=3时:

面试题64. 求1+2+…+n_第1张图片

//2.递归
int sumNums(int n) 
{
	if(n==1)
	{
		return 1; 
	}
	n+=sumNums2(n-1);
	return n;
}

但是我们看到它用到了if,所以这个方法不能用。

(三)求和公式

我们也可以利用数学的等差数列公式求和,代码如下:

//等差公式求和
int sumNums(int n) 
{
	return (1+n)*n/2;
}

但是我们看到使用了乘除,所以也不可以。

二、符合系统要求的解法

(一)【递归终止角度】逻辑运算符短路求解

每当题目要求不能使用常规的关键字和符号时,我们会想到位运算和门电路。解决这个问题的根本是如何循环起来,或者如何让递归终止。我们知道【&&】和【||】逻辑运算符,需要记住一个概念,那就是逻辑运算符的短路效应

  • if(A && B) // 若A为true,还需要判断B;若 A 为 false ,则 B 的判断不会执行(即短路),直接判定 A && B 为 false,这个称为&&短路。
  • if(A || B) // 若A为false,还需要判断B;若 A 为 true ,则 B 的判断不会执行(即短路),直接判定 A || B 为 true,这个称为 || 短路。

那么我们想一下,可以用if时,递归跳出条件为n==1,其他时候都在递归。那么就是如果n>1,不断递归,如果n<1,我们终止递归,用&&逻辑运算符的思想就是:

  • 当n>1成立时,需要递归
  • 当n>1不成立时,终止

总结出来就是 n>1 && (n+=sumNums2(n-1)),当n>1为true,判断后面条件,进行递归;当n>1为false时,直接跳出,返回结果。那我们还是n=3来画图看一下过程:

面试题64. 求1+2+…+n_第2张图片

int sumNums(int n)
{
	n>1 && (n+=sumNums4(n-1));
	return n;
}

(二)【循环角度】调用构造函数求解

上一个办法是如何停止递归,我们还可以想想如何不利用for,让数字循环累加起来。C++是一个面向对象的语言,每个对象都有一个构造函数,如果我们生成多个对象,在构造函数里面进行累加,那么多个对象,多次调用构造,形成了循环累加。那我们需要注意:

  • 因为需要在多个对象之间累加,所以变量类型应该选静态成员变量,它只和类有关,不属于任何一个对象,可以理解为全局变量,上一个对象改变了它的值,下一个对象调用时,数值不会初始化,会保持上次的值。它需要在类外加作用域初始化才可以使用,并且只有静态函数可以调用它。
  • 如何生成多个对象,这就要用到对象数组,指每一个数组元素都是对象的数组,即若一个类有若干个对象,我们把这一系列的对象用一个数组来存放。对象数组的元素是对象,不仅具有数据成员,而且还有函数成员。这样,我们就可以多次调用构造函数。
  • 在一个类里面生成其他类的对象数组,需要用到new来动态开辟数组,最后记得释放。每次生成对象数组之前,需要初始化静态变量。
  • 为啥静态变量需要初始化两次:第一次是类外初始化,否则不可以使用,第二次是为了保证在计算下一次1+2……n时,sum 和 n 清0。如果不写第二次,如果先测试了n=3,此时i=3,sum=6;再测试n=2时,i的初值为3,i++,为4,sum=6+4=10,继续i++,i=5,sum=10+5=15;这个结果是错误的,所以必须在每次生成对象数组前,再次初始化。
class Sum
{
public:
	static int i;
	static int sum;
	Sum()//每生成一个对象,调用一次
	{
		i++;
		sum+=i;
	}
	static int  getsum()//因为返回静态变量
	{
		return sum;
	}
};
int Sum::i=0;//初始化静态成员
int Sum::sum=0;

class Solution 
{
public:
	int sumNums(int n)
	{
		Sum::i=0;//需要初始化,不然b
		Sum::sum=0;
		Sum *obj=new Sum[n];//对象数组
		delete [] obj;
		return Sum::getsum();
	}
};
int main()
{
	Solution s;
	cout<<s.sumNums(3);
}

加油哦!。

你可能感兴趣的:(剑指offer习题练习)