Python-Leetcode-剑指offer(五月上做题整理)

(1)5-1-面试题39. 数组中出现次数超过一半的数字

我想到的解法:哈希表和排序,但是对比评论和题解发现自己的也不是最优的。【摩尔投票法】最优

方法一:哈希表  time O(N) space O(N) -> O(N/2)

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #哈希表 O(N)
        dic = {}
        if len(nums)%2 ==0:n = len(nums)//2
        else: n = len(nums)//2 +1
        for i in nums:
            dic[i] = dic.get(i,0) + 1
            #####  不用等到dic 建立完全在判断 O(N/2)
            #if dic[i] >= n:return i 
            #####
        for key in dic:
            if dic[key] >= n:
                return key

方法二:排序,找中位数   time  O(NlogN) space O (1)

想到了排序,但是没有考虑到出现超过一半的数字就是众数”,也没有想到中间的那个数就是众数,排序结束之后,用双指针来找到了众数。-,-蠢哭。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:        
        #排序 O(NlogN)        
        nums.sort()
        if len(nums)%2 ==0:n = len(nums)//2
        else: n = len(nums)//2 +1
        return nums[n]

方法三:摩尔投票法(最优解法) time O(N)  space O(1)  链接是一个好理解的解释。

摩尔投票法本质思想就是利用 众数记为 +1 ,把其他数记为 -1 ,将它们全部加起来,显然和大于 0抵消相减。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:                
        votes = 0  ## 来自Leetcode @Krahets 
        for num in nums:
            if votes == 0: x = num ## 重新开始拟定一个众数
            if num == x:  ## 相同+1 不同-1 
                votes += 1 
            else: votes -= 1 
        return x #最后没有被消掉的肯定是众数

(2)5-2-面试题12. 矩阵中的路径

考点:DFS+剪枝

很明确的知道这个题就是用DFS的方法来做,遇到不满足的点的时,返回到上一节点处,继续找下一个可行解,直到所有的点都不能满足要求的时候停止。但是寻找过程中,不会写如何返回上一个节点(剪枝操作-回溯),因此卡住了。

DFS的框架就是 递归框架。从一个状态下一个可行状态转换。

框架:

def DFS(parameter1,parameter2): #
    ## visited = True
    if 条件 满足:
        DFS(parameter1,parameter2) #在往下继续遍历
    ## 如果不满足 返回相应的结果
    ## 状态恢复
    ## visited = False ## 回溯
    return resluts
        

因为这个题只能走一次,所以遍历每个点的时候,都要有一个  visited 来判断。

如果 满足条件【边界范围 未被访问 board等于word】 -> 进入下一个 DFS()

如果 不满足条件 :该状态 重置 , return Fasle

如果 已经到了最后一个word点了,return True。

这个题还有一点不同的是,他是一步返回一个判断结果和 遍历到最后 返回一个结果还不太一样。【有点懵】

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m,n = len(board),len(board[0])
        visited = [[False for i in range(n)] for j in range(m)]

        ## DFS
        def DFS(i,j,k):
            visited[i][j] = True
            if k == len(word): return True ##结束探测
            k += 1
            ## 上下左右,如果满足就继续往下走了
            if i+1<m and not visited[i+1][j] and board[i+1][j]==word[k-1]:
                if DFS(i+1,j,k):
                    return True
            if j+1<n and not visited[i][j+1] and board[i][j+1]==word[k-1] :
                if DFS(i,j+1,k):
                    return True
            if i-1>=0 and board[i-1][j]==word[k-1] and not visited[i-1][j]:
                if DFS(i-1,j,k):
                    return True
            if j-1>=0 and board[i][j-1]==word[k-1] and not visited[i][j-1]:
                if DFS(i,j-1,k):
                    return True
            
            visited[i][j] = False ##如果没有往下走,那么回溯,把访问信息清空
            return False

        for i in range(m):
            for j in range(n):
                if board[i][j] == word[0]:
                    if DFS(i,j,1) :return True
        return False

(3)5-3-面试题45. 把数组排成最小的数

考点:“排序”变种  ->将数字(单个字符串)按照一定的规则重新排列,组成长字符串。

刚开始想的是,“30” “3”,那么3不是放在 “30”的前面,就是放在“30”的后面,然后可以当成是DP,来做。

