剑指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)

面试题052 正则表达式匹配

题目描述:请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
解题思路:From 剑指offer
代码

class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # 如果s与pattern都为空,则True
        if len(s) == 0 and len(pattern) == 0:
            return True
        # 如果s不为空,而pattern为空,则False
        elif len(s) != 0 and len(pattern) == 0:
            return False
        # 如果s为空,而pattern不为空,则需要判断
        elif len(s) == 0 and len(pattern) != 0:
            # pattern中的第二个字符为*,则pattern后移两位继续比较
            if len(pattern) > 1 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
        # s与pattern都不为空的情况
        else:
            # pattern的第二个字符为*的情况
            if len(pattern) > 1 and pattern[1] == '*':
                # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空
                if s[0] != pattern[0] and pattern[0] != '.':
                    return self.match(s, pattern[2:])
                else:
                    # 如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况
                    # pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的
                    # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配
                    # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位
                    return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
            # pattern第二个字符不为*的情况
            else:
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    return False

解题思路:回溯
代码

class Solution:
    # s, pattern都是字符串
    def isMatch(self, s, p):
        if not p: return not s
        # 第一个字母是否匹配
        first_match = bool(s and p[0] in {s[0],'.'})
        # 如果 p 第二个字母是 *
        if len(p) >= 2 and p[1] == "*":
            return self.isMatch(s, p[2:]) or 
            first_match and self.isMatch(s[1:], p)
        else:
            return first_match and self.isMatch(s[1:], p[1:])

解题思路:递归
代码

class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if pattern =="":
            return s==""
        if len(pattern)>1 and pattern[1]=="*":
            return self.match(s, pattern[2:]) or (s and (s[0]==pattern[0] or pattern[0] == '.') and self.match(s[1:],pattern))
        else:
            return s and (s[0]==pattern[0] or pattern[0]=='.')and self.match(s[1:],pattern[1:])

排序

面试题035 数组中的逆序数

题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入 1,2,3,4,5,6,7,0
输出 7

解题思路:归并
代码

