换个角度

来源:互联网 发布:思科2900路由器端口 编辑:程序博客网 时间:2024/05/01 04:41

下面的题目虽没有太多实际意义,但用来考察发散思维能力很不错。你能想到吗?

对于算法类的问题,思路真的很重要。很多时候都有这种感觉,一旦发现了正确的思路,难题原理如此简单。比如求子数组之和的最大值这个题目,有个算法,简简单单的几行就搞定了。

如果像那样子想,没法解决问题或问题太难,那换个思路吧。平常多考虑几种解法,多从非常规的思路去考虑问题,即使慢一点,我想也是值得的。最终收获的会更多。

发散思维是个厚积薄发的过程,只有拥有宽泛的知识面并对相关领域知识有深入理解才能思路开阔。学习的过程中要多注意融会贯通、总结分析。

 

题目一:求1+2+...+n,要求不能使用乘除法、循环、条件判断以及选择相关的关键词。

分析:我们知道要求1到n的和,除了利用公式,无外乎循环和递归两种思路。但这里限制了不能使用while和for,也不能使用if。怎么样用其它的非常规方法来实现循环和递归呢?

这个问题其实挺难,要求对C++理解足够深刻才能想到。

方法一:

利用构造函数和静态成员变量。先想想………………………

 

我们知道在创建对象的时候,构造函数会被自动调用。类的静态程序变量可以被该类的任何对象访问,并且先于对象存在。方法一就是利用这两点来实现循环求和。

下面的代码一看就知道明白了。

class A {public:A(){sum += ++n;}static void reset(){n = 0;sum = 0;}static int getSum(){return sum;}private:static int n;static int sum;};int A::n = 0;int A::sum = 0;int sum(int n){A::reset();A *p = new A[n];int s = A::getSum();delete [] p;return s;}

方法二:利用虚函数

我们同样也可以围绕递归做文章。这是种很巧妙的方法。我们利用两个函数,一个来实现递归,一个用来终止递归。

class A;A *pFun[2];class A {public:virtual int sum(int n){return 0;}};class B: public A {public:int sum(int n){return pFun[!!n]->sum(n-1) + n;}};int sum(int n){A a;B b;pFun[0] = &a;pFun[1] = &b;return pFun[1]->sum(n);}

方法三:利用函数指针

这种方法类似于上一种方法,其实比上一种更直观,且不需要虚函数的支持,在C语言中也可以用。
typedef int (*pFunc)(int n);pFunc pFuncArray[2];int sum1(int n){return 0;}int sum2(int n){return pFuncArray[!!n](n-1) + n;}int sum(int n){pFuncArray[0] = sum1;pFuncArray[1] = sum2;return pFuncArray[1](n);}

上面的方法中,我觉得很巧妙的地方在于利用!!n把n映射为布尔值、利用构造函数来实现循环、利用函数指针来实现递归。


题目二:不用加法、乘除做加法

一般都能立即想到用位运算,但要想出一种简洁的方法可不容易。我们先来考虑如何做十进制加法。以11+9为例,我们先不考虑进位,对应位相加得10。然后再来考虑进位,个位数相加有进位,这个进位就相当于已求得的部分和加上当前位的权值乘以10,即10+1*10 = 20。

我们以类似的方法来考虑二进制加法。以1011 + 1001为例,对应位相加得0010。然后考虑进位,1011

    +1001

可以看到左起1位和4位有进位。关键在于怎么考虑这个进位。类似于10进制加法,这里的进位相当于已求得的部分和加上当前位权值乘二。再进一步考虑,乘与二等价于左移一位。我们知道只有对应两位都为1时才产生进位。那么两数按位与,得到的结果中为1的位就是加法中产生进位的位。我们把两个加数按位与得到的结果左移一位再与已经求得的部分和做或操作,就相当于处理了进位。当然有时候需要这样处理多次,因为会产生新的进位。我们要这样处理直到不再有新的进位为止。

总的说来分为两步:1 是对应位相加,这和异或运算的结果一样。

                  2 进位,两数按位与左移一位,再与已求得的部分和做或运算。

代码如下:

int add(int a, int b){int sum, carry;do{sum = a^b;carry = (a&b)<<1;a = sum;   //已求得的部分和b = carry;  //新的进位}while(b);return a;}

可以输入正数、负数、0进行测试。

题目三:不定义新的变量交换两个整数的值

方法一:

a = a+b;
b = a-b;
a = a-b;

方法二:

a = a^b;
b = a^b;
a = a^b;

参考:《剑指offer - 名企面试官精解典型编程题》

原创粉丝点击