[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

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