但是 由于存在 1,4,2 -> '124' 发现并不能用DP来做。[DP的状态转换条件个数是一定的]

然后就不会做了。 想的是 当  ans = [ '30','3'] 时,'34' 从0,1,2三个位置分别插入,然后在比较每次插入时,数字组合的大小,但是这样太麻烦了,而且存在着很多int() 和 str() 的来回转换。

规则就是从 产生的字符串最小来的,假设 x,y是两个字符串'30','3'。

如果 x+y > y+x : x>y   反之 x+y<y+x: x<y

-> '30'+'3' < '3'+'30' :'30' <'3' ,排序的时候,'3'应该放在'30'后面,按照从小到大的规则。

规则出来了,之后就是基本排序的方法【快排】的模板套进去了。

class Solution: 
    def minNumber(self, nums: List[int]) -> str:
        def judge(x,y): #
            if int(x+y) > int(y+x):
                 return True# x>y
            else: 
                return False # x<y

        num = [ str(nums[i]) for i in range(0,len(nums))]

        for i in range(0,len(nums)): # O(N^2) 冒泡
            min_ = num[i]
            for j in range(i+1,len(nums)):
                if not judge(num[j],min_) : #按照规则去比较大小
                        temp = min_
                        min_ = num[j]
                        num[j] = temp
            num[i] = min_
        return ''.join(num)

        # O(NlogN)
        i,j = 0,len(nums)-1
        def get(num,low,high):
            temp = num[low]
            while(low<high):
                while(low<high and judge(num[high],temp)): high-=1
                num[low] = num[high]
                while(low<high and not judge(num[low],temp)):low+=1
                num[high] = num[low]
            num[low] =temp
            return low
        
        def quick_sort(num,low,high):# O(NlogN)
            if low<high:
                index = get(num,low,high)
                quick_sort(num,low,index-1)
                quick_sort(num,index+1,high)
        
        quick_sort(num,i,j)
        return ''.join(num)



 下面的这个也是快排,但是来自此处

  比我快的原因:

(1)python中可以直接用 “<” 比大小,不用再去写judge函数去判断。[c中不能直接用关系运算符比字符串大小]

(2)get 和 quick_sort() 是可以合并的,这样节省了temp的开销,且没有来回调用get()的问题。

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def fast_sort(l , r):
            if l >= r: return
            i, j = l, r
            while i < j:
                while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
                while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[l] = strs[l], strs[i]
            fast_sort(l, i - 1)
            fast_sort(i + 1, r)
        
        strs = [str(num) for num in nums]
        fast_sort(0, len(strs) - 1)
        return ''.join(strs)

利用排序的另外一种方法(python)利用sort() 函数中的cmp,自定义规则,然后排序。曾经写过博客,然而并没有实际用过。这里也写一下。 代码也是摘自上面的题解连接。其中sort() 时间复杂度 O(NlogN)

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def sort_rule(x, y): # 比较x,y大小
            a, b = x + y, y + x
            if a > b: return 1 # x+y >y+x -----> x>y
            elif a < b: return -1  ## 小于
            else: return 0  ##等于
        
        strs = [str(num) for num in nums]
        strs.sort(key = functools.cmp_to_key(sort_rule)) ##比较规则,按照定义的比较规则去排序
        return ''.join(strs)

(4)5-4-面试题09. 用两个栈实现队列

考点:队列先进先出,栈先进后出(队列和栈的相关知识) python list.pop() #默认删除最后一个元素

我的思路:一个栈用来存储元素S1,当需要删除时,判断S1是否空,不空那么把栈顶元素赋值给ans(return),将剩下的元素给S2。S1置空,再将S2元素返回进去。 23.64%(时间)

大佬们的思路:一个栈只存储S1,一个只用来删除S2。若S2不空,直接删除最后一个元素。若空,判断S1是否为空,若空 return -1。否则将S1 [1,2,3] 从栈顶依次删除,放入S2 [3,2,1]。(这样保证了S2的栈顶是S1的栈底,也就是队列的先进先出)。删除时,删除的是1。S1再放的时候,还是满足的,只不过这样不能保证某个状态下,根据某一个栈就能把所有元素取出。[用一个栈保证栈底是栈顶]    74.83%

为什么我的慢?因为我 有一个来回折腾S1和S2的过程。S1置空虽然是直接覆盖的,但是按照正常的来说,是应该逐个删除的。

