剑指offer66题(Python)——第二天

如果你只做力所能及的事,你就永远无法进步。

7、斐波那契数列

对于斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。

思路:嗯,就是如果你面试的时候用递归的方法就可以准备走人了,我们需要高效的方法。可以利用递推的无后效性,记忆前两个状态。还有一种高级别算法,采用矩阵,算法的时间复杂度只有logN。


# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        a, b = 0, 1
        for _ in range(n):
            a, b = b, a+b
        return a

注:此处要分清楚a=b,b=a+b和a,b = b,a+b的区别,对于后者,其实是b=1,a+b=0+1=1,再赋值给a和b。


8、跳台阶(斐波那契应用1)

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5,  可以总结出f(n) = f(n-1) + f(n-2)的规律
# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number <=0:
            return 0
        else:
            a,b=1,1
            for _ in range(number):
                a,b=b,a+b
            return a

9、变态跳台阶(斐波那契应用2)

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
            跳1级,剩下n-1级,则剩下跳法是f(n-1)
            跳2级,剩下n-2级,则剩下跳法是f(n-2)
            所以f(n)=f(n-1)+f(n-2)+...+f(1)
            因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
            所以f(n)=2*f(n-1)=2^(n-1)
        n=1,有1种方法; n=2,有2种方法; n=3,有4=2^(3-1)种方法;
# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number<0:
            return 0
        else:
            return pow(2,number-1)  //pow()方法返回x^y的值。

10、矩形覆盖(斐波那契应用3)

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:此题的实现方法与跳台阶一样。采用归纳法,得到法f(1)=1,f(2) = 2, f(3) = 3, f(4) = 5,总结出f(n) = f(n-1) + f(n-2)的规律。

更一般的结论,如果用1*m的方块覆盖m*n区域,递推关系式为f(n) = f(n-1) + f(n-m),(n > m)。

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        if number<=0:
            return 0
        else:
            a,b=1,1
            for _ in range(number):
                a,b=b,a+b
            return a

11、二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
            举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count=0
        if n<0:
            n=n&0xFFFFFFFF #把负号去掉,如果负号在后面会陷入死循环
        return bin(n).count('1')
        while n:
            count+=1
            n=(n-1)&n
        return count

注:n=(n-1)&n还可以应用于判断一个整数是不是2的整数次方。一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0。因此,把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0。

 if(((n-1)&n)==0)return true;  
 return false;  

        输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n

    思路:第一步求这两个数的异或,第二步统计异或结果中1的位数 

int count=0;  
int c=0;  
c=m^n;//第一步求这两个数的异或  
while(c!=0){//第二步统计异或结果中1的位数  
   ++count;  
   c=(c-1)&c;  
}  
return count;  

12、数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路:下面第一种是我写的比较“有碍观瞻”的代码,虽然没毛病,但是效率低啊,sad!

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        result = 1.0
        if base==0:
            return False
        if exponent == 0:
            return 1
        for _ in range(abs(exponent)):
            result *= base
        if exponent < 0:
            result =1/result
        return result

完美解决方案:采用递归的思想:n为偶数,a^n=a^n/2*a^n/2;n为奇数,a^n=(a^(n-1)/2)*(a^(n-1/2))*a时间复杂度O(logn)。

# -*- coding:utf-8 -*-
def Power(base, exponent):
    # write code here
    result = 1.0
    p=abs(exponent)
    while(p):
        if(p&1):  #判断奇偶
            result *=base
        base*=base
        p>>=1  #右移运算替代除以2
    if(exponent>0):
        return result
    else:
        return 1/result
今日份正能量——




猜你喜欢

转载自blog.csdn.net/u012114090/article/details/80378349
今日推荐