[Python筆記] 劍指offer刷題記錄——進度25/75

劍指offer刷題記錄

LeetCode上的劍指offer題
刷題ing…

3.數組中重複的數字

#遇見了得先問面試官時間和空間複雜度的要求
#1.排序+一個下一個
#時間O(nlogn) 空間O(1)
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        nums.sort()
        for i in range(len(nums)-1):
            if nums[i]==nums[i+1]:
                return nums[i]
#2.hash
#時間O(n),空間O(n)
#Python中的成員資格(membership)檢查運算“in”,在列表(list)中遍歷成員,時間複雜度爲O(N); 在字典(dict)中, 時間複雜度爲O(N)
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        memo = dict()
        for num in nums:
            if not memo.__contains__(num):
                memo[num]=1
            else:
                return num
#3.原地哈希
#時間O(n),空間O(1)
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        n = len(nums)
        #把原列表當哈希再用
        for i in range(n):
            while i!= nums[i]:
                if nums[i] == nums[nums[i]]:
                    return nums[i]
                temp = nums[i]
                nums[i],nums[temp]= nums[temp],nums[i]

4.二維數組中的查找

#1.視作BST_遞歸
#從右上角開始比較,比它大就往下數一行,比它小就往左數一列
class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
        self.target = target
        self.res = False
        self.helper(0,len(matrix[0])-1,matrix)
        return self.res

    def helper(self,i,j,matrix):
        if i<len(matrix) and j>=0:
            if matrix[i][j]==self.target:
                self.res = True
            if matrix[i][j]>self.target:
                self.helper(i,j-1,matrix)
            else:
                self.helper(i+1,j,matrix)
#2.視作BST_迭代
class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
        n = len(matrix)
        m = len(matrix[0])
        i = 0
        j = m-1
        while i<len(matrix) and j>=0:
            if matrix[i][j]==target:
                return True
            elif matrix[i][j]>target:
                j-=1
            else:
                i+=1
        return False
#3.暴力_內循環二分查找剪枝
class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        #暴力,內循環用二分查找
        if not matrix:
            return False
        n = len(matrix)
        m = len(matrix[0])
        def helper(line,i,j,target):
            if i>j:
                return False
            mid = (i+j)//2
            if line[mid]==target:
                return True
            elif line[mid]>target:
                return helper(line,i,mid-1,target)
            else:
                return helper(line,mid+1,j,target)

        for i in range(n):
            if helper(matrix[i],0,m-1,target):
                return True
        return False
        

5.替換空格

#1.一般py字符串操作
class Solution:
    def replaceSpace(self, s: str) -> str:
        return s.replace(' ','%20')
#2.一般遍歷,外部空間使用
class Solution:
    def replaceSpace(self, s: str) -> str:
        ans = ''
        for l in s:
            if l==' ':
                ans+='%20'
            else:
                ans+=l
        return ans

6.從尾到頭打印鏈表

#1.常規壓棧
class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        #因爲數組返回,可以直接壓棧
        p = head
        stack = []
        while p:
            stack.append(p.val)
            p = p.next
        return stack[::-1]
#2.遞歸棧
class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        if not head:
           return []
        else:
            return self.reversePrint(head.next) + [head.val]
#3.無棧,兩次遍歷
class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        p = head
        cnt=0
        while p:
            cnt+=1
            p = p.next
        p = head
        ans = [0]*cnt
        while cnt>0:
            ans[cnt-1]=p.val
            cnt -= 1
            p = p.next
        return ans

7.重建二叉樹

#1.遞歸
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        def helper(preleft,preright,inleft,inright,preorder,inorder):
            if preleft>preright:
                return
            root = TreeNode(preorder[preleft])
            p = inleft
            while inorder[p]!=root.val:
                p+=1
            left = p-inleft
            root.left = helper(preleft+1,preleft+left,inleft,inleft+left-1,preorder,inorder)
            root.right = helper(preleft+left+1,preright,inleft+left+1,inright,preorder,inorder)
            return root
        return helper(0,len(preorder)-1,0,len(inorder)-1,preorder,inorder)