class Solution:
    def InversePairs(self, data):
        #发现可以用归并排序,归并拼接后用计算排序时元素的index变动了多少
        #两个有序序列,每个元素移动index数(严格来说不是移动,这里不知怎么表达)之和好像刚好等于逆序对的个数
        #我也不知为什么,找了半天发现了这个规律
        _,s=self.MergeSort(data)
        return s%1000000007
     
    def MergeSort(self,data):
        n=len(data)
        #递归基
        if n==1:return data, 0
        #分两半来排序
        part1,part2=data[:n//2],data[n//2:]
        sorted_part1,s1=self.MergeSort(part1)
        sorted_part2,s2=self.MergeSort(part2)
        #排序后拼接这两半,拼接后先计数,然后将两个有序序列合并
        s,sorted_temp=0,sorted_part1+sorted_part2
        #用p、q两个指针指向两段,计算q中每个元素离插入点的index差
        p,q,len1,len_all=0,sorted_temp.index(sorted_part2[0]),len(sorted_part1),len(sorted_temp)
        while p<len1 and q<len_all:
            #移动p使p成为插入排序的插入点,计算要移动多少个位置
            while p<len1:
                if sorted_temp[q]<sorted_temp[p]:
                    s+=len1-p
                    break
                p+=1
            q+=1
        #完成排序,并把排序后的内容回溯给上一级做准备
        l=[]
        p,q=0,sorted_temp.index(sorted_part2[0])
        while p<len1 and q<len_all:
            if sorted_temp[p]<sorted_temp[q]:
                l.append(sorted_temp[p])
                p+=1
            else:
                l.append(sorted_temp[q])
                q+=1
        if p==len1:l+=sorted_temp[q:]
        if q==len_all:l+=sorted_part1[p:]
        return l,s+s1+s2

代码

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        def mergeSort(l=0, r=len(nums)):#左闭右开区间
            if r - l > 1:
                mid = (l + r)//2
                mergeSort(l, mid)
                mergeSort(mid, r)
                i, j, tmp = l, mid, []
                while i < mid and j < r:
                    if nums[i] <= nums[j]:
                        tmp.append(nums[i])
                        i += 1
                    else:
                        tmp.append(nums[j])
                        j += 1
                        self.cnt += mid - i
                tmp.extend(nums[i:mid] if i<mid else nums[j:r])
                nums[l:r] = tmp

        self.cnt = 0
        mergeSort()
        return self.cnt

位运算

面试题011 二进制中1的个数

题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
解题思路:二进制表示中,末尾的1减去后,低位变为0,高位不变,按位与就可以去掉这个1
代码

# From leetcode
class Solution(object):
    def hammingWeight(self, n):
        """
        :type n: int
        :rtype: int
        """
        res = 0
        while n:
            res += 1
            n &= n - 1
        return res
# From 剑指offer 使用c_int()函数,不然负数不会变成0
from ctypes import *
class Solution:
    def NumberOf1(self, n):
        # write code here
        ret = 0
        while c_int(n).value:
            ret += 1
            n = n & n-1            
        return ret

面试题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

面试题040 数组中只出现一次的数字

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解题思路:HashMap
代码

class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        hashMap = {}
        for i in array:
            if str(i) in hashMap:
                hashMap[str(i)] += 1
            else:
                hashMap[str(i)] = 1
        res = []
        for k in hashMap.keys():
            if hashMap[k] == 1:
                res.append(int(k))
        return res
class Solution:
   
    def FindNumsAppearOnce(self, array):
        # write code here
        map = {}
        res = []
        for n in array:
            map[n] = map.get(n,0)+1
        for n in array:
            if map[n] == 1:
                res.append(n)
        return res

解题思路:位运算中异或性质,两个相同数字异或是0 一个数和0异或还是它本身
代码

class Solution:
    def FindNumsAppearOnce(self, array):
        if not array:
            return []
        # 对array中的数字进行异或运算
        tmp = 0
        for i in array:
            tmp ^= i
        # 获取tmp中最低位1的位置
        idx = 0
        while (tmp & 1) == 0:
            tmp >>= 1
            idx += 1
        a = b = 0
        for i in array:
            if self.isBit(i, idx):
                a ^= i
            else:
                b ^= i
        return [a, b]
 
    def isBit(self, num, idx):
        """
        判断num的二进制从低到高idx位是不是1
        :param num: 数字
        :param idx: 二进制从低到高位置
        :return: num的idx位是否为1
        """
        num = num >> idx
        return num & 1

其他算法

面试题002 替换空格

题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
解题思路:遍历空格并替换
代码

class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s = list(s)
        count = len(s)
        for i in range(0,count):
            if s[i]==' ':
                s[i] = '%20'
        return ''.join(s)

面试题013 调整数组顺序使奇数位于偶数前面

题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
解题思路:遍历,分两个数组分别统计奇数偶数,最后拼接
代码

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

面试题028 数组中出现次数超过一半的数字

题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解题思路:统计数组中每个元素出现的次数,返回次数大于数组长度一半的元素
代码

import collections
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        temp = collections.Counter(numbers)
        x = len(numbers)/2
        for k,v in temp.items():
            if v > x:
                return k
        return 0

面试题031 整数中1出现的次数

题目描述:求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解题思路:设定整数点(如1、10、100等等)作为位置点i(对应n的各位、十位、百位等等),分别对每个数位上有多少包含1的点进行分析。
根据设定的整数位置,对n进行分割,分为两部分,高位n/i,低位n%i
当i表示百位,且百位对应的数>=2,如n=31456,i=100,则a=314,b=56,此时百位为1的次数有a/10+1=32(最高两位0~31),每一次都包含100个连续的点,即共有(a/10+1)100个点的百位为1;
当i表示百位,且百位对应的数为1,如n=31156,i=100,则a=311,b=56,此时百位对应的就是1,则共有a/10(最高两位0-30)次是包含100个连续点,当最高两位为31(即a=311),本次只对应局部点00~56,共b+1次,所有点加起来共有(a/10
100)+(b+1),这些点百位对应为1;
当i表示百位,且百位对应的数为0,如n=31056,i=100,则a=310,b=56,此时百位为1的次数有a/10=31(最高两位0~30);
综合以上三种情况,当百位对应0或>=2时,有(a+8)/10次包含所有100个点,还有当百位为1(a%101),需要增加局部点b+1
之所以补8,是因为当百位为0,则a/10
(a+8)/10,当百位>=2,补8会产生进位位,效果等同于(a/10+1)

代码

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        i = 1
        while i <= n:
            a = n / i
            b = n % i
            count += (a+8) / 10 * i + (a % 10 == 1)*(b + 1)
            i *= 10
        return count

面试题032 把数组排成最小的数

题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
解题思路:将n1 n2转成字符串 s1 s2 ,拼接成s1s2 s2s1 取整比较大小,小的放前面
代码

class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        if not numbers:
            return ""
        lmb = lambda n1, n2:int(str(n1)+str(n2))-int(str(n2)+str(n1))
        array = sorted(numbers, cmp=lmb)
        return ''.join([str(i) for i in array])

面试题033 丑数

题目描述:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
示例
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
解题思路:From Leetcode 动态规划


代码

class Solution(object):
    def nthUglyNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp, a, b, c = [1] * n, 0, 0, 0
        for i in range(1, n):
            n2, n3, n5 = dp[a] * 2, dp[b] * 3, dp[c] * 5
            dp[i] = min(n2, n3, n5)
            if dp[i] == n2: a += 1
            if dp[i] == n3: b += 1
            if dp[i] == n5: c += 1
        return dp[-1]
# 剑指Offer
# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        if index < 1:
            return 0 
        res = [1]
        t2 = t3 = t5 = 0 
        nextIdx = 1
        while nextIdx < index:
            minNum = min(res[t2] * 2, res[t3] * 3, res[t5] * 5)
            res.append(minNum) 
            while res[t2] * 2 <= minNum:
                t2 += 1
            while res[t3] * 3 <= minNum:
                t3 += 1
            while res[t5] * 5 <= minNum:
                t5 += 1 
            nextIdx += 1 
        return res[nextIdx - 1]

面试题 顺时针打印矩阵

题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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

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

题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
解题思路:分治法是不断的缩小范围,从而找到符合条件的解
二分法的分析我们知道,数组可以分为前后两个递增数组,下面的分析也都利用递增的特性
当numbers[mid] > numbers[high]时,说明最小值在mid的右边,缩小范围low = mid + 1
当numbers[mid] == numbers[high]时,我们不知道最小值的范围,但是可以肯定的是去除numbers[high]是没有影响的,缩小范围high -= 1
当numbers[mid] < numbers[high]时,我们知道最小值的不是numbers[mid]]就是在mid的左边,缩小范围high = mid