class CQueue:

    def __init__(self):
        # 一个栈用来存储 # 一个栈是删除工具
        self.S1 = []
        self.S2 = [] 

    def appendTail(self, value: int) -> None:
        self.S1.append(value)

    def deleteHead(self) -> int:
        # mine
        if len(self.S1) == 0 :return -1
        ans = self.S1[0]
        self.S2 = []
        for i in self.S1[1:]: #从栈顶从新开始
            self.S2.append(i)
        self.S1 = self.S2 
        return ans

        ## others
        if self.S2 : return self.S2.pop() #删除S2栈顶
        elif not self.S1: return -1
        else:
            while self.S1: # 将S1倒叙存入S2,
                self.S2.append(self.S1.pop())
            return self.S2.pop()

(5)5-5-面试题59 - I. 滑动窗口的最大值

考点:双端队列(单调队列) 可以和单调栈做个对比。->面试题63. 股票的最大利润

思路:时间主要浪费在求解滑动窗口内的最大值O(k)。如何才能使时间变成O(1)呢?考虑用空间换时间。辅助的操作就是队列了。

暴力法:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        ans = []
        i,n = 0,len(nums)
        while(i<n and i+k < n+1): ## O(nk)
            ans.append(max(nums[i:i+k])) #O(k)
            i += 1
        return ans

双端队列:时间 O(N) 空间 O(k) 双端队列大小和窗口大小相同。

保证队列中是递减的,那么每一轮滑动过程中,Q[0]就是最大值。当进行下一轮滑动时,首先让最左端的最大的这种情况排除,然后在每次放入一个,使窗口向右滑动。

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if not nums or k == 0: return []
        deque = collections.deque()
        for i in range(k): # 未形成窗口
            while deque and deque[-1] < nums[i]: deque.pop()
            deque.append(nums[i])
        res = [deque[0]]
        for i in range(k, len(nums)): # 形成窗口后
            if deque[0] == nums[i - k]: deque.popleft() ##不理解的一句话 
            while deque and deque[-1] < nums[i]: deque.pop()
            deque.append(nums[i])
            res.append(deque[0])
        return res

对于 if deque[0] == nums[i - k]: deque.popleft() 因为每一次都往后挪一个,所以上一轮的第一个元素就应该挪出去,如果Q中最大就是上一轮的第一个元素。那么如果存在于这一轮会对结果产生影响。如果Q[0]不是上一轮中的第一个元素,那么肯定的是上一轮中的第一个元素已经挪出去了。因此判断的是这一轮的Q[0]和上一轮的第一个元素的比较。【比较绕的一个点】

因为 nums[i - k] 是这轮要去挪出去的,所以要和这个元素比较。

(6)5-6-面试题64. 求1+2+…+n

考点 :位运算和逻辑运算的使用

方法一:利用and的逻辑运算规则实现。 终止递归条件是 逻辑与

class Solution:
    def sumNums(self, n: int) -> int:
        # if n==0:return 0
        def get_res(n):
            return n and n + get_res(n - 1)  # 递归形式
            # 变量都不为0时(n>0),返回后面的那个
            # 当变量为0时候(n=0)返回0
        return get_res(n)

方法二:位运算。

按照求和公式,可以很快的想到:\frac{n^2 +n}{2},除以2可以利用 >> 实现。然后 n^2 +n不知道如何做了。

利用快速乘法或者快速幂类的思想,利用移位运算符解决问题。知识盲点已经补充,见链接

class Solution:
    def sumNums(self, n: int) -> int:

        temp = n+1
        ans = 0
        
        #循环14遍 
        (n & 1) && (ans += temp) 
        n >>= 1
        temp <<= 1

        return ans >> 1

(7)5-7-面试题15. 二进制中1的个数

考点:位运算 & 和  "<< "   ">>"

class Solution:
    def hammingWeight(self, n: int) -> int: #log(N)
        res = 0
        while n:
            res += n & 1
            n >>= 1
        return res

第二种思路来自此处

利用  n&(n−1) time is O(N) space is O(1)

class Solution:
    def hammingWeight(self, n: int) -> int:
        res = 0
        while n:
            res += 1
            n &= n - 1
        return res

(8)5-8-面试题66. 构建乘积数组

