zoukankan      html  css  js  c++  java
  • 剑指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
    
  • 相关阅读:
    SharePoint:扩展DVWP 第11部分:在工作流中使用更多的表单字段
    Guava学习笔记:Google Guava 类库简介
    每天一个linux命令(59):rcp命令
    每天一个linux命令(60):scp命令
    【转载】程序员要勇于说不
    深入理解Java:内省(Introspector)
    Guava学习笔记:Optional优雅的使用null
    深入理解Java:注解(Annotation)基本概念
    深入理解Java:SimpleDateFormat安全的时间格式化
    每天一个linux命令(58):telnet命令
  • 原文地址:https://www.cnblogs.com/eugene0/p/12860481.html
Copyright © 2011-2022 走看看