代码

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return None
        low = 0
        high = len(rotateArray) - 1
        while low < high:
            mid = (low + high) >> 1
            if rotateArray[mid] > rotateArray[high]:
                low = mid + 1
            elif rotateArray[mid] == rotateArray[high]:
                high -= 1
            else:
                high = mid
        return rotateArray[low]

面试题 数据流中的中位数

题目描述:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例 :
输入:
["MedianFinder","addNum","addNum","findMedian","addNum","findMedian"]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
解题思路:首先对数组执行排序(使用 O(N log N)O(NlogN) 时间),然后返回中间元素即可(使用 O(1)O(1) 时间)。

代码

from heapq import *

class MedianFinder:
    def __init__(self):
        self.A = [] # 小顶堆,保存较大的一半
        self.B = [] # 大顶堆,保存较小的一半

    def addNum(self, num):
        if len(self.A) != len(self.B):
            heappush(self.A, num)
            heappush(self.B, -heappop(self.A))
        else:
            heappush(self.B, -num)
            heappush(self.A, -heappop(self.B))

    def findMedian(self):
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0

代码优化:

from heapq import *

class MedianFinder:
    def __init__(self):
        self.A = [] # 小顶堆,保存较大的一半
        self.B = [] # 大顶堆,保存较小的一半

    def addNum(self, num):
        if len(self.A) != len(self.B):
            heappush(self.B, -heappushpop(self.A, num))  # 先加到小顶堆,再把小堆顶元素加到大顶堆
        else:
            heappush(self.A, -heappushpop(self.B, -num)) # 先加到大顶堆,再把大堆顶元素加到小顶堆

    def findMedian(self):
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0