考点:用空间换时间,略微带一些找规律。这个题 O(N^2)通过不了。然后降低时间复杂度,有两条路可走:(1)用空间换时间,创建[栈/队列/数组]等来解决。(2)双指针、排序等方法来优化时间复杂度。

这个题,就属于第一种方法。

首先建立一个S1 = [A0, A0*A1,A0*A1*A2,....,A0*A1*...A(n-2)] #不包括 An-1情况

                    S2 = [A(n-1), A(n-1)*A(n-2),....,A(n-1)*A(n-2)*...A(1)] # 不包括A0情况

                    B =  [S2[n-2],S1[0]*S2[n-3],....,S1[n-1]*S2[0],S1[n-2]] 

class Solution:
    def constructArr(self, a: List[int]) -> List[int]:   ##自己的垃圾代码
        B = [1 for i in range(len(a))]
        n = len(a)
        S1 = [1 for i in range(n-1)]
        S2 = [1 for i in range(n-1)]
        for i in range(0,n-1):
            if i==0:
                S1[i] = a[i]
            else:S1[i] = a[i]*S1[i-1]
        
        for i in range(0,n-1):
            if i==0: S2[i] = a[n-i-1]
            else:S2[i] = S2[i-1]*a[n-i-1]
        for i in range(0,n):
            if i == 0:B[i] = S2[n-i-2]
            elif i == n-1:B[i] = S1[i-1]
            else:
                B[i] = S1[i-1] * S2[n-i-2] 
        return B

看了评论和题解,发现了几个比较好的思想。因为如果暴力里面,肯定是下面这样的。

for i in range(len(a)):
    for j in range(len(a)):
        if j!=i:
            b[i] *= a[j]

降低复杂度,直接从j = i的地方(对角线)分开不就好了? 画一下矩阵。

先把j=i前面的相乘赋给B[j],再把j=i后面的相乘 乘到 B[j]中。 想法来自:Leetcode此题评论 @Leslie zjz

        B = [1 for i in range(len(a))]
        n = len(a)
        i,temp = 0,1
        while(i<n):
            B[i] = temp
            temp *= a[i] 
            i += 1
        i,temp=n-1,1
        while(i>=0):
            B[i] *= temp
            temp *= a[i]
            i -= 1
        return B

(9)5-9-面试题48. 最长不含重复字符的子字符串

暴力解法:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:## O(N^2) O(N)
        if len(s) <= 1: return len(s)
        stack,max_ = [],0
        for i in range(0,len(s)): 
            stack = []
            stack.append(s[i])
            for j in range(i+1,len(s)):
                if s[j] not in stack:
                    stack.append(s[j])
                else:
                    break
            max_ = max(len(stack),max_)
        return max_ 

 

(10)5-10-面试题10- I. 斐波那契数列

考点:求余问题。递归、DP解法。 和青蛙跳台阶一样。

这个题在最初DP问题中就有了,直接写就行了。

class Solution:
    def fib(self, n: int) -> int:

        a,b = 0,1 # O(N)
        if n == 0:return 0
        if n == 1:return 1
        for i in range(2,n+1):
            a,b = b%1000000007,(a+b)%1000000007
        return b 

递归会超时。 可以利用 functools.lru_cache来解决。

from functools import lru_cache
class Solution:
    def fib(self, n: int) -> int:
        @lru_cache(None)
        def t(n): # 超时间 O(n)
            if n==0:return 0
            if n==1:return 1
            return (t(n-1)+t(n-2))%1000000007
        return t(n)

还有一个利用数学归纳法证明之后,再做的题解,链接

(11)5-11-面试题17. 打印从1到最大的n位数

看了一下评论这个题没有什么意义,剑指里面考的是大数问题。而且python没有特别强调的溢出问题,所以不用python说了,第二遍看c刷剑指再补充。

class Solution:
    def printNumbers(self, n: int) -> List[int]:

        l = []
        for i in range(1,10**n): ##10**n
            l.append(i)
        return l

(12)5-12-面试题56 - I. 数组中数字出现的次数

考点: 异或[位运算] 。真真想不到,即使以前做类似的了。

O(2N) O(N) -> 哈希表 

