剑指Offer算法类题目[Python版]

斐波拉契数列

面试题007 斐波拉契数列

题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。n<=39
解题思路:利用dp[i]=dp[i-1]+dp[i-2]
代码

class Solution:
    def Fibonacci(self, n):
        # write code here
        f1 = 0
        f2 = 1
        if n== 0:
            return f1
        elif n==1:
            return f2
        for _ in range(n-1):
            f2, f1 = f1+f2, f2
        return f2

面试题008 跳台阶

题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
解题思路:假设第n节台阶有f(n)种跳法。f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)
代码

class Solution:
    def jumpFloor(self, number):
        # write code here
        f0 = 0
        f1 = 1
        f2 = 2
        if number == 0:
            return f0
        if number == 1:
            return f1
        if number == 2:
            return f2
        for _ in range(number-2):
            f2, f1 = f1+f2, f2
        return f2%1000000007

面试题009 变态跳台阶

题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路:f(1)=1 f(2)=2 f(3)=4 f(4) = 8 ... 得到f(n+2)=2f(n+1)
代码

class Solution:
    def jumpFloorII(self, number):
        # write code here
        f1 = 1
        if number == 1:
            return f1
        for _ in range(number-1):
            f1 = 2*f1
        return f1

面试题010 矩形覆盖

题目描述:我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
解题思路:f(1)=1 f(2)=2 f(n)=f(n-1)+f(n-2)
代码

class Solution:
    def rectCover(self, number):
        # write code here
        if number == 0:
            return 0
        f1 = 1
        f2 = 2
        if number == 1:
            return f1
        if number == 2:
            return f2
        for _ in range(number-2):
            f2, f1 = f1+f2, f2
        return f2

搜索算法

面试题001 二维数组查找

题目描述:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
解题思路:分治解题 从右上角(或左下角)开始查找,target更大 指针下移 target更小 指针左移
代码

function Find(target, array)
{
    // write code here
    if(array.length != 0) {
				var row=0;
				var col=array[0].length - 1;
				while(row<array.length&&col>=0) {
					if(array[row][col]==target) {
						return true;
					}else if(array[row][col]<target) {
						++row;
					}else {
						--col;
					}
				}
				return false;
			}
}

面试题006 旋转数组的最小数字

题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路:From 牛客剑指offer
二分查找变形
二分查找分为三种情况讨论:
1.如果mid > high那么mid一定不是最小的,所以low = mid + 1
2.如果mid < high那么mid可能是最小的,也可能不是,所以high = mid
3.如果mid == high,情况比较特殊例如[0, 1, 1, 1]和[1, 1, 0, 1],这种只能一个个试high = high -1
题目中给的旋转数组是非递减而不是递增,所以一定要考虑第三种情况
代码

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
 
        lowp = 0
        highp = len(rotateArray) - 1
 
        while lowp < highp:
            mid = (lowp + highp) // 2
            if rotateArray[mid] < rotateArray[highp]:
                highp = mid
                continue
 
            if rotateArray[mid] > rotateArray[highp]:
                lowp = mid + 1
                continue
 
            if rotateArray[mid] == rotateArray[highp]:
                highp = highp - 1
 
        return rotateArray[lowp]

解题思路:From 牛客剑指offer
非递减是指列表list[i]<=list[i+1],list[2:]中存在一个最小数
代码

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        for i in range(len(rotateArray)-1):
            if(rotateArray[i+1]<rotateArray[i]):
                return rotateArray[i+1]
        return -1

面试题037 数字在排序数组中出现的次数

题目描述:统计一个数字在排序数组中出现的次数。
解题思路:通过两次二分查找,递归中直接计算k的个数
代码

class Solution:
    def GetNumberOfK(self, data, k):
        if not data:
            return 0
        return self.helper(data,k)
 
    def helper(self,data,k):
        if not data:
            return 0
        left, right = 0, len(data) - 1
        mid = (left + right) // 2
        if data[mid] > k:
            return self.helper(data[:mid], k)
        elif data[mid] < k:
            return self.helper(data[mid + 1:], k)
        else:
            return 1 + self.helper(data[:mid], k) + self.helper(data[mid + 1:], k)
     

解题思路:双指针
代码

class Solution:
    def GetNumberOfK(self, data, k):
                # write code here
        if len(data)==1:
            return 1 if k in data else 0
        left=0
        right=len(data)-1
        while left<right:
            if data[left]!=k:
                left+=1
            if data[right]!=k:
                right-=1
            if data[left]==k and data[right]==k:
                return right-left+1 
        return 0
 

全排序

面试题027 字符串的排序

题目描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
解题思路:From 剑指Offer 全排列
代码

class Solution:
    def Permutation(self, ss):
        if len(ss) <= 1:
            return ss
        res = set()
        # 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
        for i in range(len(ss)):
            for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
                res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
        return sorted(res)         # sorted()能对可迭代对象进行排序,结果返回一个新的list

解题思路:Frome leetcode
回溯法
第一步,求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符进行交换
第二步,固定住第一个字符,求后面字符的全排列.这时候我们仍把后面的字符分成两部分: 后面字符的第一个字符以及这个字符后面的所有字符.
然后把第一个字符逐一和它后面的字符交换.
算法最后的结果可能会有重复的情况出现,我们使用python自带的set()函数来去重

代码

class Solution(object):
    def permutation(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        result = []
        if not s:
            return []
        s = list(s)
        temp = [] 
        self.stringSort(s, temp, result)
        return list(set(result))
    
    def stringSort(self, s, temp, result):
        if len(s) == 1:
            temp.append(s[0])
            result.append(''.join(temp))
            temp.pop()
            return 
        for i in range(0,len(s)):
            if i!= 0 and s[i] == s[0]:
                continue
            s[0],s[i] = s[i],s[0]
            temp.append(s[0])
            self.stringSort(s[1:], temp, result)
            temp.pop()
            s[i], s[0], = s[0], s[i]

动态规划

面试题030 连续数组的最大和

题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
解题思路:动态规划
代码

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        n = len(array)
        dp = [ i for i in array]
        for i in range(1,n):
            dp[i] = max(dp[i-1]+array[i],array[i])
         
        return max(dp)

面试题012 数值的整数次方

解题思路1 考虑所有情况,循环连乘
代码:

def power(base, exponent):
    if (base==0):
        return 0
    if (exponent == 0):
        return 1   
    res = 1
    for i in range(abs(exponent)): #i只是循环变量,不起作用
        res *= base
    return 1/res if exponent < 0 else res

解题思路2 快速幂快速幂详解
代码

def fast_power(self, base, exponent):
        if base == 0:
            return 0
        if exponent == 0:
            return 1
        e = abs(exponent)
        tmp = base
        res = 1
        while(e > 0):
            #如果最后一位为1,那么给res乘上这一位的结果
            if (e & 1 == 1):
                res =res * tmp
            e = e >> 1
            tmp = tmp * tmp
        return res if exponent > 0 else 1/res

面试题 顺时针打印矩阵

题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
解题思路:打印第一行 然后删除第一行 剩余部分逆时针转动90度。重复以上步骤,直到矩阵为空
代码

# -*- coding:utf-8 -*-

class Solution:
    def printMatrix(self, matrix):
        # write code here
        s=[]
        while matrix:
            s+=matrix[0]
            del matrix[0]
            matrix=zip(*matrix)[::-1]
        return s

猜你喜欢

转载自www.cnblogs.com/eugene0/p/12860481.html