#2.迭代
'''
看第i個元素位於當前root的left還是right就看中序有無遍歷到root,未遍歷到就是在root左側,左子樹,反之右子樹
使用棧保存遍歷過的節點。初始時令中序遍歷的指針指向第一個元素,遍歷前序遍歷的數組,如果前序遍歷的元素不等於中序遍歷的指針指向的元素,則前序遍歷的元素爲上一個節點的左子節點。如果前序遍歷的元素等於中序遍歷的指針指向的元素,則正向遍歷中序遍歷的元素同時反向遍歷前序遍歷的元素,找到最後一次相等的元素,將前序遍歷的下一個節點作爲最後一次相等的元素的右子節點。其中,反向遍歷前序遍歷的元素可通過棧的彈出元素實現。
'''
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
        root = TreeNode(preorder[0])
        length = len(preorder)
        stack = []
        stack.append(root)#節點入棧
        index = 0
        for i in range(1, length):
            preorderval = preorder[i]
            node = stack[-1]
            if node.val != inorder[index]: # 每次比較棧頂元素和inorder[index]
                node.left = TreeNode(preorderval)
                stack.append(node.left)
            else:
                while stack and stack[-1].val == inorder[index]:# 棧頂元素等於inorder[index],彈出;並且index += 1
                    node = stack[-1]
                    stack.pop()
                    index += 1
                node.right = TreeNode(preorderval)
                stack.append(node.right)
        return root

9.用兩個棧實現隊列

#1.腦子一熱只寫了一個棧
class CQueue:

    def __init__(self):
        self.deque = []

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

    def deleteHead(self) -> int:
        if len(self.deque)==0:
            return -1
        else:
            ans = self.deque[0]
            self.deque = self.deque[1:]
            return ans
#2.雙棧
'''
其中 stack1 用於存儲元素,stack2 用於輔助操作
若stack1非空而stack2空,則將1清空入棧2,2用於輔助pop
'''
class CQueue:

    def __init__(self):
        self.stack1 = []
        self.stack2 = []

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

    def deleteHead(self) -> int:
        if self.stack2:#平時就從棧2pop反序的,就是FIFO了
            return self.stack2.pop()
        elif not self.stack1:#兩個棧都空了,沒得吐了
            return -1
        else:#棧2空了,棧1數據傾倒進去
            while self.stack1:#棧尾變棧頂,反向堆到stack2裏邊
                self.stack2.append(self.stack1.pop())
            return self.stack2.pop()

10. 斐波那契數列

#1.暴力
class Solution:
    def fib(self, n: int) -> int:
        a0 = 0
        a1 = 1
        if n == 0:
            return 0
        if n==1:
            return 1
        ans = 0
        for i in range(n-1):
            ans = a0+a1
            a0 = a1
            a1 = ans
        return ans % 1000000007
#2.暴力記憶化遞歸
'''
在遞歸法的基礎上,新建一個長度爲 nn 的數組,用於在遞歸時存儲 f(0)f(0) 至 f(n)f(n) 的數字值,重複遇到某數字則直接從數組取用,避免了重複的遞歸計算。

'''
class Solution:
    @lru_cache(None)
    def fib(self, n: int) -> int:
        if n <2:
            return n
        return (self.fib(n-1)+self.fib(n-2))% 1000000007

11-2.青蛙跳臺階問題

#1.dp
class Solution:
    def numWays(self, n: int) -> int:
        #dpdp????
        if n<2:
            return 1
        dp = [0]*(n+1)
        dp[0]=1
        dp[1]=1
        for i in range(2,n+1):
            dp[i] = dp[i-1]+dp[i-2]
        return dp[-1]%1000000007
#2.dp空間優化
class Solution:
    def numWays(self, n: int) -> int:
        #dpdp空間優化
        if n<2:
            return 1
        pre0=1
        pre1=1
        for i in range(2,n+1):
            ans = pre0+pre1
            pre0 = pre1
            pre1 = ans
        return ans%1000000007

11.旋轉數組的最小數字

#1.一次遍歷找轉折點
class Solution:
    def minArray(self, numbers: List[int]) -> int:
        for i in range(len(numbers)-1):
            if numbers[i+1]<numbers[i]:
                return numbers[i+1]
        else:
            return numbers[0]