知识点:(1)a^b  按照相同为0不同为1,求解每一位二进制

               (2)a^a = 0  ;a^0 = a; a ^ b ^ c = a ^ c ^ b [交换律]

                (3)  (a^b)^c = a^(b^c)   结合律

                (4)A ^ B ^ B = A ^ 0 = A ---> A ^ B = C 则 C ^ B = A (自反性)

 四道关联题的整理与解析来自此处

136 ->除了某个数字之外,所有数据都出现了2次。找到这个数字。

136举例: 0^a^b^c^c^a = 0^a^a^c^c^b = a^a^c^c^b = b【主要利用交换律】 O(N) O(1)

single_number = 0
for i in nums:
    single_number ^= num # 0
return single_number   

面试题56 - II. 数组中数字出现的次数 II-> 除了一个数字出现一次,其他都出现了三次。找到出现一次的数字。

Map -> O(N) O(N)

class Solution:
    def singleNumber(self, nums: List[int]) -> int:        
        ## 哈希
        dic ={} #O(n) O(n)
        for i in nums:
            dic[i] = dic.get(i,0)+1
        for key,value in dic.items():
            if value == 1:
                return key

数学方法

return (sum(set(nums))*3-sum(nums))//2 # O(N)?

从二进制出发,找规律

[4,3,4,4]      1      0     0   4

                   0      1     1   3 

                   1      0     0   

                   1      0     0   4

                    4      1     1  +

可以看出,出现三次的二进制数每位相加后都是3的倍数,所以 把每一位相加,然后 是3n+1的。除以3之后,就是答案。

        ans = 0
        i = 0 ## num 最大不超过32位
        while(i<32):  ## 常数次time is 32
            count = 0
            index = 1<<i  # 来衡量从右到左的每一位
            for j in nums: ## time is O(N) 
                if j & index != 0 : # 该位 存在1
                    count += 1
            if count%3 == 1 :# 判断该位置是否是单独数字产生
                ans += index
                # ans |= index
            i += 1
        return ans  ## O(32n) ->O(n)

 数字电路和DFA的方法。题解点击此处。 [偷懒,不看了]

645. 错误的集合 数组里面有唯一重复的一个数字还有一个缺失的数字,重复数字里面有一个本应该是缺失的数字,找出这个两个数字。

用 异或 来找出缺失的数字。

由于限定了数组从1~n。那么将 1~n做异或。再将结果与给定数组做异或。即可得到缺失的数组的异或。

然后再利用异或结果,把这 例子样本 和 标准样本 两个数字分开。

然后分开之后,可以发现。缺失数组中除了缺失的都是成对的。而多了的那个中,除了多了的,也都是成对的。所以在分别异或。就分开了 缺失和重复。题解来自此处

class Solution:
    def findErrorNums(self, nums: List[int]) -> List[int]:
       
        ans = 0
        for number in nums:
            ans = number ^ ans
        for i in range(1,len(nums)+1):
            ans ^= i
        h = 1
        while(ans & h ==0): h <<= 1 #区分界限
        # h = ans&(-ans)

        a,b = 0,0
        for number in nums: 
            if number &h ==0:
                a ^= number
            else:
                b ^= number
        for i in range(1,len(nums)+1):
            if i&h ==0: a^= i
            else:b^=i

        if b in nums: return [b,a]
        else: return [a,b]

 

本道题。题解来自此处。如果可以将两个不同的数字分组,那么两组不同的分别异或就可以得到最终答案。

以一个规则分组:可以利用奇偶性将相同的数组分组。不管怎么样,相同的一定会分到同一组。

如何去分组 里面两个不同的,是关键!因为将所有的数字进行异或,肯定存在结果中某一位为1。那么就以这个去分组。

打个简单的比方,就像区分两幅画,那就是以画中的某一个不同点去区分。因为 a^b 不同,所以异或有一位为1,那么 把这位数字找见[找见最低位为1的],再分别与a b异或,那么肯定得到不同的结果。

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:

        ans = 0
        for number in nums:
            ans ^= number # 为了找不同的那位
        h = 1 ## h 01 10 100 1000 这样的形式  
        while( ans & h == 0): 
            #  print(ans & 1)  ans >>= 1 ->把每一位最低位值取出,不太一样注意区分
            h <<= 1 # 找 最低位为1 的  
        # 用h来做划分
        a,b = 0,0  
        for number in nums:
            if number & h == 0: 
        # 这个规则对于划分相同的没什么影响,不管怎么样相同的一定会在一起
                a ^= number
            else:
                b ^= number
        return [a,b]