将中位数左边的数保存在大顶堆中,右边的数保存在小顶堆中。这样可以在 {mathcal{O}}(1)O(1) 时间内得到中位数。

注意:Python 中没有大顶堆,只能将值取负保存在小顶堆来模拟。为了方便理解,将堆用优先队列表示

面试题 字符串流中第一个不重复的字符

题目描述:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
解题思路:利用hash表记录字符串s中每个字符出现的次数,再遍历字符串,判断出现次数是否为1,如果是则返回所在位置;遍历完成都没有则说明没有只出现过一次的字符,返回-1

代码

class Solution:
    # 返回对应char
    def __init__(self):
        self.s=''
        self.dict1={}
    def FirstAppearingOnce(self):
        # write code here
        for i in self.s:
            if self.dict1[i]==1:
                return i
        return '#'
    def Insert(self, char):
        # write code here
        self.s=self.s+char
        if char in self.dict1:
            self.dict1[char]=self.dict1[char]+1
        else:
            self.dict1[char]=1
class Solution:
    def __init__(self):
        self.s = ''
        self.queue = []       #按顺序保存所有只出现一次的字符
        self.second = []      #按顺序保存所有出现过的字符
 
    def FirstAppearingOnce(self):
        if self.queue:
            return self.queue[0]
        return '#'
 
    def Insert(self, char):
        self.s += char
        if char in self.queue:
            self.queue.pop(self.queue.index(char))
        elif char not in self.second:
            self.queue.append(char)
            self.second.append(char)

面试题 表示数值的字符串

题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
解题思路:
代码

# 正则
class Solution:
    # s字符串
    def isNumeric(self, s):
        import re
        p=re.compile(r'^[+-]?d*(.d+)?([eE][+-]?d+)?$')
        return p.match(s)

From leetcode

class Solution(object):
    def isNumber(self, s):
        """
        :type s: str
        :rtype: bool
        """
        if '' == s[0]:
            return False
        else:
            s1 = s.rstrip().strip()
            if " " in s1:
                return False
            # 先对+ -号处理
            for i in ['+','-']:
                if i in s1:
                    if s1.rindex(i) == 0:
                        if 'e'==s1[1] :
                            return False
                        else: pass
                    else:
                        if s1.count(i)==2:
                            if s1.index(i)==0 and 'e' == s1[s1.rindex(i) -1] and '' != s1[s1.rindex(i)+1:]:pass
                            else: return False
                        elif s1.count(i)==1:
                            if 'e' == s1[s1.rindex(i) -1] and '' != s1[s1.rindex(i)+1:]: pass
                            else: return False
                        else:return False
            # 对 “.”处理
            if '.' in s1:
                if s1.count('.') == 1:
                    pass
                else:
                    return False
            # 对 “e”处理
            if 'e' in s1:
                if s1.count('e') == 1:
                    e_l = s1.split('e')
                    if len(e_l[1])>0:
                        if '.' in e_l[1]:
                            return False
                    else:
                        return False

                    if len(e_l[0])>0:
                        if '.'==e_l[0]:
                            return False
                    else:
                        return False
                else:
                    return False
            # 数字判断
            s2 = s1.replace('+','').replace('-','').replace('.','').replace('e','')
            if len(s2)>0:
                for i in s2:
                    if i in ['1','2','3','4','5','6','7','8','9','0']:
                        pass
                    else:return False
                return True
            else:
                return False
class Solution(object):
    def isNumber(self, s):
        try:
            s = float(s)
            return True
        except:
            return False
原文地址:https://www.cnblogs.com/eugene0/p/12860481.html