#2.二分_要注意邊界條件
class Solution:
    def minArray(self, numbers: List[int]) -> int:
        l = 0
        r = len(numbers)-1
        while l<r:
            mid = (r-l)//2+l
            if numbers[mid]<numbers[r] and numbers[mid]<=numbers[l]:
                #右半邊有序,轉折點確定在左邊
                r=mid
            elif numbers[mid]>=numbers[l] and numbers[mid]>numbers[r]:
                #左半有序,確定轉折點在右,mid肯定不是
                l=mid+1
            else:#完全有序數列
                r-=1
        return numbers[l]

12.矩陣中的路徑

#1.邊界條件十分痛苦DFS
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        #dfs
        def dfs(board,i,j,cnt,word):
            m = len(board)
            n = len(board[0])
            if cnt==len(word):
                return True
            if i<0 or i>=m or j<0 or j>=n or board[i][j]!=word[cnt]:
                return False
            board[i][j]='*'
            for x,y in [(0,1),(0,-1),(1,0),(-1,0)]:
                idx1 = i+x
                idx2 = j+y
                #print(board[idx1][idx2],word[cnt])
                if dfs(board,idx1,idx2,cnt+1,word):
                    return True
            #這個進入點沒能找到,返回來的時候cnt可以作爲標識
            board[i][j] = word[cnt]
            return False
        m = len(board)
        n = len(board[0])
        if m<1 and n<1 and not word:
            return False
        for i in range(m):
            for j in range(n):
                if dfs(board,i,j,0,word):
                    return True
        return False

13.機器人的運動範圍