总结一下:感觉这类题,出现某某数字中除了a、b等只出现了一次。可以考虑位运算(异或 与)。如果是出现了a、b两种数字,找出这两个数字,那么先想的一定是如何把这两个数字分开。如果是只出现了一次,那么可以直接使用异或(找二进制数)的规律了。 像数字 2 4 6 等中只出现了一次,那么直接异或就行了。如果是 3,5,7等中只出现了一次。那么就是数组中数字出现的次数 II中的这种思路。

(13)5-13-面试题44. 数字序列中某一位的数字

考点:机智的找规律

(14)5-14-面试题16. 数值的整数次方

考点:快速幂    我自己已经写过专门的博客,不在总结了。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        '''temp = 1
        if n <0: b=-n
        else: b=n
        
        while(b):
            if b & 1:
                temp *= x
            x *= x
            b >>= 1
        if n>=0:return temp
        else:return 1/temp '''

        temp = 1 
        if n <0:x,n=1/x,-n ## 这里很巧妙 两种的时间复杂度差不多
        while(n):
            if n& 1:
                temp *= x
            x *= x
            n >>= 1
        return temp

(15)5-15-面试题45. 把数组排成最小的数

考点:DP算法 因为刷过了小青蛙跳台阶,所以这个题就很容易的想到是DP的方法。

只不过有两个限制条件:

(1) 当前位置和前一个位置组成的数字>25,这种情况下 f[n] = f[n-1]

(2)当前位置和前一个位置组成的数字=当前位置数字,这种情况,f[n] =f[n-1]

(3)否则 当前位置的方案数 f[n] = f[n-1]+f[n-2]  n>=2

f[1] =1 f[0]=1 没有num也是一种情况。

所以就有了下面的代码:

class Solution:
    def translateNum(self, num: int) -> int:
        # 转成 list  O(N) O(N)
        if num == 0: return 1
        l = []
        while(num):
            l.append(num%10)
            num //= 10
        l = l[::-1] 
        
        f = [0 for i in range(len(l)+1)]
        f[0] = 1
        f[1] = 1
        for i in range(2,len(l)+1):
            if l[i-1]+l[i-2]*10 >25:
                f[i] = f[i-1]
            elif l[i-1]+l[i-2]*10 == l[i-1]:
                f[i] = f[i-1]
            else:
                f[i] = f[i-1]+f[i-2]
        return f[len(l)]

上面代码 time is O(2N) space is O(2N)

所以,可以将f搞没。然后 if l[i-1]+l[i-2]*10 >25 和 l[i-1]+l[i-2]*10 == l[i-1] 是可以合并的,简化if判断。

class Solution:
    def translateNum(self, num: int) -> int:
        # 转成 list  O(N) O(N)
        if num == 0: return 1
        l = []
        while(num):
            l.append(num%10)
            num //= 10
        l = l[::-1]   ## 可以简化成 s = str(num)       
        a,b = 1,1
        for i in range(2,len(l)+1):
            if l[i-1]+l[i-2]*10 >25 or l[i-2] == 0: 
                a = b
            else:  ##   if  '10' <= s[i-2:i] <'25'
                a,b=b,a+b
        return b

代码: time is O(2N) space is O(N)

看了一眼解题发现大神的思路是从右往左来查看,效果是一样的。然后呢再利用由于list时的求从右往左的每一位,来简化运算,使得space is O(1)。思路来源于此处

下面代码  time is O(N) space is O(N) 。 

class Solution:
    def translateNum(self, num: int) -> int:
        s = str(num)
        a = b = 1
        for i in range(len(s) - 2, -1, -1):
            if if "10" <= s[i:i + 2] <= "25":
                a,b= b,a+b
            else:
                a = b
        return b

再简化:time is O(N) space is O(1)

class Solution:
    def translateNum(self, num: int) -> int:
        a = b = 1
        y = num % 10
        while num != 0:
            num //= 10
            x = num % 10
            tmp = 10 * x + y ##每次求解两位
            c = a + b if 10 <= tmp <= 25 else a ##如果tmp 满足条件就是两种方案 否则为1
            a, b = c, a  # 做一次更新,a,b
            y = x #把此次的个位数留下来,坐下一次循环使用
        return a

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Foneone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值