剑指offer在线编程(08-06)【2】

Date: 2019-08-06

1. 斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

n<=39

第一种方法是在本地进行的递归调试:

def Fibonacci(n):
    # write code here
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return Fibonacci(n - 1) + Fibonacci(n - 2)

print(Fibonacci(7))
# 13

第二种是采用的写成一个list的形式,减少递归调用的时间:

# version: python2.7
# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        s = [0, 1]
        if n < 2:
            return s[n]
        else: 
            for i in range(2,n+1):
                s.append(s[i-1]+s[i-2])
            return s[n]

2.  跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

原题表明的考察的知识点是递归方法的使用,如下方式写递归在页面上不能通过,但是在本地是可以得到正确的结果。

# 跳台阶
def jumpFloor(number):
    # write code here
    if number == 1:
        return 1
    elif number == 2:
        return 2
    else:
        return jumpFloor(number - 1) + jumpFloor(number - 2)
print(jumpFloor(6))
# 13

第二种的方式与斐波那契数列的实现方式一致,可以看出本题的思路与斐波那契数列近似。第n节台阶可以从n-1节台阶跳1级台阶上去,也可以从n-2节台阶跳2级台阶上去,所以跳上第n级台阶的方式=跳上第n-1级台阶的方法+ 跳上第n-2级台阶的方法。

s(n) = s(n-1)+s(n-2),

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

3.  变态跳台阶 (贪心算法知识点考察)

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

分析:本题刚开始并不知道如何具体用贪心算法,分析几组情况之后发现:

number = 1: 1   (1)

number = 2:2   (1,1),(2)

number = 3: 4  (1,1,1),(1,2),(2,1)(3)

number =4: 8  (1,1,1,1),(1,1,2),(1,2,1),(2,1,1),(2,2)(1,3)(3,1)(4)

number =5:16 (1,1,1,1,1),(1,1,1,2),(1,1,2,1),(1,2,1,1),(2,1,1,1),(1,2,2)(2,1,2),(2,2,1),(1,1,3),(1,3,1),(3,1,1),(2,3),(3,2),(1,4),(4,1)(5)

发现规律:结果都是2的次方,则2^(number-1).

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number <= 0:
            return 0
        else:
            return pow(2, number-1)

疑惑:感觉没有真正用到贪心算法也能通过本题的测试! 所以拿到编程题一定要尝试去分析几组例子。也比如昨天的二叉树重建,旋转数组的最小数字、从尾到头的打印链表等都需要分析 分析 分析!!!

4.  矩形覆盖 (递归算法考察)

题目描述

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

发现本题仍然是考察的类似于斐波那契数列那样的递归算法,遂如下实现:

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

5.   二进制中1的个数 (考察知识点:进制转换,补码反码原码)

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        return sum([(n >> i & 1) for i in range(32)])

 

本地调试可以正确返回结果:

def NumberOf1(n):
    # write code here
    if n == 0:
        return 0
    elif n > 0:
        res = 0
        for i in list(bin(n)[2:]):
            res += int(i)
        return res
    else:
        res = 0
        for i in list(bin(abs(n))[2:]):
            res += int(i)
        return 33-res

print(NumberOf1(-15))  #29
print(NumberOf1(-15))  #4

知识点补充1:python的内置进制转换函数的使用

十进制——> 二进制: bin(x), 转换后的二进制数中带有前缀0b  |||二进制——>十进制:int('binary string',2)

十进制 ——> 八进制:oct(x),转换后的八进制数中带有前缀0o  |||八进制——>十进制: int('octal string',8)

十进制 ——>十六进制:hex(x),转换后的十六进制数中带有前缀0x  |||十六进制——>十进制:int('hexadecial string',16)

 

知识补充2:

首先提几个概念: 原码,反码,补码

原码是什么?

原码就是早期用来表示数字的一种方式: 一个正数,转换为二进制位就是这个正数的原码。负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码

举例说明:

int类型的 3 的原码是 11B(B表示二进制位), 在32位机器上占四个字节,那么高位补零就得:

00000000 00000000 00000000 00000011

int类型的 -3 的绝对值的二进制位就是上面的 11B 展开后高位补零就得:

10000000 00000000 00000000 00000011

但是原码有几个缺点,零分两种 +0 和 -0 。很奇怪是吧!还有,在进行不同符号的加法运算或者同符号的减法运算的时候,不能直接判断出结果的正负。你需要将两个值的绝对值进行比较,然后进行加减操作 ,最后符号位由绝对值大的决定。于是反码就产生了。

 

反码是什么 ?

正数的反码就是原码,负数的反码等于原码除符号位以外所有的位取反

举例说明:

int类型的 3 的反码是

00000000 00000000 00000000 00000011

和原码一样没什么可说的

int类型的 -3 的反码是

11111111 11111111 11111111 11111100

除开符号位 所有位 取反

解决了加减运算的问题,但还是有正负零之分,然后就到补码了

 

补码是什么?

正数的补码与原码相同,负数的补码为 其原码除符号位外所有位取反(得到反码了),然后最低位加1.

还是举例说明:

int类型的 3 的补码是:

00000000 00000000 00000000 00000011

int类型的 -3 的补码是

11111111 11111111 1111111 11111101

就是其反码加1

 

最后总结一下:

正数的反码和补码都与原码相同。

负数的反码为对该数的原码除符号位外各位取反。

负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1

 

 

各自的优缺点:

原码最好理解了,但是加减法不够方便,还有两个零。。

反码稍微困难一些,解决了加减法的问题,但还是有有个零

补码理解困难,其他就没什么缺点了

 

喔日,说到这里,估计都晕了,举个栗子把。

5的原码是 00000000000000000000000000000101(四个字节,32位(byte))

5的原码和反码,补码都一样。

-5的原码是其绝对值5的原码基础上将高位上数字设置为1,用来表示正负数(符号位) ,10000000000000000000000000000101

-5的反码就是原码符合外取反得到反码11111111111111111111111111111010

-5的补码就是反码加一得到补码11111111111111111111111111111011

最后补充一句,负数一般用补码来计算。
 

6. 数值的整数次方 (考察知识:数学)

题目描述

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

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        return pow(base, exponent)

更一般化的需要讨论的方法:

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

7.调整数组顺序使奇数位于偶数前面

题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路:该题的思路比较有意思,初始设置两个空列表,分别用于存放奇数和偶数的列表,开始遍历array,遇到奇数就将其放到奇数列表中,遇到偶数就将其放到偶数列表中,最后直接奇数列表+偶数列表就可以了。这样也保证了相对位置。

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        odd = []
        even = []
        for i in array:
            if i %2 == 1:
                odd.append(i)
            else:
                even.append(i)
        return odd + even 

8. 链表中倒数第k个结点

题目描述

输入一个链表,输出该链表中倒数第k个结点。

初始化一个空列表,用于遍历链表时存放相应的节点(而非节点上的val).注意判断k的值,进行调整。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        list1 = []
        while head != None:
            list1.append(head)  # 返回的是整个节点,而非仅仅是节点上的val
            head = head.next
        if k > len(list1) or k <1:
            return   # 此处不能加False
        return list1[-k]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值