#1.dfs
class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        self.visited = [[False]*n for _ in range(m)]
        return self.dfs(0,0,m,n,k)
    def dfs(self,i,j,m,n,k):
        if (i<0 or i>=m or j<0 or j>=n or (i//10+i%10+j//10+j%10)>k or self.visited[i][j]):
            return 0
        self.visited[i][j] = True
        return self.dfs(i+1,j,m,n,k)+self.dfs(i-1,j,m,n,k)+self.dfs(i,j+1,m,n,k)+self.dfs(i,j-1,m,n,k)+1

14.剪繩子

#1.dpdp
class Solution:
    def cuttingRope(self, n: int) -> int:
        #dpdp
        dp = [0]*(n+1)
        dp[1]=1
        for i in range(2,n+1):
            for j in range(1,i):
                #j是減下來的長度,dp記錄當前長度最大切割乘積
                #max(dp[j],j)決定用切下來的那段再切切還是就不切了比較長
                #和dpi比較看需不需要在長度j這裏切割
                dp[i] = max(max(dp[j],j)*(i-j),dp[i])
        return dp[-1]
#2.奇妙數學法
#推導——儘可能將n長度三等分
'''
利用均值不等式求出乘積最大值 L(m)=(n/m)^m 對此式求導(可利用對數法),可以證明當 m=n/e 時,乘積取最大,此時每段繩子的長度爲 n/(n/e)=e,自然對數e的值爲2.718,接近3
'''
class Solution:
    def cuttingRope(self, n: int) -> int:
        if n <= 3: return n - 1
        a, b = n // 3, n % 3
        if b == 0: return int(math.pow(3, a))
        if b == 1: return int(math.pow(3, a - 1) * 4)
        return int(math.pow(3, a) * 2)

14-2.大數剪繩子,取模防溢出

class Solution:
    def cuttingRope(self, n: int) -> int:
        #dpdp
        dp = [0]*(n+1)
        dp[1]=1
        for i in range(2,n+1):
            for j in range(1,i):
                #j是減下來的長度,dp記錄當前長度最大切割乘積
                #max(dp[j],j)決定用切下來的那段再切切還是就不切了比較長
                #和dpi比較看需不需要在長度j這裏切割
                dp[i] = max(max(dp[j],j)*(i-j),dp[i])
                #大數的話在這一步就會溢出
        return dp[-1]% 1000000007

15.二進制中1的個數

#1.位運算1
class Solution:
    def hammingWeight(self, n: int) -> int:
        cnt=0
        while n!=0:
            '''
        1100:減一後變爲1011
        1100&1011=1000
        n與減1後的數做與運算會減少原本n的1個數
        即有幾個1就可以做幾次與運算
            '''
            cnt+=1
            n&=n-1
        return cnt
#2.位運算2
class Solution:
    def hammingWeight(self, n: int) -> int:
        cnt=0
        while n!=0:
            '''
            有符號右移>>(若正數,高位補0,負數,高位補1)
            無符號右移>>>(不論正負,高位均補0)
            然而py沒有無符號右移
            '''
            cnt+=n&1
            n>>=1
        return cnt

16. 數值的整數次方

#1.迭代快速冪,非位運算考量,其實位運算也可
class Solution:
    def myPow(self, x: float, n: int) -> float:
        #奇數、偶數、負數
        #偶數的話直接翻倍,奇數的話在外邊存儲一倍
        #一般快速冪
        if n==0:
            return 1
        if n==1:
            return x
        if n==-1:
            return 1/x
        m = abs(n)
        tmp = []
        while m>1:
            if m%2==0:
                x*=x
                m=m//2
            else:
                tmp.append(x)
                x*=x
                m=m//2
        while tmp:
            x*=tmp.pop()
        if n<0:
            return 1/x
        return x
#2.遞歸
class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
        if n < 0:
            return 1 / self.myPow(x, -n)
        # 如果是奇數
        if n & 1:
            return x * self.myPow(x, n - 1)
        return self.myPow(x * x, n // 2)

17.打印從1到最大的n位數

#1.普通
class Solution:
    def printNumbers(self, n: int) -> List[int]:
        return list(range(1,10**n))
#2.字符串,不過還不是大數,畢竟int(''.join(tmp))
class Solution:
    def printNumbers(self, n: int) -> List[int]:
        res = []
        tmp = ['']*n
        def helper(idx):
            if idx==n:
                res.append(int(''.join(tmp)))
                return 
            for i in range(10):
                tmp[idx]=chr(ord('0')+i)
                helper(idx+1)
        helper(0)
        return res[1:]
#3.大數-string操作
class Solution:
    def printNumbers(self, n: int) -> List[int]:

        def helper(cur_s: str, place: int, increas: int): # place = -1, -2, -3
            if abs(place) > len(cur_s):
            	#倒着數位數,用abs
                cur_s = '1' + cur_s
                #進位
                return cur_s
            else:
                if cur_s[place] != '9':
                    if place == -1:
                        cur_s = cur_s[:place] + str(int(cur_s[place]) + 1)
                    else:
                        cur_s = cur_s[:place] + str(int(cur_s[place]) + 1) + cur_s[place+1:]
                    return cur_s
                else:
                    #進位時place所在位位清0
                    if place == -1:
                        cur_s = cur_s[:place] + '0'
                    else:
                        cur_s = cur_s[:place] + '0' + cur_s[place+1:]
                    return helper(cur_s, place-1, 1)
        
        res = []
        cur_s = '0'
        while len(cur_s) <= n:
            res.append(int(cur_s))
            cur_s = helper(cur_s, -1, 1)#這樣即便是剛進位的2位數,也照樣從個位數開始增加返回
        return res[1:]

18.刪除鏈表的節點

#1.非空啞結點和一遍遍歷
#邊界值非空判斷其實也可以,但是雙指針優雅一點
class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head
        p = dummy
        while p and p.next:
            if p.next.val==val:
                p.next = p.next.next
                break
            p = p.next
        return dummy.next

19.正則表達式匹配(hard)

假設主串爲 AA,模式串爲 BB 從最後一步出發,需要關注最後進來的字符。假設 AA 的長度爲 nn ,BB 的長度爲 mm ,關注正則表達式 BB 的最後一個字符是誰,它有三種可能,正常字符、*∗ 和 .(點),那針對這三種情況討論即可,如下:
如果 B 的最後一個字符是正常字符,那就是看 A[n-1]是否等於 B[m−1],相等則看A0…n−2與B0…m−2,不等則是不能匹配,這就是子問題。
如果 B 的最後一個字符是.,它能匹配任意字符,直接看A 0…n−2與B 0…m−2

此時:f[i][j]=f[i−1][j−1]

如果 B 的最後一個字符是它代表 B[m-2]=cB[m−2]=c 可以重複0次或多次,它們是一個整體 c
情況一:A[n-1] 是 0 個 c,B 最後兩個字符廢了,能否匹配取決於A0…n−1 和B0…m−3是否匹配
情況二:A[n-1]是多個 c 中的最後一個(這種情況必須 A[n-1]=c 或者 c=’.’),所以 A 匹配完往前挪一個,B繼續匹配,因爲可以匹配多個,繼續看A0…n−2和 B_{0…m-1}B0…m−1是否匹配。

1:直接砍掉正則串的後面兩個, f[i][j] = f[i][j-2]
2:正則串不動,主串前移一個,f[i][j] = f[i-1][j]

dp邊界:
空串和空正則是匹配的,f[0][0] = truef[0][0]=true
空串和非空正則,不能直接定義 true 和 false,必須要計算出來。
非空串和空正則必不匹配,f[1][0]=…=f[n][0]=false

#1.dpdp
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        #竟然是dp
        lenp = len(p)
        lens = len(s)
        dp = [[False]*(lenp+1) for _ in range(lens+1)]
        dp[0][0]=True
        for j in range(1,lenp+1):
            if p[j-1]=='*':
                dp[0][j]=dp[0][j-1] or dp[0][j-2]#空串和非空正則,不能直接定義 true 和 false,必須要計算出來。
        for i in range(1,lens+1):
            for j in range(1,lenp+1):
                if s[i-1]==p[j-1] or p[j-1]=='.':
                    dp[i][j]=dp[i-1][j-1]#p和s當前字符匹配,進到下一字符
                elif p[j-1]=='*':
                    if s[i-1]==p[j-2] or p[j-2]=='.':#看再往前一個
                        #當前字符和前一個字符是匹配的
                        dp[i][j] = dp[i][j-2] or dp[i][j-1] or dp[i-1][j]#true/false傳遞
                        #1)刪除前一個字符 dp[i][j-2]
                        #2)保留前一個字符 dp[i][j-1]
                        #3)複製前一個字符 dp[i-1][j]
                    else:
                        #尾上2個p的字符廢了,只能刪除字符
                        dp[i][j] = dp[i][j-2] 
        return dp[-1][-1]
#2.遞歸
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        def match(s, p, i, j):
            if j == len(p): return i == len(s)#全空True,只有正則空False,若兩個指針都進行到頭True
            flag = (i != len(s) and (s[i] == p[j] or p[j] == "."))
            if j < len(p) - 1  and p[j+1] == "*":
                #flag==T,後者爲爲情況1or情況2;
                return flag and match(s, p, i+1, j) or match(s, p, i, j+2)
            else:#當前不是*,f[i][j]=f[i−1][j−1]
                return flag and match(s, p, i+1, j+1)
        return match(s,p,0,0)
#3.遞歸清晰版
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if not p: return not s
        first_match = bool(s) and p[0] in (".", s[0])
        if len(p) >= 2 and p[1] == "*":
            if first_match:
                return self.isMatch(s[1:], p) or self.isMatch(s, p[2:])
            return self.isMatch(s, p[2:])   
        return first_match and self.isMatch(s[1:], p[1:])
#4.Py正則
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        return re.fullmatch(p, s) != None

20.表示數值的字符串(hard)

#1.把輸入拆分改造成isnumeric可以判斷的程度,看按decimal格式拆分的部分是否都由數字組成
class Solution:
    def isNumber(self, s: str) -> bool:
        '''
        空格只能出現在首尾,出現在中間一定是非法的。
        正負號只能出現在兩個地方,第一個地方是數字的最前面,表示符號。
        第二個位置是e後面,表示指數的正負。如果出現在其他的位置一定也是非法的。
        e只能出現一次,並且e之後一定要有數字纔是合法的,123e這種也是非法的。
        小數點,由於e之後的指數一定是整數,所以小數點最多隻能出現一次,並且一定要在e之前。
        所以如果之前出現過小數點或者是e,再次出現小數點就是非法的。
        '''
        s = s.strip()  #去掉兩端的空白符
        if not s :
            return False
        else:
            if s[0] in ['+', '-']:
                #去掉正負號
                s = s[1:]  
            if 'e' in s:
                temp_list = s.split('e')
                if len(temp_list) > 2:  
                    #字符串s中含有多於一個的’e‘,返回False
                    return False
                temp_list[0] = temp_list[0].replace('.', '', 1)  #去掉e前面的字符串中的'.',只進行一次,還有就是有多個'.'
                if len(temp_list[1]) > 0 and temp_list[1][0] in ['+', '-']:  
                    # 去掉e後面字符串中的'+'或者'-',僅去掉一次,還有就是有多個'+', '-'
                    temp_list[1] = temp_list[1].replace(temp_list[1][0], '', 1)
                if temp_list[0].isnumeric() and temp_list[1].isnumeric():
                    return True
                return False
            else:  # s中不含'e'
                s = s.replace('.', '', 1)
                if s.isnumeric():
                    return True
                return False
#2.確定有限自動機DFA
#參考:https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/solution/que-ding-you-xian-zi-dong-ji-dfa-by-justyou/
class Solution:
    def isNumber(self, s: str) -> bool:
        if not s:
        	return False
        根據有限狀態的圖來建立的狀態跳轉表格
        transTable = [
            [1,2,7,-1,-1,0],
            [-1,2,7,-1,-1,-1],
            [-1,2,3,4,-1,9],
            [-1,3,-1,4,-1,9],
            [6,5,-1,-1,-1,-1],
            [-1,5,-1,-1,-1,9],
            [-1,5,-1,-1,-1,-1],
            [-1,8,-1,-1,-1,-1],
            [-1,8,-1,4,-1,9],
            [-1,-1,-1,-1,-1,9]
        ]

        cols = {
            "sign":0,
            "number":1,
            ".":2,
            "exp":3,
            "other":4,
            "blank":5  
        }

        def get_col(c):
        	#做判斷
            if c.isdigit():return 'number'
            elif c in {'+','-'}:return 'sign'
            elif c == '.':return '.'
            elif c in {'E','e'}:return 'exp'
            elif c == ' ':return 'blank'
            else:return 'other'

        legal_state = {2,3,5,8,9}#結束狀態
        '''
		中途遇到空格轉到9,若後邊還有別的直接就-1out,
        '''
        state = 0
        for c in s:
            state = transTable[state][cols[get_col(c)]]#結合當前的狀態和當前的字符來跳轉狀態
            if state == -1:
            	return False#沒能跳轉出去
        return True if state in legal_state else False

21.調整數組順序使奇數位於偶數前面

#1.暴力
class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        left = []
        right = []
        for i in range(len(nums)):
            if nums[i]%2==0:
                right.append(nums[i])
            else:
                left.append(nums[i])
        return left+right
#2.快排雙指針+swap
class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        #快排的雙指針妙用
        l = 0
        r = len(nums)-1
        while l<r:
            while l<r and nums[r]%2==0:
                r-=1
                #直到指針對撞或者找到右邊第一個奇數停止
            while l<r and nums[l]%2!=0:
                l+=1
                #直到指針對撞或者找到左邊第一個偶數停止
            nums[l],nums[r]=nums[r],nums[l]#swap
            l+=1
            r-=1
        return nums
#3.快慢雙指針
class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        #快排的雙指針妙用
        low = 0
        fast = 0
        while fast<len(nums):
            if nums[fast]%2!=0:
                nums[low],nums[fast]=nums[fast],nums[low]
                low+=1
            fast+=1
        return nums

22.鏈表中倒數第k個節點

#1.兩次遍歷法
class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        p = head
        cnt = 0
        while p:
            cnt+=1
            p = p.next
        cnt-=k
        p = head
        while cnt:
            p = p.next
            cnt-=1
        return p
#2.兩個指針法
class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        pre = head
        cur = head
        cnt = 1
        while cnt<k:
            cnt+=1
            cur = cur.next
        while cur.next:
            pre = pre.next
            cur = cur.next
        return pre

24.反轉鏈表

#全文背誦
#1.迭代
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
            return None
        pre = None
        while head:
            next = head.next
            head.next = pre
            pre = head
            head = next
        return pre
#2.遞歸
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        node = self.reverseList(head.next)
        head.next.next = head #自己和鄰居閉環
        head.next = None #去向通路阻斷
        return node

25.合併兩個排序的鏈表

#1.遞歸
class Solution:
    def mergeTwoLists(self, l1, l2):
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        elif l1.val < l2.val:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2
#2.迭代
class Solution:
    def mergeTwoLists(self, l1, l2):
        dummy = ListNode(0)
        pre = dummy
        while l1 and l2:
            if l1.val<=l2.val:
                pre.next = l1
                pre = pre.next
                l1 = l1.next
            else:
                pre.next = l2
                pre = pre.next
                l2 = l2.next
        if l1:
            pre.next = l1
        if l2:
            pre.next = l2
        return dummy.next

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章