leetcode200_python

文章目录


DP

10. 正则表达式匹配
1626873747975
def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)

        def matches(i, j):
            if i == 0:
                return False
            if p[j -1] == '.':
                return True
            return s[i -1] == p[j - 1]
        
        f = [[False] * ( n + 1) for _ in range(m + 1)]
        f[0][0] = True
        for i in range(m + 1):
            for j in range(1, n + 1):
                if p[j -1] == '*':
                    f[i][j] |= f[i][j -2]
                    if matches(i, j -1):
                        f[i][j] |= f[i -1][j]
                
                else:
                    if matches(i, j):
                        f[i][j] |= f[i -1][j -1]
                    
        return f[m][n]
44. 通配符匹配
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)

        dp = [[False] * (n + 1) for _ in range(m + 1)]
        dp[0][0] = True
        for i in range(1, n + 1):
            if p[i - 1] == '*':
                dp[0][i] = True
            else:
                break
        
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if p[j - 1] == '*':
                    dp[i][j] = dp[i][j - 1] | dp[i - 1][j]
                elif p[j - 1] == '?' or s[i - 1] == p[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                
        return dp[m][n]



53. 最大子序和
def maxSubArray(self, nums):
        pre = 0
        maxAns = nums[0]
        for x in nums:
            pre = max(pre + x, x)
            maxAns = max(maxAns, pre)
        return maxAns
62. 不同路径
def uniquePaths(self, m: int, n: int) -> int:
        cur = [1] * n
        for i in range(1, m):
            for j in range(1, n):
                cur[j] += cur[j-1]
        return cur[-1]

def uniquePaths(self, m: int, n: int) -> int:
        return comb(m + n - 2, n - 1)


63. 不同路径 II
def uniquePathsWithObstacles(grid):
    m, n=len(grid), len(grid[0])
    dp = [[0]*n for _ in range(m)]
    i=0 # 第一列初始化
    while i<m and grid[i][0]!=1: 
        dp[i][0]=1
        i+=1
    j=0 # 第一行初始化
    while j<n and grid[0][j]!=1: 
        dp[0][j]=1
        j+=1
    # 递归
    for i in range(1,m):
        for j in range(1,n):
            if grid[i][j]!=1:
                if not grid[i-1][j]: dp[i][j]+=dp[i-1][j]
                if not grid[i][j-1]: dp[i][j]+=dp[i][j-1]
    return dp[-1][-1]

64. 最小路径和
 def minPathSum(self, grid: [[int]]) -> int:
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i == j == 0: continue
                elif i == 0:  grid[i][j] = grid[i][j - 1] + grid[i][j]
                elif j == 0:  grid[i][j] = grid[i - 1][j] + grid[i][j]
                else: grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]
        return grid[-1][-1]


120. 三角形最小路径和
def minimumTotal(self, triangle: List[List[int]]) -> int:
        if not triangle:return 0
        res = triangle[-1]
        for i in range(len(triangle)-2,-1,-1):
            for j in range(len(triangle[i])):
                res[j] = min(res[j],res[j+1]) + triangle[i][j]
        return res[0]
121. 买卖股票的最佳时机
def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n ==0:
            return 0
        dp = [0] * n
        minprice = prices[0]
        for i in range(1,n):
            minprice = min(minprice,prices[i])
            dp[i] = max(dp[i-1],prices[i] -minprice)
        return dp[-1]
122. 买卖股票的最佳时机 II
# 贪心 
  def maxProfit(self, prices: List[int]) -> int:
        profit = 0
        for i in range(1, len(prices)):
            tmp = prices[i] - prices[i - 1]
            if tmp > 0: profit += tmp
        return profit
        
# 动态规划
 def maxProfit(self, prices: List[int]) -> int:
        dp0 = 0             # 手里没股票
        dp1 = - prices[0]   # 手里有股票
        for i in range(1, len(prices)):
            dp0 = max(dp0, dp1 + prices[i])
            dp1 = max(dp1, dp0 - prices[i])
        return dp0

123. 买卖股票的最佳时机 III
def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        buy1 = buy2 = -prices[0]
        sell1 = sell2 = 0
        for i in range(1, n):
            buy1 = max(buy1, -prices[i])
            sell1 = max(sell1, buy1 + prices[i])
            buy2 = max(buy2, sell1 - prices[i])
            sell2 = max(sell2, buy2 + prices[i])
        return sell2
188. 买卖股票的最佳时机 IV
def maxProfit(self, k: int, prices: List[int]) -> int:
        if not prices:
            return 0

        n = len(prices)
        k = min(k, n//2)
        buy = [0] * (k+1)
        sell = [0]*(k+1)

        buy[0],sell[0] = -prices[0],0
        for i in range(1,k+1):
            buy[i] =sell[i] = float('-inf')

        for i in range(1,n):
            buy[0] = max(buy[0],sell[0] - prices[i])
            for j in range(1, k +1):
                buy[j] = max(buy[j],sell[j] - prices[i])
                sell[j] = max(sell[j],buy[j-1]+prices[i])

        return max(sell)
152. 乘积最大子数组
def maxProduct(self, nums: List[int]) -> int:
        reverse_nums = nums[::-1]
        for i in range(1, len(nums)):
            nums[i] *= nums[i - 1] or 1
           
            reverse_nums[i] *= reverse_nums[i - 1] or 1
        
        return max(nums + reverse_nums)
174. 地下城游戏
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
        n, m = len(dungeon), len(dungeon[0])
        BIG = 10 ** 9
        dp = [[BIG] * (m + 1) for _ in range(n + 1)]
        dp[n][m-1] = dp[n -1][m] = 1
        for i in range(n-1, -1, -1):
            for j in range(m -1, -1, -1):
                min_ = min(dp[i+1][j], dp[i][j + 1])
                dp[i][j] = max(min_ -dungeon[i][j], 1)
        return dp[0][0]
198. 打家劫舍
def rob(self, nums: List[int]) -> int:
        prev = 0
        curr = 0
        for i in nums:
            prev, curr = curr, max(curr, prev + i)
        return curr
213. 打家劫舍 II
 def rob(self, nums: List[int]) -> int:
        def robRange(start, end):
            first = nums[start]
            second = max(nums[start], nums[start + 1])
            for i in range(start + 2, end + 1):
                first, second = second, max(first + nums[i], second)
            return second

        length = len(nums)
        if length == 1:
            return nums[0]
        elif length == 2:
            return max(nums[0], nums[1])
        else:
            return max(robRange(0, length - 2), robRange(1, length - 1))
5. 最长回文子串
# 方法一:动态规划
def expandStr(self, s, left, right):
        while left >=0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return left + 1, right -1

    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n < 2:
            return s

        max_len = 1
        begin = 0
        dp =[[False] * n for _ in range(n)]
        for i in range(n):
            dp[i][i] = True

        for L in range(2, n + 1):
            for i in range(n):
                j = L + i -1
                if j >= n:
                    break

                if s[i] != s[j]:
                    dp[i][j] = False

                else:
                    if j - i < 3:
                        dp[i][j] = True
                    else:
                        dp[i][j] = dp[i+1][j-1]
                if dp[i][j] and j - i + 1 > max_len:
                    max_len = j - i + 1
                    begin = i
        return s[begin: begin + max_len]
        
# 方法二:中心扩展算法
class Solution:
    def expandAroundCenter(self, s, left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return left + 1, right - 1

    def longestPalindrome(self, s: str) -> str:
        start, end = 0, 0
        for i in range(len(s)):
            left1, right1 = self.expandAroundCenter(s, i, i)
            left2, right2 = self.expandAroundCenter(s, i, i + 1)
            if right1 - left1 > end - start:
                start, end = left1, right1
            if right2 - left2 > end - start:
                start, end = left2, right2
        return s[start: end + 1]

# 方法三:Manacher 算法
 def expand(self, s, left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return (right - left - 2) // 2

    def longestPalindrome(self, s: str) -> str:
        end, start = -1, 0
        s = '#' + '#'.join(list(s)) + '#'
        arm_len = []
        right = -1
        j = -1
        for i in range(len(s)):
            if right >= i:
                i_sym = 2 * j - i
                min_arm_len = min(arm_len[i_sym], right - i)
                cur_arm_len = self.expand(s, i - min_arm_len, i + min_arm_len)
            else:
                cur_arm_len = self.expand(s, i, i)
            arm_len.append(cur_arm_len)
            if i + cur_arm_len > right:
                j = i
                right = i + cur_arm_len
            if 2 * cur_arm_len + 1 > end - start:
                start = i - cur_arm_len
                end = i + cur_arm_len
        return s[start+1:end+1:2]

17. 电话号码的字母组合
def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return []
        ans = []
        dic = { "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",}

        def dfs(digits, level, temp):
            if level == len(digits):
                ans.append(''.join(temp))
            else:
                for letter in dic[digits[level]]:
                    temp.append(letter)
                    dfs(digits, level + 1, temp)
                    temp.pop()
        dfs(digits,0, [])
        return ans
72. 编辑距离
def minDistance(self, word1: str, word2: str) -> int:
        m, n = len(word1), len(word2)
        dp = list(range(n + 1))
        for i in range(m):
            lu = dp[0]
            dp[0] = i + 1
            for j in range(n):
                dp[j + 1], lu = min(dp[j] + 1, dp[j + 1] + 1, lu + int(word1[i] != word2[j])), dp[j + 1]
        return dp[-1]
    
def minDistance(self, word1: str, word2: str) -> int:
     
        m, n = len(word1), len(word2)
        dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
        for i in range(m + 1): dp[i][0] = i
        for j in range(n + 1): dp [0][j] = j
        
        for i in range(1,m + 1):
            for j in range(1,n + 1):
                dp[i][j] = min(dp[i-1][j-1] + (0 if word1[i-1] == word2[j-1] else 1),
                               dp[i-1][j] +1,
                               dp[i][j-1]+1)
        return dp[m][n]
115. 不同的子序列
def numDistinct(self, s: str, t: str) -> int:
        m, n = len(s), len(t)
        if m < n:
            return 0
        
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        for i in range(m + 1):
            dp[i][n] = 1
        
        for i in range(m - 1, -1, -1):
            for j in range(n - 1, -1, -1):
                if s[i] == t[j]:
                    dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j]
                else:
                    dp[i][j] = dp[i + 1][j]
        
        return dp[0][0]

131. 分割回文串
def partition(self, s: str) -> List[List[str]]:
        n = len(s)
        ret, ans = [], []

        @cache
        def isPalindrome(i, j):
            if i >= j:
                return 1
            return isPalindrome(i + 1, j - 1) if s[i] == s[j] else -1

        def dfs(i):
            if i == n:
                ret.append(ans[:])
                return
            
            for j in range(i, n):
                if isPalindrome(i, j) == 1:
                    ans.append(s[i: j + 1])
                    dfs(j + 1)
                    ans.pop()

        dfs(0)
        isPalindrome.cache_clear()
        return ret
132. 分割回文串 II
def minCut(self, s: str) -> int:
        n = len(s)
        g = [[True] * n for _ in range(n)]

        for i in range(n -1, -1,-1):
            for j in range(i + 1, n):
                g[i][j] = (s[i] == s[j]) and g[i + 1][j - 1]

        f = [float('inf')] * n
        for i in range(n):
            if g[0][i]:
                f[i] =0
            else:
                for j in range(i):
                    if g[j + 1][i]:
                        f[i] = min(f[i], f[j] + 1)
        
        return f[n -1]
161. 相隔为 1 的编辑距离
def isOneEditDistance(self, s: str, t: str) -> bool:
        ns,nt = len(s), len(t)

        if ns > nt:
            return self.isOneEditDistance(t, s)
        
        if nt - ns > 1:
            return False

        for i in range(ns):
            if s[i] != t[i]:
                if ns == nt:
                    return s[i + 1:] == t[i+1:]
                else:
                    return s[i:] == t[i+1:]
        return ns + 1 == nt

递归 & 回溯 & 迭代

21. 合并两个有序链表
# 递归
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
# 迭代
 def mergeTwoLists(self, l1, l2):
        prehead = ListNode(-1)

        prev = prehead
        while l1 and l2:
            if l1.val <= l2.val:
                prev.next = l1
                l1 = l1.next
            else:
                prev.next = l2
                l2 = l2.next            
            prev = prev.next

        # 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev.next = l1 if l1 is not None else l2

        return prehead.next
24. 两两交换链表中的节点
# 递归
def swapPairs(self, head: ListNode)->ListNode:
    if not head or not head.next:
        return head
    newHead = head.next
    head.next = self.swapPairs(newHead.next)
    newHead.next=head
    return newHead

# 迭代
 def swapPairs(self, head: ListNode) -> ListNode:
        dummyHead = ListNode(0)
        dummyHead.next = head
        temp = dummyHead
        while temp.next and temp.next.next:
            node1 = temp.next
            node2 = temp.next.next
            temp.next = node2
            node1.next = node2.next
            node2.next = node1
            temp = node1
        return dummyHead.next


101. 对称二叉树
1. 递归
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        
        def symmetric(left,right):
            if left and not right: return False
            elif not left and right: return False
            elif not left and not right: return True
            else:
                return left.val==right.val and symmetric(left.left,right.right) and symmetric(left.right,right.left)

        return symmetric(root.left,root.right)

    
def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        queue_ = [root.left, root.right]
        while queue_:
            left = queue_.pop()
            right = queue_.pop()
            if not left and not right:
                continue
            if not left or not right:
                return False
            if left.val != right.val:
                return False
            queue_.append(left.left)
            queue_.append(right.right)
            queue_.append(left.right)
            queue_.append(right.left)
        return True
77. 组合
 def combine(self, n: int, k: int) -> List[List[int]]:
        # 排列组合的性质:C(m,n)=C(m-1,n)+C(m-1,n-1)
        if k > n or k == 0: return []
        if k == 1: 
            return [[i] for i in range(1, n+1)]
        if k == n:
            return [[i for i in range(1, n+1)]]
        res = self.combine(n-1, k)
        for item in self.combine(n-1, k-1):
            item.append(n)
            res.append(item)
        return res

78. 子集
# 库函数
def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        for i in range(len(nums)+1):
            for tmp in itertools.combinations(nums, i):
                res.append(tmp)
        return res
# 迭代
def subsets(self, nums: List[int]) -> List[List[int]]:
        res = [[]]
        for i in nums:
            res = res + [[i] + num for num in res]
        return res
# 递归
def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        n = len(nums)
        
        def helper(i, tmp):
            res.append(tmp)
            for j in range(i, n):
                helper(j + 1,tmp + [nums[j]] )
        helper(0, [])
        return res  

90. 子集 II
def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if not nums:
            return []
        n = len(nums)
        res = []
        nums.sort()
		# 思路1
        def helper1(idx, n, temp_list):
            if temp_list not in res:
                res.append(temp_list)
            for i in range(idx, n):
                helper1(i + 1, n, temp_list + [nums[i]])
		# 思路2
        def helper2(idx, n, temp_list):
            res.append(temp_list)
            for i in range(idx, n):
                if i > idx and  nums[i] == nums[i - 1]:
                    continue
                helper2(i + 1, n, temp_list + [nums[i]])

        helper2(0, n, [])
        return res


def subsetsWithDup(self, nums: List[int]) ->List[List[int]]:
        nums.sort()
        ans = set()
        cur = []
        self.dfs(nums, 0, cur, ans)
        return [list(x) for x in ans]

    def dfs(self, nums, u, cur, ans):
        if u == len(nums):
            ans.add(tuple(cur))
            return
        cur.append(nums[u])
        self.dfs(nums, u + 1,cur, ans)
        cur.pop()
        self.dfs(nums, u + 1, cur, ans)
79. 单词搜索
# 方法一:回溯
 def exist(self, board: List[List[str]], word: str) -> bool:
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

        def check(i: int, j: int, k: int) -> bool:
            if board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True
            
            visited.add((i, j))
            result = False
            for di, dj in directions:
                newi, newj = i + di, j + dj
                if 0 <= newi < len(board) and 0 <= newj < len(board[0]):
                    if (newi, newj) not in visited:
                        if check(newi, newj, k + 1):
                            result = True
                            break
            
            visited.remove((i, j))
            return result

        h, w = len(board), len(board[0])
        visited = set()
        for i in range(h):
            for j in range(w):
                if check(i, j, 0):
                    return True
        
        return False

22. 括号生成
@lru_cache(None)
def generateParenthesis(self, n):
        if n ==0:
            return ['']
        ans = []
        for c in range(n):
            for left in self.generateParenthesis(c):
                for right in self.generateParenthesis(n-1-c):
                    ans.append('({}){}'.format(left,right))
        return ans
87. 扰乱字符串
@cache
def isScramble(self, s1: str, s2: str) -> bool:
        if len(s1) != len(s2):
            return False

        if s1 == s2:
            return True
        if sorted(s1) != sorted(s2):
            return False

        for i in range(1, len(s1)):
            if self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:]) or \
                    (self.isScramble(s1[:i], s2[-i:]) and self.isScramble(s1[i:], s2[:-i])):
                return True
        return False
139. 单词拆分
def wordBreak(self, s: str, wordDict: List[str]) -> bool:       
        n=len(s)
        dp=[False]*(n+1)
        dp[0]=True
        for i in range(n):
            for j in range(i+1,n+1):
                if(dp[i] and (s[i:j] in wordDict)):
                    dp[j]=True
        return dp[-1]

# 记忆化回溯
 def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        import functools
        @functools.lru_cache(None)
        def back_track(s):
            if(not s):
                return True
            res=False
            for i in range(1,len(s)+1):
                if(s[:i] in wordDict):
                    res=back_track(s[i:]) or res
            return res
        return back_track(s)
140. 单词拆分 II
 def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        @lru_cache(None)
        def backtrack(index: int) -> List[List[str]]:
            if index == len(s):
                return [[]]
            ans = list()
            for i in range(index + 1, len(s) + 1):
                word = s[index:i]
                if word in wordSet:
                    nextWordBreaks = backtrack(i)
                    for nextWordBreak in nextWordBreaks:
                        ans.append(nextWordBreak.copy() + [word])
            return ans
        
        wordSet = set(wordDict)
        breakList = backtrack(0)
        return [" ".join(words[::-1]) for words in breakList]


165. 比较版本号
  def get_next_chunk(self, version, n,p):
        if p > n -1:
            return 0, p
        p_end = p
        while p_end < n and version[p_end] !='.':
            p_end +=1
        i = int(version[p:p_end]) if p_end != n - 1 else int(version[p:n])
        p = p_end + 1
        return i, p

    def compareVersion(self, version1: str, version2: str) -> int:
        p1 = p2 = 0
        n1, n2 = len(version1), len(version2)
        while p1 < n1 or p2 < n2:
            i1, p1 = self.get_next_chunk(version1, n1, p1)
            i2, p2 = self.get_next_chunk(version2, n2, p2)
            if i1 != i2:
                return 1 if i1 > i2 else -1
        
        return 0
186. 翻转字符串里的单词 II
 def reverseWords(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        i = 0
        for j in range(len(s)):
            if s[j] != ' ':
                continue
            self.reverse(s, i,j)
            i = j + 1
        self.reverse(s, i, len(s))
        self.reverse(s, 0, len(s))

    def reverse(self, s, i, j):
        for k in range(i, (i + j) //2):
            g = j - 1 - k + i
            s[k], s[g] = s[g], s[k]
138. 复制带随机指针的链表
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    def __init__(self):
        self.visitedHash = {}

    def copyRandomList(self, head: 'Node') -> 'Node':
        if head is None:
            return 
        
        if head in self.visitedHash:
            return self.visitedHash[head]
        

        node = Node(head.val,None, None)

        self.visitedHash[head] = node

        node.next = self.copyRandomList(head.next)
        node.random = self.copyRandomList(head.random)

        return node

DFS & BFS

36. 有效的数独
 def isValidSudoku(self, board: List[List[str]]) -> bool:
        rows = [{} for i in range(9)]
        columns = [{} for i in range(9)]
        boxes = [{} for i in range(9)]
        
        for i in range(9):
            for j in range(9):
                num = board[i][j]
                if num !='.':
                    num = int(num)
                    box_index = (i//3)* 3 + j//3
                    
                    rows[i][num] = rows[i].get(num,0)+1
                    columns[j][num] = columns[j].get(num,0) + 1
                    boxes[box_index][num] = boxes[box_index].get(num,0) +1
                    
                    if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1:
                        return False
        return True
37. 解数独
def solveSudoku(self, board: List[List[str]]) -> None:
        def flip(i, j, digit):
            line[i] ^= (1 << digit)
            col[j] ^= ( 1<< digit)
            block[i//3][j//3] ^=(1<<digit)
        
        def dfs(pos):
            nonlocal valid
            if pos == len(spaces):
                valid = True
                return 
            i, j = spaces[pos]
            mask = ~(line[i] | col[j] | block[i//3][j//3]) & 0x1ff
            while mask:
                digitMask = mask & (-mask)
                digit = bin(digitMask).count("0") - 1
             
                flip(i, j, digit)
                board[i][j] = str(digit + 1)
                dfs(pos + 1)
                flip(i,j,digit)
                mask &= (mask -1)
                if valid:
                    return 
        
        line = [0] * 9 
        col = [0] * 9 
        block = [[0] * 3 for _ in range(3)]
        valid = False
        spaces = list()
        
        for i in range(9):
            for j in range(9):
                if board[i][j] == '.':
                    spaces.append((i,j))
                else:
                    digit = int(board[i][j]) -1
                    flip(i, j, digit)
                    
        dfs(0)
39. 组合总和
  def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        ans = []
        temp = []
        def dfs(candidates, target):
            
            if target ==0:
                ans.append(temp)
            if target > 0:
                num = candidates[0]
                target -= num
                dfs(candidates, target)
                target += num
40. 组合总和 II
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        def dfs(pos, rest):
            nonlocal sequence
            if rest == 0:
                ans.append(sequence[:])
                return 
            if pos == len(freq) or rest < freq[pos][0]:
                return
            
            dfs(pos + 1, rest)

            most = min(rest // freq[pos][0], freq[pos][1])
            for i in range(1, most + 1):
                sequence.append(freq[pos][0])
                dfs(pos + 1, rest - i * freq[pos][0])
            sequence = sequence[:-most]
        
        freq = sorted(collections.Counter(candidates).items())
        ans = list()
        sequence = list()
        dfs(0, target)
        return ans
216. 组合总和 III
# 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
# 输入: k = 3, n = 7, 输出: [[1,2,4]]

 def combinationSum3(self, k, n):
        res = []
        def backtrack(path, index, n, k):
            if n == 0 and k == 0:       #单次结束并添加的条件,和为n, 总数为k. 
                res.append(path[:])     #添加路径到结果中,注意[:]的使用
                return
            for i in range(index, 10):  #遍历的路径,也就是1-9.
                path.append(i)          #添加进路径
                backtrack(path, i + 1, n - i, k - 1) #递归,并index加1防止重复值加入。
                path.pop()              #回溯
        backtrack([], 1, n, k)
        return res

# Python 内部已经实现了常用的排列与组合的函数在itertools模块下

product 笛卡尔积  (有放回抽样排列)
permutations 排列  (不放回抽样排列)
combinations 组合没有重复  (不放回抽样组合)
combinations_with_replacement 组合有重复 (有放回抽样组合)
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        return [list(i) for i in itertools.combinations(range(1,10), k) if sum(i) ==  n]


46. 全排列
def permute(self, nums: List[int]) -> List[List[int]]:
        ans = []
        temp = []

        def dfs(nums,level):
            if level ==len(nums)-1:
                return ans.append(nums[:])
            for i in range(level, len(nums)):

                nums[level], nums[i] = nums[i], nums[level]
                dfs(nums, level + 1)
                nums[level], nums[i] = nums[i], nums[level]
        
        dfs(nums,0)
        return ans
47. 全排列 II
from typing import List
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:    

        def dfs(nums, size, depth, path, used, res):
            if depth == size:
                res.append(path.copy())
                return

            for i in range(size):
                if not used[i]:
                    if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]: 
                        continue
                    used[i] = True
                    path.append(nums[i])
                    dfs(nums, size, depth + 1, path, used, res)
                    used[i] = False
                    path.pop()

        size = len(nums)
        if size == 0:
            return []
        nums.sort()
        used = [False] * len(nums)
        res = []
        dfs(nums, size, 0, [], used, res)
        return res
51. N 皇后
def solveNQueens(self, n: int) -> List[List[str]]:
        def generateBoard():
            board = list()
            for i in range(n):
                row[queens[i]] = 'Q'
                board.append(''.join(row))
                row[queens[i]] = '.'
            return board

        def solve(row, columns, pie, na):
            if row == n:
                board = generateBoard()
                solutions.append(board)
                return
            bits = (~(columns | pie | na) & (1 << n) - 1)
            while bits:
                position = bits & -bits
                column = bin(position -1).count('1')
                queens[row] = column
                solve(row + 1,columns|position,(pie|position)<<1,(na|position)>>1)
                bits = bits &(bits -1)

        solutions = list()
        queens = [-1] * n
        row = ['.'] * n
        solve(0, 0, 0, 0)
        return solutions
130. 被围绕的区域
def solve(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        if not board:
            return
        
        n, m = len(board), len(board[0])

        def dfs(x, y ):
            if not 0 <= x < n or not 0 <= y < m or board[x][y] !='O':
                return

            board[x][y] = 'A'
            dfs(x + 1,y)
            dfs(x -1,y)
            dfs(x, y + 1)
            dfs(x, y -1)

        for i in range(n):
            dfs(i, 0)
            dfs(i, m -1)

        for i in range(m -1):
            dfs(0, i)
            dfs(n -1, i)

        for i in range(n):
            for j in range(m):
                if board[i][j] == 'A':
                    board[i][j] ='O'
                elif board[i][j] == 'O':
                    board[i][j] = 'X'
200. 岛屿数量
def numIslands(self, grid: List[List[str]]) -> int:
        nr = len(grid)
        if nr == 0:
            return 0
        nc = len(grid[0])
        num_islands = 0
        for r in range(nr):
            for c in range(nc):
                if grid[r][c] == '1':
                    num_islands += 1
                    grid[r][c] = '0'
                    neighbors = collections.deque([(r, c)])
                    while neighbors:
                        row, col = neighbors.popleft()
                        for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
                            if 0 <= x < nr and 0 <= y < nc and grid[x][y] == '1':
                                neighbors.append((x, y))
                                grid[x][y] = '0'
        return num_islands
212. 单词搜索 II
 def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        if not board or not board[0]:
            return []
        if not words:
            return []

        self.result = set()

        root = collections.defaultdict()
        for word in words:
            node = root
            for char in word:
                node = node.setdefault(char,collections.defaultdict())
            node[END_OF_WORD] = END_OF_WORD
        self.m, self.n = len(board),len(board[0])

        for i in range(self.m):
            for j in range(self.n):
                if board[i][j] in root:
                    self._dfs(board,i,j,"",root)

        return list(self.result)

    def _dfs(self, board, i, j,cur_word, cur_dict):
        cur_word += board[i][j]
        cur_dict = cur_dict[board[i][j]]
        
        if END_OF_WORD in cur_dict:
            self.result.add(cur_word)
        
        tmp,board[i][j] = board[i][j],'@'
        for k in range(4):
            x, y= i + dx[k],j + dy[k]
            if 0<=x < self.m and 0 <=y<self.n and board[x][y] !='@' and board[x][y] in cur_dict:
                self._dfs(board,x,y,cur_word,cur_dict)
        board[i][j] = tmp
        
# 方法一:使用前缀树的回溯

 def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        WORD_KEY = '$'
        
        trie = {}
        for word in words:
            node = trie
            for letter in word:
                # retrieve the next node; If not found, create a empty node.
                node = node.setdefault(letter, {})
            # mark the existence of a word in trie node
            node[WORD_KEY] = word
        
        rowNum = len(board)
        colNum = len(board[0])
        
        matchedWords = []
        
        def backtracking(row, col, parent):    
            
            letter = board[row][col]
            currNode = parent[letter]
            
            # check if we find a match of word
            word_match = currNode.pop(WORD_KEY, False)
            if word_match:
                # also we removed the matched word to avoid duplicates,
                #   as well as avoiding using set() for results.
                matchedWords.append(word_match)
            
            # Before the EXPLORATION, mark the cell as visited 
            board[row][col] = '#'
            
            # Explore the neighbors in 4 directions, i.e. up, right, down, left
            for (rowOffset, colOffset) in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
                newRow, newCol = row + rowOffset, col + colOffset     
                if newRow < 0 or newRow >= rowNum or newCol < 0 or newCol >= colNum:
                    continue
                if not board[newRow][newCol] in currNode:
                    continue
                backtracking(newRow, newCol, currNode)
        
            # End of EXPLORATION, we restore the cell
            board[row][col] = letter
        
            # Optimization: incrementally remove the matched leaf node in Trie.
            if not currNode:
                parent.pop(letter)

        for row in range(rowNum):
            for col in range(colNum):
                # starting from each of the cells
                if board[row][col] in trie:
                    backtracking(row, col, trie)
        
        return matchedWords    

链接:https://leetcode-cn.com/problems/word-search-ii/solution/dan-ci-sou-suo-ii-by-leetcode/

91. 解码方法
	@functools.lru_cache(None)
    def numDecodings(self, s: str) -> int:
        
        alpha = set(str(i) for i in range(1, 27))
        self.ans = 0

        def dfs(s):
            if len(s) == 0:
                self.ans += 1
                return
            if s[0] in alpha:
                dfs(s[1:])
            if len(s) > 1 and s[:2] in alpha:
                dfs(s[2:])
            return

        dfs(s)
        return self.ans
93. 复原 IP 地址
 def restoreIpAddresses(self, s: str) -> List[str]:
        SEG_COUNT = 4
        ans = []
        segments = [0] * SEG_COUNT

        def dfs(segId, segStart):
            if segId == SEG_COUNT:
                if segStart == len(s):
                    ipAddr = '.'.join(str(seg) for seg in segments)
                    ans.append(ipAddr)
                return

            if segStart == len(s):
                return 
            
            if s[segStart] == '0':
                segments[segId] = 0
                dfs(segId + 1, segStart + 1)
            
            addr = 0
            for segEnd in range(segStart,len(s)):
                addr = addr* 10 + (ord(s[segEnd]) - ord('0'))
                if 0 < addr <= 0xFF:
                    segments[segId] = addr
                    dfs(segId + 1, segEnd + 1)
                else:
                    break
        
        dfs(0, 0)
        return ans
97. 交错字符串
 def isInterleave(self,s1, s2, s3):
        import functools
        n1, n2, n3 = len(s1), len(s2), len(s3)

        @functools.lru_cache(None)
        def helper(i, j, k):
            if i == n1 and j == n2 and k == n3:
                return True
            if k < n3:
                if i < n1 and s1[i] == s3[k] and helper(i + 1, j, k + 1):
                    return True
                if j < n2 and s2[j] == s3[k] and helper(i, j + 1, k + 1):
                    return True
            return False
        print(helper.cache_info())
        return helper(0, 0, 0)


def isInterleave(self,s1, s2, s3):
        len1,len2,len3 = len(s1),len(s2),len(s3)
        if(len1 + len2 != len3):
            return False
        dp = [[False] * (len2 + 1) for i in range(len1 +1)]
        dp[0][0]= True
        for i in range(1,len1 + 1):
            dp[i][0] = (dp[i-1][0] and s1[i-1]==s3[i-1])
        for i in range(1,len2 + 1):
            dp[0][i] = (dp[0][i-1] and s2[i-1] == s3[i -1])
        for i in range(1,len1 +1):
            for j in range(1,len2 +1):
                dp[i][j] = (dp[i][j-1] and s2[j-1] == s3[i+j-1])or (dp[i-1][j] and s1[i-1]==s3[i + j -1])
        return dp[-1][-1]
126. 单词接龙 II
from collections import defaultdict
from typing import List
from collections import deque
import string


class Solution:

    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        # 先将 wordList 放到哈希表里,便于判断某个单词是否在 wordList 里
        word_set = set(wordList)
        res = []
        if len(word_set) == 0 or endWord not in word_set:
            return res

        successors = defaultdict(set)
        # 第 1 步:使用广度优先遍历得到后继结点列表 successors
        # key:字符串,value:广度优先遍历过程中 key 的后继结点列表

        found = self.__bfs(beginWord, endWord, word_set, successors)
        if not found:
            return res
        # 第 2 步:基于后继结点列表 successors ,使用回溯算法得到所有最短路径列表
        path = [beginWord]
        self.__dfs(beginWord, endWord, successors, path, res)
        return res

    def __bfs(self, beginWord, endWord, word_set, successors):
        queue = deque()
        queue.append(beginWord)

        visited = set()
        visited.add(beginWord)

        found = False
        word_len = len(beginWord)
        next_level_visited = set()

        while queue:
            current_size = len(queue)
            for i in range(current_size):
                current_word = queue.popleft()
                word_list = list(current_word)

                for j in range(word_len):
                    origin_char = word_list[j]

                    for k in string.ascii_lowercase:
                        word_list[j] = k
                        next_word = ''.join(word_list)

                        if next_word in word_set:
                            if next_word not in visited:
                                if next_word == endWord:
                                    found = True

                                # 避免下层元素重复加入队列
                                if next_word not in next_level_visited:
                                    next_level_visited.add(next_word)
                                    queue.append(next_word)

                                successors[current_word].add(next_word)
                    word_list[j] = origin_char
            if found:
                break
            # 取两集合全部的元素(并集,等价于将 next_level_visited 里的所有元素添加到 visited 里)
            visited |= next_level_visited
            next_level_visited.clear()
        return found

    def __dfs(self, beginWord, endWord, successors, path, res):
        if beginWord == endWord:
            res.append(path[:])
            return

        if beginWord not in successors:
            return

        successor_words = successors[beginWord]
        for next_word in successor_words:
            path.append(next_word)
            self.__dfs(next_word, endWord, successors, path, res)
            path.pop()

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <queue>


using namespace std;

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string> &wordList) {
        vector<vector<string>> res;
        // 因为需要快速判断扩展出的单词是否在 wordList 里,因此需要将 wordList 存入哈希表,这里命名为「字典」
        unordered_set<string> dict = {wordList.begin(), wordList.end()};
        // 修改以后看一下,如果根本就不在 dict 里面,跳过
        if (dict.find(endWord) == dict.end()) {
            return res;
        }
        // 特殊用例处理
        dict.erase(beginWord);

        // 第 1 步:广度优先遍历建图
        // 记录扩展出的单词是在第几次扩展的时候得到的,key:单词,value:在广度优先遍历的第几层
        unordered_map<string, int> steps = {{beginWord, 0}};
        // 记录了单词是从哪些单词扩展而来,key:单词,value:单词列表,这些单词可以变换到 key ,它们是一对多关系
        unordered_map<string, set<string>> from = {{beginWord, {}}};
        int step = 0;
        bool found = false;
        queue<string> q = queue<string>{{beginWord}};
        int wordLen = beginWord.length();
        while (!q.empty()) {
            step++;
            int size = q.size();
            for (int i = 0; i < size; i++) {
                const string currWord = move(q.front());
                string nextWord = currWord;
                q.pop();
                // 将每一位替换成 26 个小写英文字母
                for (int j = 0; j < wordLen; ++j) {
                    const char origin = nextWord[j];
                    for (char c = 'a'; c <= 'z'; ++c) {
                        nextWord[j] = c;
                        if (steps[nextWord] == step) {
                            from[nextWord].insert(currWord);
                        }
                        if (dict.find(nextWord) == dict.end()) {
                            continue;
                        }
                        // 如果从一个单词扩展出来的单词以前遍历过,距离一定更远,为了避免搜索到已经遍历到,且距离更远的单词,需要将它从 dict 中删除
                        dict.erase(nextWord);
                        // 这一层扩展出的单词进入队列
                        q.push(nextWord);
                        // 记录 nextWord 从 currWord 而来
                        from[nextWord].insert(currWord);
                        // 记录 nextWord 的 step
                        steps[nextWord] = step;
                        if (nextWord == endWord) {
                            found = true;
                        }
                    }
                    nextWord[j] = origin;
                }
            }
            if (found) {
                break;
            }
        }
        // 第 2 步:深度优先遍历找到所有解,从 endWord 恢复到 beginWord ,所以每次尝试操作 path 列表的头部
        if (found) {
            vector<string> Path = {endWord};
            dfs(res, endWord, from, Path);
        }
        return res;
    }

    void dfs(vector<vector<string>> &res, const string &Node, unordered_map<string, set<string>> &from,
             vector<string> &path) {
        if (from[Node].empty()) {
            res.push_back({path.rbegin(), path.rend()});
            return;
        }
        for (const string &Parent: from[Node]) {
            path.push_back(Parent);
            dfs(res, Parent, from, path);
            path.pop_back();
        }
    }
};

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class Solution {

    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        List<List<String>> res = new ArrayList<>();
        // 因为需要快速判断扩展出的单词是否在 wordList 里,因此需要将 wordList 存入哈希表,这里命名为「字典」
        Set<String> dict = new HashSet<>(wordList);
        // 特殊用例判断
        if (!dict.contains(endWord)) {
            return res;
        }

        dict.remove(beginWord);

        // 第 1 步:广度优先遍历建图
        // 记录扩展出的单词是在第几次扩展的时候得到的,key:单词,value:在广度优先遍历的第几层
        Map<String, Integer> steps = new HashMap<>();
        steps.put(beginWord, 0);
        // 记录了单词是从哪些单词扩展而来,key:单词,value:单词列表,这些单词可以变换到 key ,它们是一对多关系
        Map<String, List<String>> from = new HashMap<>();
        int step = 1;
        boolean found = false;
        int wordLen = beginWord.length();
        Queue<String> queue = new LinkedList<>();
        queue.offer(beginWord);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String currWord = queue.poll();
                char[] charArray = currWord.toCharArray();
                // 将每一位替换成 26 个小写英文字母
                for (int j = 0; j < wordLen; j++) {
                    char origin = charArray[j];
                    for (char c = 'a'; c <= 'z'; c++) {
                        charArray[j] = c;
                        String nextWord = String.valueOf(charArray);
                        if (steps.containsKey(nextWord) && step == steps.get(nextWord)) {
                            from.get(nextWord).add(currWord);
                        }
                        if (!dict.contains(nextWord)) {
                            continue;
                        }
                        // 如果从一个单词扩展出来的单词以前遍历过,距离一定更远,为了避免搜索到已经遍历到,且距离更远的单词,需要将它从 dict 中删除
                        dict.remove(nextWord);
                        // 这一层扩展出的单词进入队列
                        queue.offer(nextWord);

                        // 记录 nextWord 从 currWord 而来
                        from.putIfAbsent(nextWord, new ArrayList<>());
                        from.get(nextWord).add(currWord);
                        // 记录 nextWord 的 step
                        steps.put(nextWord, step);
                        if (nextWord.equals(endWord)) {
                            found = true;
                        }
                    }
                    charArray[j] = origin;
                }
            }
            step++;
            if (found) {
                break;
            }
        }

        // 第 2 步:深度优先遍历找到所有解,从 endWord 恢复到 beginWord ,所以每次尝试操作 path 列表的头部
        if (found) {
            Deque<String> path = new ArrayDeque<>();
            path.add(endWord);
            dfs(from, path, beginWord, endWord, res);
        }
        return res;
    }

    public void dfs(Map<String, List<String>> from, Deque<String> path, String beginWord, String cur, List<List<String>> res) {
        if (cur.equals(beginWord)) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (String precursor : from.get(cur)) {
            path.addFirst(precursor);
            dfs(from, path, beginWord, precursor, res);
            path.removeFirst();
        }
    }
}
127. 单词接龙
# 双向广度优先搜索
 def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        def addWord(word: str):
            if word not in wordId:
                nonlocal nodeNum
                wordId[word] = nodeNum
                nodeNum += 1
        
        def addEdge(word: str):
            addWord(word)
            id1 = wordId[word]
            chars = list(word)
            for i in range(len(chars)):
                tmp = chars[i]
                chars[i] = "*"
                newWord = "".join(chars)
                addWord(newWord)
                id2 = wordId[newWord]
                edge[id1].append(id2)
                edge[id2].append(id1)
                chars[i] = tmp

        wordId = dict()
        edge = collections.defaultdict(list)
        nodeNum = 0

        for word in wordList:
            addEdge(word)
        
        addEdge(beginWord)
        if endWord not in wordId:
            return 0
        
        disBegin = [float("inf")] * nodeNum
        beginId = wordId[beginWord]
        disBegin[beginId] = 0
        queBegin = collections.deque([beginId])

        disEnd = [float("inf")] * nodeNum
        endId = wordId[endWord]
        disEnd[endId] = 0
        queEnd = collections.deque([endId])

        while queBegin or queEnd:
            queBeginSize = len(queBegin)
            for _ in range(queBeginSize):
                nodeBegin = queBegin.popleft()
                if disEnd[nodeBegin] != float("inf"):
                    return (disBegin[nodeBegin] + disEnd[nodeBegin]) // 2 + 1
                for it in edge[nodeBegin]:
                    if disBegin[it] == float("inf"):
                        disBegin[it] = disBegin[nodeBegin] + 1
                        queBegin.append(it)

            queEndSize = len(queEnd)
            for _ in range(queEndSize):
                nodeEnd = queEnd.popleft()
                if disBegin[nodeEnd] != float("inf"):
                    return (disBegin[nodeEnd] + disEnd[nodeEnd]) // 2 + 1
                for it in edge[nodeEnd]:
                    if disEnd[it] == float("inf"):
                        disEnd[it] = disEnd[nodeEnd] + 1
                        queEnd.append(it)
        
        return 0

# 广度优先搜索 + 优化建图
     def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        def addWord(word: str):
            if word not in wordId:
                nonlocal nodeNum
                wordId[word] = nodeNum
                nodeNum += 1
        
        def addEdge(word: str):
            addWord(word)
            id1 = wordId[word]
            chars = list(word)
            for i in range(len(chars)):
                tmp = chars[i]
                chars[i] = "*"
                newWord = "".join(chars)
                addWord(newWord)
                id2 = wordId[newWord]
                edge[id1].append(id2)
                edge[id2].append(id1)
                chars[i] = tmp

        wordId = dict()
        edge = collections.defaultdict(list)
        nodeNum = 0

        for word in wordList:
            addEdge(word)
        
        addEdge(beginWord)
        if endWord not in wordId:
            return 0
        
        dis = [float("inf")] * nodeNum
        beginId, endId = wordId[beginWord], wordId[endWord]
        dis[beginId] = 0

        que = collections.deque([beginId])
        while que:
            x = que.popleft()
            if x == endId:
                return dis[endId] // 2 + 1
            for it in edge[x]:
                if dis[it] == float("inf"):
                    dis[it] = dis[x] + 1
                    que.append(it)
        
        return 0
221. 最大正方形
  def maximalSquare(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0
        
        maxSide = 0
        rows, columns = len(matrix), len(matrix[0])
        dp = [[0] * columns for _ in range(rows)]
        for i in range(rows):
            for j in range(columns):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                    maxSide = max(maxSide, dp[i][j])
        
        maxSquare = maxSide * maxSide
        return maxSquare

133. 克隆图
"""
class Node:
    def __init__(self, val = 0, neighbors = None):
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []
"""

class Solution:
    def __init__(self):
        self.visited = {}

    def cloneGraph(self, node: 'Node') -> 'Node':
        if not node:
            return node
        
        if node in self.visited:
            return self.visited[node]

        clone_node = Node(node.val, [])

        self.visited[node] = clone_node

        if node.neighbors:
            clone_node.neighbors = [self.cloneGraph(n) for n in node.neighbors]

        return clone_node
207. 课程表
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        edges = collections.defaultdict(list)
        indegrees = [0] * numCourses

        for info in prerequisites:
            edges[info[1]].append(info[0])
            indegrees[info[0]] += 1
        q = collections.deque([u for u in range(numCourses) if indegrees[u] == 0])
        visited = 0

        while q:
            visited +=1
            u = q.popleft()
            for v in edges[u]:
                indegrees[v] -= 1
                if indegrees[v] == 0:
                    q.append(v)

        return visited == numCourses
        
210. 课程表 II
# 返回你为了学完所有课程所安排的学习顺序
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        edges = collections.defaultdict(list)
        visited = [0] * numCourses
        result = list()
        valid = True

        for info in prerequisites:
            edges[info[1]].append(info[0])

        def dfs(u):
            nonlocal valid
            visited[u] = 1
            for v in edges[u]:
                if visited[v] == 0:
                    dfs(v)
                    if not valid:
                        return
                elif visited[v] == 1:
                    valid = False
                    return
            visited[u] = 2
            result.append(u)

        for i in range(numCourses):
            if valid and not visited[i]:
                dfs(i)
        if not valid:
            return list()

        return result[::-1]

贪心

45. 跳跃游戏 II
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        maxPos, end, step = 0, 0, 0
        for i in range(n - 1):
            if maxPos >= i:
                maxPos = max(maxPos, i + nums[i])
                if i == end:
                    end = maxPos
                    step += 1
        return step
55. 跳跃游戏
 def canJump(self, nums: List[int]) -> bool:
        max_i = 0
        for i, jump in enumerate(nums):
            if max_i>=i and i+jump>max_i:
                max_i = i+jump
        
        return max_i>=i
134. 加油站
def canCompleteCircuit(self, gas, cost):
        if sum(gas) < sum(cost):
            return -1
        total = start = 0
        for i in range(len(gas)):
            total += gas[i] - cost[i]
            if total < 0:
                total = 0
                start = i + 1
        return start
# 暴力
def canCompleteCircuit(self, gas, cost):
        if sum(gas) < sum(cost):
            return -1
        ln = len(gas)
        for i in range(ln):
            if gas[i] < cost[i]:
                continue
            total = 0
            for j in range(i, i + ln):
                j %= ln
                total += gas[j] - cost[j]
                if total < 0:
                    break
            else:
                return i
        return -1

双指针(滑动窗口)

3. 无重复字符的最长子串
 def lengthOfLongestSubstring(self, s: str) -> int:
        cache = {}
        left = maxlen=0
        for i, j in enumerate(s):
            if j in cache:
                left = max(left, cache[j]  +1 )
            cache[j] = i
            maxlen = max(maxlen, i - left + 1)
        return maxlen
11. 盛最多水的容器
def maxArea(self, height: List[int]) -> int:
        ans = 0
        n = len(height)
        left, right = 0, n -1
        while left < right:
            cur = min(height[right], height[left] )* (right - left)
            ans = max(ans, cur)
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return ans
15. 三数之和
def threeSum(self, nums: List[int]) -> List[List[int]]:

        res = []
        nums.sort()
        for i in range(len(nums) -2):
            if i > 0 and nums[i] == nums[i -1]:
                continue
            l, r = i + 1, len(nums) -1
            while l < r:
                s = nums[i] + nums[l] + nums[r]
                if s < 0: l += 1
                elif s > 0: r -= 1
                else:
                    res.append((nums[i], nums[l], nums[r]))
                    while l < r and nums[l] == nums[l + 1]:
                        l += 1
                    while l < r and nums[r] == nums[r -1]:
                        r -= 1
                    l += 1;r -=1
        return res
16. 最接近的三数之和
def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        n = len(nums)
        best = 10**7
        
        # 根据差值的绝对值来更新答案
        def update(cur):
            nonlocal best
            if abs(cur - target) < abs(best - target):
                best = cur
        
        # 枚举 a
        for i in range(n):
            # 保证和上一次枚举的元素不相等
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            # 使用双指针枚举 b 和 c
            j, k = i + 1, n - 1
            while j < k:
                s = nums[i] + nums[j] + nums[k]
                # 如果和为 target 直接返回答案
                if s == target:
                    return target
                update(s)
                if s > target:
                    # 如果和大于 target,移动 c 对应的指针
                    k0 = k - 1
                    # 移动到下一个不相等的元素
                    while j < k0 and nums[k0] == nums[k]:
                        k0 -= 1
                    k = k0
                else:
                    # 如果和小于 target,移动 b 对应的指针
                    j0 = j + 1
                    # 移动到下一个不相等的元素
                    while j0 < k and nums[j0] == nums[j]:
                        j0 += 1
                    j = j0

        return best
18. 四数之和
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        quadruplets = list()
        if not nums or len(nums) < 4:
            return quadruplets
        
        nums.sort()
        length = len(nums)
        for i in range(length - 3):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:
                break
            if nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target:
                continue
            for j in range(i + 1, length - 2):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
                    break
                if nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target:
                    continue
                left, right = j + 1, length - 1
                while left < right:
                    total = nums[i] + nums[j] + nums[left] + nums[right]
                    if total == target:
                        quadruplets.append([nums[i], nums[j], nums[left], nums[right]])
                        while left < right and nums[left] == nums[left + 1]:
                            left += 1
                        left += 1
                        while left < right and nums[right] == nums[right - 1]:
                            right -= 1
                        right -= 1
                    elif total < target:
                        left += 1
                    else:
                        right -= 1
        
        return quadruplets
167. 两数之和 II - 输入有序数组
def twoSum(self, numbers: List[int], target: int) -> List[int]:
        low, high = 0, len(numbers) - 1
        while low < high:
            total = numbers[low] + numbers[high]
            if total == target:
                return [low + 1, high + 1]
            elif total < target:
                low += 1
            else:
                high -= 1

        return [-1, -1]

#  二分查找
 def twoSum(self, numbers: List[int], target: int) -> List[int]:
        n = len(numbers)
        for i in range(n):
            low, high = i + 1, n - 1
            while low <= high:
                mid = (low + high) // 2
                if numbers[mid] == target - numbers[i]:
                    return [i + 1, mid + 1]
                elif numbers[mid] > target - numbers[i]:
                    high = mid - 1
                else:
                    low = mid + 1
        
        return [-1, -1]

26. 删除有序数组中的重复项
 def removeDuplicates(self, nums: List[int]) -> int:
        if not nums:
            return 0
        
        n = len(nums)
        fast = slow = 1
        while fast < n:
            if nums[fast] != nums[fast - 1]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        
        return slow

80. 删除有序数组中的重复项 II
def removeDuplicates(self, nums: List[int]) -> int:
        # 变动1: 由于元素可以重复2次,left现在从第二个元素开始,right从第三个元素开始
        left = 1
        for right in range(2, len(nums)):
            # 变动2: 以前之和nums[left]比, 现在还要和nums[left - 1]比,从而保证元素可以重复两次
            if nums[right] == nums[left] and nums[right] == nums[left - 1]:
                continue
            left += 1
            nums[left] = nums[right]
        return left + 1

# 至多K次
 def removeDuplicates(self, nums: List[int], K: int) -> int:
        left = K - 1
        for right in range(K, len(nums)):
            tag = True
            for i in range(K):
                tag *= nums[right] == nums[left - i]
            if tag:
                continue

            left += 1
            nums[left] = nums[right]
        return left + 1


75. 颜色分类
# 方法一:单指针
 def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        ptr = 0
        for i in range(n):
            if nums[i] == 0:
                nums[i], nums[ptr] = nums[ptr], nums[i]
                ptr += 1
        for i in range(ptr, n):
            if nums[i] == 1:
                nums[i], nums[ptr] = nums[ptr], nums[i]
                ptr += 1

# 方法二:双指针
 def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        p0 = p1 = 0
        for i in range(n):
            if nums[i] == 1:
                nums[i], nums[p1] = nums[p1], nums[i]
                p1 += 1
            elif nums[i] == 0:
                nums[i], nums[p0] = nums[p0], nums[i]
                if p0 < p1:
                    nums[i], nums[p1] = nums[p1], nums[i]
                p0 += 1
                p1 += 1


# 方法三:双指针
def sortColors(self, nums: List[int]) -> None:
        n = len(nums)
        p0, p2 = 0, n - 1
        i = 0
        while i <= p2:
            while i <= p2 and nums[i] == 2:
                nums[i], nums[p2] = nums[p2], nums[i]
                p2 -= 1
            if nums[i] == 0:
                nums[i], nums[p0] = nums[p0], nums[i]
                p0 += 1
            i += 1


209. 长度最小的子数组
  def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums:
            return 0
        
        n = len(nums)
        ans = n + 1
        start, end = 0, 0
        total = 0
        while end < n:
            total += nums[end]
            while total >= s:
                ans = min(ans, end - start + 1)
                total -= nums[start]
                start += 1
            end += 1
        
        return 0 if ans == n + 1 else ans
        
# 方法二:前缀和 + 二分查找
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums:
            return 0
        
        n = len(nums)
        ans = n + 1
        sums = [0]
        for i in range(n):
            sums.append(sums[-1] + nums[i])
        
        for i in range(1, n + 1):
            target = s + sums[i - 1]
            bound = bisect.bisect_left(sums, target)
            if bound != len(sums):
                ans = min(ans, bound - (i - 1))
        
        return 0 if ans == n + 1 else ans

30. 串联所有单词的子串
def findSubstring(self, s: str, words: List[str]) -> List[int]:
        allWords = collections.Counter(words)
        wordNum = len(words)
        wordLen = len(words[0])
        res = []
        for i in range(len(s) - wordNum * wordLen + 1):
            subWords = collections.defaultdict(int)
            index = i
            while index < i + wordNum * wordLen:
                curWord = s[index: index + wordLen]
                if curWord not in allWords or subWords[curWord] == allWords[curWord]:
                    break
                subWords[curWord] += 1
                index += wordLen
            if index == i + wordNum * wordLen:
                res.append(i)
        return res
def findSubstring(self, s: str, words: List[str]) -> List[int]:
        from collections import Counter
        if not s or not words:return []
        one_word = len(words[0])
        word_num = len(words)
        n = len(s)
        if n < one_word:return []
        words = Counter(words)
        res = []
        for i in range(0, one_word):
            cur_cnt = 0
            left = i
            right = i
            cur_Counter = Counter()
            while right + one_word <= n:
                w = s[right:right + one_word]
                right += one_word
                if w not in words:
                    left = right
                    cur_Counter.clear()
                    cur_cnt = 0
                else:
                    cur_Counter[w] += 1
                    cur_cnt += 1
                    while cur_Counter[w] > words[w]:
                        left_w = s[left:left+one_word]
                        left += one_word
                        cur_Counter[left_w] -= 1
                        cur_cnt -= 1
                    if cur_cnt == word_num :
                        res.append(left)
        return res

38. 外观数列
def countAndSay(self, n: int) -> str:
        pre = ''
        cur = '1'

        # 从第 2 项开始
        for _ in range(1, n):
            # 这里注意要将 cur 赋值给 pre
            # 因为当前项,就是下一项的前一项。有点绕,尝试理解下
            pre = cur
            # 这里 cur 初始化为空,重新拼接
            cur = ''
            # 定义双指针 start,end
            start = 0
            end = 0
            # 开始遍历前一项,开始描述
            while end < len(pre):
                # 统计重复元素的次数,出现不同元素时,停止
                # 记录出现的次数,
                while end < len(pre) and pre[start] == pre[end]:
                    end += 1
                # 元素出现次数与元素进行拼接
                cur += str(end-start) + pre[start]
                # 这里更新 start,开始记录下一个元素
                start = end
        
        return cur

76. 最小覆盖子串
def minWindow(self, s: str, t: str) -> str:
        need=collections.defaultdict(int)
        for c in t:
            need[c]+=1
        needCnt=len(t)
        i=0
        res=(0,float('inf'))
        for j,c in enumerate(s):
            if need[c]>0:
                needCnt-=1
            need[c]-=1
            if needCnt==0:       #步骤一:滑动窗口包含了所有T元素
                while True:      #步骤二:增加i,排除多余元素
                    c=s[i] 
                    if need[c]==0:
                        break
                    need[c]+=1
                    i+=1
                if j-i<res[1]-res[0]:   #记录结果
                    res=(i,j)
                need[s[i]]+=1  #步骤三:i增加一个位置,寻找新的满足条件滑动窗口
                needCnt+=1
                i+=1
        return '' if res[1]>len(s) else s[res[0]:res[1]+1]    #如果res始终没被更新过,代表无满足条件的结果

159. 至多包含两个不同字符的最长子串
def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
        n = len(s)
        if n < 3:
            return n
        
        left, right = 0, 0
        hashmap = collections.defaultdict()

        max_len = 2

        while right <n:
            if len(hashmap) < 3:
                hashmap[s[right]] = right
                right +=1
            
            if len(hashmap) == 3:
                del_idx = min(hashmap.values())
                del hashmap[s[del_idx]]
                left = del_idx + 1

            max_len = max(max_len, right - left)
        
        return max_len

单调栈

42. 接雨水
 def trap(self, height):
        ans = 0
        stack = list()
        n = len(height)
        height = [0] + height + [0]
        for i, h in enumerate(height):
            while stack and h > height[stack[-1]]:
                top = stack.pop()
             
                if not stack:
                    break
                currHeigh = min(height[stack[-1]], height[i]) - height[top]
                ans +=  (i - stack[-1] - 1) * currHeigh
            stack.append(i)

        return ans
84. 柱状图中最大的矩形
def largestRectangleArea(self, heights: List[int]) -> int:
        stack = []
        heights = [0] + heights + [0]
        res = 0
        for i, h in enumerate(heights):
            while stack and heights[stack[-1]] > h:
                tmp = stack.pop()
                
                res = max(res, (i - stack[-1] -1) * heights[tmp])
            stack.append(i)
        return res
85. 最大矩形
def maximalRectangle(self, matrix: List[List[str]]) -> int:
        res = 0
        if not matrix or not matrix[0]:
            return res
            
        def helper(arr):
            nonlocal res
            stack = []
            for i in range(len(arr)):
                while stack and arr[i] < arr[stack[-1]]:
                    idx =stack.pop()
                    res = max(res, (i -stack[-1] -1) * arr[idx])
                stack.append(i)

        r, c = len(matrix), len(matrix[0])
        cnts = [0] * (c + 2)
        for i in range(r):
            for j in range(c):
                if matrix[i][j] == '1':
                    cnts[j +1] +=1
                else:
                    cnts[j+1] = 0
            helper(cnts)
        return res

二分法

4. 寻找两个正序数组的中位数
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        n1 = len(nums1)
        n2 = len(nums2)
        if n1 > n2:
            return self.findMedianSortedArrays(nums2, nums1)
        
        k = ( n1 + n2 + 1)//2
        left = 0
        right = n1 
        while left < right:
            m1 = left + (right - left)//2
            m2 = k - m1
            if nums1[m1] < nums2[m2-1]:
                left = m1 + 1
            else:
                right = m1
                
        m1 = left 
        m2 = k - m1
        
        c1 = max(nums1[m1 -1] if m1> 0 else float('-inf'), 
                nums2[m2 -1] if m2 > 0 else float('-inf'))
        if ( n1 + n2 ) % 2 == 1:
            return c1
        
        c2 = min(nums1[m1] if m1 < n1 else float('inf'),
                nums2[m2] if m2 < n2 else float('inf'))
        return (c1 + c2) /2
33. 搜索旋转排序数组
def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        l, r = 0, len(nums) - 1
        while l <= r:
            mid = (l + r) // 2
            if nums[mid] == target:
                return mid
            if nums[0] <= nums[mid]:
                if nums[0] <= target < nums[mid]:
                    r = mid - 1
                else:
                    l = mid + 1
            else:
                if nums[mid] < target <= nums[len(nums) - 1]:
                    l = mid + 1
                else:
                    r = mid - 1
        return -1
81. 搜索旋转排序数组 II
def search(self, nums: List[int], target: int) -> bool:
        if not nums:
            return False
        n = len(nums)
        if n == 1:
            return nums[0] == target
        
        l, r = 0, n - 1
        while l <= r:
            mid = (l + r) //2
            if nums[mid] == target:
                return True
            if nums[l] == nums[mid] and nums[mid] == nums[r]:
                l += 1
                r -=1
            elif nums[l] <= nums[mid]:
                if nums[l] <= target and target <= nums[mid]:
                    r = mid -1
                else:
                    l = mid + 1
            else:
                if nums[mid] < target and target <= nums[n - 1]:
                    l = mid + 1
                else:
                    r = mid - 1
        return False
34. 在排序数组中查找元素的第一个和最后一个位置
import bisect
class Solution:
    def searchRange(self, nums, target):
        left = bisect.bisect_left(nums,target)
        if left == len(nums) or nums[left] != target:
            return [-1,-1]
        right = bisect.bisect_right(nums,target)
        return [left,right - 1]

class Solution:
    def searchRange(self, nums, target):

        def bisect_left(num):
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left + right) // 2
                if num <= nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
            return left

        begin = bisect_left(target)
        if begin == len(nums) or nums[begin] != target:
            return [-1, -1]
        return [begin, bisect_left(target + 1) - 1]


35. 搜索插入位置
class Solution:
    def searchInsert(self, nums, target):
        return bisect.bisect_left(nums, target)
74. 搜索二维矩阵
 def searchMatrix(self, matrix, target):
        M, N = len(matrix), len(matrix[0])
        left, right = 0, M * N - 1
        while left <= right:
            mid = left + (right - left) // 2
            cur = matrix[mid // N][mid % N]
            if cur == target:
                return True
            elif cur < target:
                left = mid + 1
            else:
                right = mid - 1
        return False

153. 寻找旋转排序数组中的最小值
def findMin(self, nums: List[int]) -> int:
        left, right = 0, len(nums) -1
        while left < right:
            mid = (left + right) >> 1
            if nums[mid] > nums[right]:
                left = mid + 1
            else:
                right = mid
        
        return nums[left]
154. 寻找旋转排序数组中的最小值 II
def findMin(self, nums: List[int]) -> int:
        low,high = 0,len(nums) -1
        while low < high:
            pivot = low + (high - low) //2
            if nums[pivot] < nums[high]:
                high = pivot
            elif nums[pivot] > nums[high]:
                low = pivot + 1
            else:
                high -= 1
        return nums[low]
162. 寻找峰值
# 方法一: 线性扫描
def findPeakElement(self, nums: List[int]) -> int:
        for i in range(len(nums) - 1):
            if nums[i] > nums[i+1]:
                return i
        return len(nums) -1
# 二分
def findPeakElement(self, nums: List[int]) -> int:
    if len(nums)==1: return 0
    n=len(nums)
    if nums[0]>nums[1]: return 0
    if nums[n-1]>nums[n-2]: return n-1
    left, right=0, n-1
    # left<=mid<right<n 所以 mid+1<n
    while left<right:
        mid=(left+right)//2
        # 直到退回不等的时候, 根据nums[mid]和nums[mid+1]的关系来判断
        if nums[mid]>nums[mid+1]:
            #因为mid<right 所以这步也缩小了区间
            right=mid 
        else:
            #因为nums[mid]<=nums[mid+1] 无论是<还是= 令left=mid+1都不会漏掉
            left=mid+1 
    return left

def findPeakElement(self, nums: List[int]) -> int:
        nums.append(-float("inf"))
        lo, hi = 0, len(nums) - 1
        while lo < hi:
            mid = (lo + hi) // 2
            if nums[mid] < nums[mid + 1]:
                lo = mid + 1
            else:
                hi = mid
        return lo
410. 分割数组的最大值
 def splitArray(self, nums: List[int], m: int) -> int:
        def check(x):
            total, cnt = 0, 1
            for num in nums:
                if total + num > x:                   
                    cnt += 1
                    total = num
                else:
                    total += num
            return cnt <= m
        
        left = max(nums)
        right = sum(nums)
        while left < right:
            mid = (left + right) //2
            if check(mid):
                right = mid
            else:
                left = mid + 1
        
        return left

105. 从前序与中序遍历序列构造二叉树
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        def myBuildTree(preorder_left,preorder_right,inorder_left,inorder_right):
            if preorder_left > preorder_right:
                return None
            preorder_root = preorder_left
            inorder_root = index[preorder[preorder_root]]

            root = TreeNode(preorder[preorder_root])
            size_left_subtree = inorder_root - inorder_left
            root.left = myBuildTree(preorder_left +1,preorder_left + size_left_subtree,inorder_left,inorder_root -1)
            root.right = myBuildTree(preorder_left+size_left_subtree + 1,preorder_right,inorder_root+1,inorder_right)
            return root
        n = len(preorder)
        index = {element: i for i, element in enumerate(inorder)}
        return myBuildTree(0,n-1,0,n-1)
106. 从中序与后序遍历序列构造二叉树
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        def helper(in_left, in_right):
            if in_left > in_right:
                return None
            val = postorder.pop()
            root = TreeNode(val)
            index = idx_map[val]

            root.right = helper(index + 1, in_right)
            root.left = helper(in_left, index  -1)
            return root
        
        idx_map = {val:idx for idx, val in enumerate(inorder)}
        return helper(0, len(inorder) -1)
108. 将有序数组转换为二叉搜索树
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        def helper(left, right):
            if left > right:
                return

            mid = (left + right + randint(0, 1)) // 2

            root = TreeNode(nums[mid])
            root.left = helper(left, mid - 1)
            root.right = helper(mid + 1, right)
            return root

        return helper(0, len(nums) - 1)
94. 二叉树的中序遍历
 def inorderTraversal(self, root: TreeNode) -> List[int]:
        ret = []
        res = []
        if not root:
            return 
    
        res.append(root.val)
     
        self.inorderTraversal(root.left)
        self.inorderTraversal(root.right)
        print( res)
   
        return res
144. 二叉树的前序遍历
def preorderTraversal(self, root: TreeNode) -> List[int]:
        def preorder(root: TreeNode):
            if not root:
                return
            res.append(root.val)
            preorder(root.left)
            preorder(root.right)
        
        res = list()
        preorder(root)
        return res
def preorderTraversal(self, root: TreeNode) -> List[int]:
        res = list()
        if not root:
            return res
        
        stack = []
        node = root
        while stack or node:
            while node:
                res.append(node.val)
                stack.append(node)
                node = node.left
            node = stack.pop()
            node = node.right
        return res

145. 二叉树的后序遍历
def postorderTraversal(self, root: TreeNode) -> List[int]:
        ans = []
        def post(root):
           
            if root is None:
                return root
            post(root.left)
            post(root.right)
            ans.append(root.val)
        post(root)
        return ans
95. 不同的二叉搜索树 II
# 给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n # 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        def generateTrees(start, end):
            if start > end:
                return [None,]
            
            allTrees = []
            for i in range(start,end+ 1):
                leftTrees = generateTrees(start, i -1)
                rightTrees = generateTrees(i + 1, end)

                for l in leftTrees:
                    for r in rightTrees:
                        currTree = TreeNode(i)
                        currTree.left = l
                        currTree.right = r
                        allTrees.append(currTree)
            return allTrees

        return generateTrees(1, n) if n else []
96. 不同的二叉搜索树
1626920972816
# 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二# 叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
def numTrees(self, n: int) -> int:
        C = 1 
        for i in range(0, n):
            C = C * 2 * (2 * i + 1) / (i + 2)
        return int(C)
 def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        G = [0]*(n+1)
        G[0], G[1] = 1, 1

        for i in range(2, n+1):
            for j in range(1, i+1):
                G[i] += G[j-1] * G[i-j]

        return G[n]


98. 验证二叉搜索树
def isValidBST(self,root):
        def isBST(root:TreeNode, min_val, max_val):
            if root is None: return True
            if root.val >= max_val or root.val <= min_val:
                return False
            return isBST(root.left, min_val, root.val) and \
                isBST(root.right,root.val, max_val)
        return isBST(root, float('-inf'),float('inf'))
99. 恢复二叉搜索树
 def recoverTree(self, root: TreeNode) -> None:
        self.firstNode = None
        self.secondNode = None
        self.preNode = TreeNode(float('-inf'))
        stack = []
        p = root
        while stack or p:
            while p:
                stack.append(p)
                p = p.left
            p = stack.pop()
        
            if not firstNode and pre.val > p.val:
                firstNode = pre
            if firstNode and pre.val > p.val:
                secondNode = p
            pre = p
            p = p.right
        firstNode.val, secondNode.val = secondNode.val, firstNode.val
        
        
# 线索二叉树
def recoverTree(self, root: TreeNode) -> None:

        x, y, pre, tmp = None, None, None, None
        while root:
            if root.left:
                tmp = root.left
                while tmp.right and tmp.right != root:
                    tmp = tmp.right
                if tmp.right is None: # 建立线索
                    tmp.right = root
                    root = root.left
                else:
                    if pre and pre.val > root.val:
                        y = root
                        if not x:
                            x = pre
                    pre = root
                    tmp.right = None  # 拆除线索
                    root = root.right
                        
            else:
                if pre and pre.val > root.val:
                    y = root
                    if not x:
                        x = pre
                pre = root
                root = root.right
        if x and y:
            x.val, y.val = y.val, x.val
108. 将有序数组转换为二叉搜索树
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        def helper(left, right):
            if left > right:
                return

            mid = (left + right + randint(0, 1)) // 2

            root = TreeNode(nums[mid])
            root.left = helper(left, mid - 1)
            root.right = helper(mid + 1, right)
            return root

        return helper(0, len(nums) - 1)
109. 有序链表转换二叉搜索树
def sortedListToBST(self, head: ListNode) -> TreeNode:
        def getMedian(left,right):
            fast = slow = left
            while fast != right and fast.next != right:
                fast = fast.next.next
                slow = slow.next
            return slow

        def buildTree(left, right):
            if left  == right:
                return None
            mid = getMedian(left, right)
            root = TreeNode(mid.val)
            root.left = buildTree(left, mid)
            root. right = buildTree(mid.next, right)
            return root
        
        return buildTree(head, None)
100. 相同的树
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if not p and not q: return True
        elif not p or not q: return False
        elif p.val != q.val: return False
        else: return self.isSameTree(p.left, q.left) and 						 	self.isSameTree(p.right, q.right)
# 方法二:广度优先搜索
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if not p and not q:
            return True
        if not p or not q:
            return False
        
        queue1 = collections.deque([p])
        queue2 = collections.deque([q])

        while queue1 and queue2:
            node1 = queue1.popleft()
            node2 = queue2.popleft()
            if node1.val != node2.val:
                return False
            left1, right1 = node1.left, node1.right
            left2, right2 = node2.left, node2.right
            if (not left1) ^ (not left2):
                return False
            if (not right1) ^ (not right2):
                return False
            if left1:
                queue1.append(left1)
            if right1:
                queue1.append(right1)
            if left2:
                queue2.append(left2)
            if right2:
                queue2.append(right2)

        return not queue1 and not queue2
101. 对称二叉树
# 递归
def isSymmetric(self, root):
		"""
		:type root: TreeNode
		:rtype: bool
		"""
		if not root:
			return True
		def dfs(left,right):
			# 递归的终止条件是两个节点都为空
			# 或者两个节点中有一个为空
			# 或者两个节点的值不相等
			if not (left or right):
				return True
			if not (left and right):
				return False
			if left.val!=right.val:
				return False
			return dfs(left.left,right.right) and dfs(left.right,right.left)
		# 用递归函数,比较左节点,右节点
		return dfs(root.left,root.right)
# 队列实现
def isSymmetric(self, root):
		"""
		:type root: TreeNode
		:rtype: bool
		"""
		if not root or not (root.left or root.right):
			return True
		# 用队列保存节点	
		queue = [root.left,root.right]
		while queue:
			# 从队列中取出两个节点,再比较这两个节点
			left = queue.pop(0)
			right = queue.pop(0)
			# 如果两个节点都为空就继续循环,两者有一个为空就返回false
			if not (left or right):
				continue
			if not (left and right):
				return False
			if left.val!=right.val:
				return False
			# 将左节点的左孩子, 右节点的右孩子放入队列
			queue.append(left.left)
			queue.append(right.right)
			# 将左节点的右孩子,右节点的左孩子放入队列
			queue.append(left.right)
			queue.append(right.left)
		return True
110. 平衡二叉树
def isBalanced(self, root: TreeNode) -> bool:
        def height(root):
            if not root:
                return 0
            leftHeight = height(root.left)
            rightHeight = height(root.right)
            if leftHeight == -1 or rightHeight == -1 or abs(height(root.left)- height(root.right)) > 1:
                return -1
            return max(leftHeight, rightHeight) + 1

        return height(root) >= 0
226. 翻转二叉树
 def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return root
        
        left = self.invertTree(root.left)
        right = self.invertTree(root.right)
        root.left, root.right = right, left
        return root
222. 完全二叉树的节点个数
 def countNodes(self, root: TreeNode) -> int:
        # 满二叉树公式
        def getNodesNum(node: TreeNode):
            if not node:
                return 0
            left_node = node.left
            right_node = node.right
            left_h, right_h = 0, 0
            while left_node:
                left_node = left_node.left
                left_h += 1
            while right_node:
                right_node = right_node.right
                right_h += 1
            if left_h == right_h:
                return (2 << left_h) - 1
            return getNodesNum(node.left) + getNodesNum(node.right) + 1
        return getNodesNum(root)

        # 迭代
        '''
        if not root:
            return 0
        queue = collections.deque()
        queue.append(root)
        res = 0
        while queue:
            sz = len(queue)
            for i in range(sz):
                node = queue.popleft()
                res += 1
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return res
        '''

        # 递归
        def getNodesNum(cur: TreeNode):
            if not cur:
                return 0
            left_node   = getNodesNum(cur.left)
            right_node  = getNodesNum(cur.right)
            treeNum     = left_node + right_node + 1
            return treeNum
        return getNodesNum(root)
      

102. 二叉树的层序遍历
  def levelOrder(self,root):
        if root is None:
            return []
        
        result = []
        queue = deque()
        queue.append(root)
        
        #visited  = []
        
        while queue:
            level_size = len(queue)
            current_level = []
            
            for _ in range(level_size):
                node = queue.popleft()
                current_level.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
                
            result.append(current_level)
            
        return result
        
        
def levelOrder(self, root):
        if not root: return []
        self.result = []
        self._dfs(root, 0)
        return self.result

    def _dfs(self, node, level):
        if not node: return

        if len(self.result) < level +1:
            self.result.append([])

        self.result[level].append(node.val)

        self._dfs(node.left,level +1)
        self._dfs(node.right,level + 1)
107. 二叉树的层序遍历 II
# 给定一个二叉树,返回其节点值自底向上的层序遍历
 def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
      
        levelOrder = list()
        if not root:
            return levelOrder
        
        q = collections.deque([root])
        while q:
            level = list()
            size = len(q)
            for _ in range(size):
                node = q.popleft()
                level.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            levelOrder.append(level)
            
        return levelOrder[::-1]
103. 二叉树的锯齿形层序遍历
 def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        
        if not root:
            return []
        import collections
        queue = collections.deque()
        queue.append(root)
        
        index = 1
        res = []
        while queue:
            size = len(queue)
            tmp = []
            for _ in range(size):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            if (index &1) ==1:
                res.append(tmp)
            else:
                res.append(tmp[::-1])
            index +=1
        return res
987. 二叉树的垂序遍历
def verticalTraversal(self, root):
        seen = collections.defaultdict(
                  lambda: collections.defaultdict(list))

        def dfs(node, x=0, y=0):
            if node:
                seen[x][y].append(node)
                dfs(node.left, x-1, y+1)
                dfs(node.right, x+1, y+1)

        dfs(root)
        ans = []
        
        for x in sorted(seen):
            report = []
            for y in sorted(seen[x]):
                
                report.extend(sorted(node.val for node in seen[x][y]))
            ans.append(report)

        return ans
199. 二叉树的右视图
def rightSideView(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        
        queue = [root]
        res = []
        while queue:
            res.append(queue[-1].val)
            l1 = []
            for node in queue:
                if node.left:
                    l1.append(node.left)
                if node.right:
                    l1.append(node.right)
            queue = l1
        return res
104. 二叉树的最大深度
def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        return 1 + max(self.maxDepth(root.left),self.maxDepth(root.right))
        
        
def maxDepth(self, root: TreeNode) -> int:
        nodes = []
        level =0
        if not root:return level
        nodes.append(root)
        while nodes:
            level +=1
            tmp = []
            for node in nodes:
                if node.left:
                    tmp.append(node.left)
                if node.right:
                    tmp.append(node.right)
            nodes = tmp
        return level
111. 二叉树的最小深度
def minDepth(self,root):
        if not root:
            return 0
        
        queue = collections.deque([(root,1)])
        while queue:
            node,depth = queue.popleft()
            if not node.left and not node.right:
                return depth
            if node.left:
                queue.append((node.left,depth +1))
            if node.right:
                queue.append((node.right,depth + 1))
        return 0
        
def minDepth(self,root):
 
        if not root: return 0
        if not root.left and not root.right:
            return 1
        min_depth = 10 ** 9
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)
        return min_depth + 1
230. 二叉搜索树中第K小的元素
def kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """
        def inorder(r):
            return inorder(r.left) + [r.val] + inorder(r.right) if r else []
    
        return inorder(root)[k - 1]

 def kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """
        stack = []
        
        while True:
            while root:
                stack.append(root)
                root = root.left
            root = stack.pop()
            k -= 1
            if not k:
                return root.val
            root = root.right

236. 二叉树的最近公共祖先
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':

        if not root or root ==p or root ==q :
            return root
        left = self.lowestCommonAncestor(root.left,p,q)
        right = self.lowestCommonAncestor(root.right,p,q)
        if not left:return right
        if not right:return left
        return root
105. 从前序与中序遍历序列构造二叉树
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        def myBuildTree(preorder_left,preorder_right,inorder_left,inorder_right):
            if preorder_left > preorder_right:
                return None
            preorder_root = preorder_left
            inorder_root = index[preorder[preorder_root]]

            root = TreeNode(preorder[preorder_root])
            size_left_subtree = inorder_root - inorder_left
            root.left = myBuildTree(preorder_left +1,preorder_left + size_left_subtree,inorder_left,inorder_root -1)
            root.right = myBuildTree(preorder_left+size_left_subtree + 1,preorder_right,inorder_root+1,inorder_right)
            return root
        n = len(preorder)
        index = {element: i for i, element in enumerate(inorder)}
        return myBuildTree(0,n-1,0,n-1)
106. 从中序与后序遍历序列构造二叉树
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        def helper(in_left, in_right):
            if in_left > in_right:
                return None
            val = postorder.pop()
            root = TreeNode(val)
            index = idx_map[val]

            root.right = helper(index + 1, in_right)
            root.left = helper(in_left, index  -1)
            return root
        
        idx_map = {val:idx for idx, val in enumerate(inorder)}
        return helper(0, len(inorder) -1)
112. 路径总和
# 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        if not root.left and not root.right:
            return sum == root.val
        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)

# 广度优先搜索
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        que_node = collections.deque([root])
        que_val = collections.deque([root.val])
        while que_node:
            now = que_node.popleft()
            temp = que_val.popleft()
            if not now.left and not now.right:
                if temp == sum:
                    return True
                continue
            if now.left:
                que_node.append(now.left)
                que_val.append(now.left.val + temp)
            if now.right:
                que_node.append(now.right)
                que_val.append(now.right.val + temp)
        return False

113. 路径总和 II
# 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根# 节点到叶子节点 路径总和等于给定目标和的路径。
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        ret = list()
        path = list()

        def dfs(root, targetSum):
            if not root:
                return

            path.append(root.val)
            targetSum -= root.val
            if not root.left and  not root.right and targetSum == 0:
                ret.append(path[:])

            dfs(root.left, targetSum)
            dfs(root.right, targetSum)
            path.pop()
        
        dfs(root, targetSum)
        return ret
124. 二叉树中的最大路径和
def maxPathSum(self, root: TreeNode) -> int:
        maxSum = float('-inf')

        def maxGain(node):
            nonlocal maxSum
            if not node:
                return 0

            leftGain = max(maxGain(node.left), 0)
            rightGain = max(maxGain(node.right), 0)

            priceNewpath = node.val + leftGain + rightGain

            maxSum = max(maxSum, priceNewpath)

            return node.val + max(leftGain, rightGain)
        
        maxGain(root)
        return maxSum
129. 求根节点到叶节点数字之和
 def sumNumbers(self, root: TreeNode) -> int:
        def dfs(root, prevTotal):
            if not root:
                return 0

            total = prevTotal * 10 + root.val
            if not root.left and not root.right:
                return total
            else:
                return dfs(root.left, total) + dfs(root.right, total)
        return dfs(root, 0)
114. 二叉树展开为链表
def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        cur = root
        while cur:
            if cur.left:
                pre = nxt = cur.left
                while pre.right:
                    pre = pre.right
                pre.right = cur.right
                cur.left = None
                cur.right = nxt
            cur = cur.right
116. 填充每个节点的下一个右侧节点指针
"""
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL

class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return root
        
        Q = collections.deque([root])
        while Q:
            size = len(Q)
            for i in range(size):
                node = Q.popleft()
                if i < size - 1:
                    node.next = Q[0]
                
                if node.left:
                    Q.append(node.left)
                if node.right:
                    Q.append(node.right)

        return root
117. 填充每个节点的下一个右侧节点指针 II
class Solution:
    def connect(self, root: 'Node') -> 'Node':
        queue = [root]
        if not root:
            return root
        while queue:
            tmp = []
            for idx, node in enumerate(queue):
                if idx + 1 != len(queue):
                    node.next = queue[idx + 1]
                if node.left:
                    tmp.append(node.left)
                if node.right:
                    tmp.append(node.right)
            queue = tmp
        return root
156. 上下翻转二叉树
'''
根据题目描述,树中任何节点的右子节点若存在一定有左子节点,因此思路是向左遍历树进行转化;
规律是:左子节点变父节点;父节点变右子节点;右子节点变父节点。
对于某节点root,修改root.left,root.right之前,需要将三者都存下来:
    root.left是下一轮递归的主节点;
    root是下一轮递归root的root.right;
    root.right是下一轮递归root的root.left。
返回parent。
'''
def upsideDownBinaryTree(self, root: TreeNode) -> TreeNode:
        parent = parent_right = None
        while root:
            root_left = root.left
            root.left = parent_right
            parent_right = root.right
            root.right = parent
            parent = root
            root = root_left
        return parent
173. 二叉搜索树迭代器
class BSTIterator:

    def __init__(self, root):
        self.stack = []
        while root:
            self.stack.append(root)
            root = root.left

    def next(self) -> int:
        cur = self.stack.pop()
        node = cur.right
        while node:
            self.stack.append(node)
            node = node.left
        return cur.val

    def hasNext(self) -> bool:
        return len(self.stack) > 0

链表

2. 两数相加
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        
        current = dummy = ListNode()
        carry, value = 0, 0
        while carry or l1 or l2:   
            value = carry
          
            if l1: l1, value = l1.next, l1.val + value
            if l2: l2, value = l2.next, l2.val + value
         
            carry, value = divmod(value, 10)
            current.next = ListNode(value)

            current = current.next
    
        return dummy.next
25. K 个一组翻转链表
def reverse(self, head, tail):
        prev = tail.next
        p = head
        while prev != tail:
            nex = p.next
            p.next, prev, p = prev, p, nex
        return tail, head

    def reverseKGroup(self, head, k):
        hair = ListNode(0)
        hair.next = head
        pre = hair

        while head:
            tail = pre
            for i in range(k):
                tail = tail.next
                if not tail:
                    return hair.next
            nex = tail.next
            head, tail = self.reverse(head, tail)
            pre.next, tail.next, pre, head = head, nex, tail, tail.next
        return hair.next
143. 重排链表
 # 方法一:线性表
 def reorderList(self, head: ListNode) -> None:
        if not head:
            return
        
        vec = list()
        node = head
        while node:
            vec.append(node)
            node = node.next
        
        i, j = 0, len(vec) - 1
        while i < j:
            vec[i].next = vec[j]
            i += 1
            if i == j:
                break
            vec[j].next = vec[i]
            j -= 1
        
        vec[i].next = None

# 方法二:寻找链表中点 + 链表逆序 + 合并链表

class Solution:
    def reorderList(self, head: ListNode) -> None:
        if not head:
            return
        
        mid = self.middleNode(head)
        l1 = head
        l2 = mid.next
        mid.next = None
        l2 = self.reverseList(l2)
        self.mergeList(l1, l2)
    
    def middleNode(self, head: ListNode) -> ListNode:
        slow = fast = head
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        return slow
    
    def reverseList(self, head: ListNode) -> ListNode:
        prev = None
        curr = head
        while curr:
            nextTemp = curr.next
            curr.next = prev
            prev = curr
            curr = nextTemp
        return prev

    def mergeList(self, l1: ListNode, l2: ListNode):
        while l1 and l2:
            l1_tmp = l1.next
            l2_tmp = l2.next

            l1.next = l2
            l1 = l1_tmp
203. 移除链表元素
# 递归
def removeElements(self, head: ListNode, val: int) -> ListNode:
        if head is None:
            return head
        
        # removeElement方法会返回下一个Node节点
        head.next = self.removeElements(head.next, val)
        if head.val == val:
            next_node = head.next 
        else:
            next_node = head
        return next_node

# 迭代
 def removeElements(self, head: ListNode, val: int) -> ListNode:
        dummy = ListNode()
        dummy.next = head
        p = dummy
        while p is not None:
            # 向前探一个节点检查是否等于val
            if p.next and p.next.val == val:
                # 跳过 p.next 节点
                p.next = p.next.next 
            else:
                p = p.next
        return dummy.next

19. 删除链表的倒数第 N 个结点
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head
        fast = head
        slow = dummy
        while n-1 >0 and fast:
            fast = fast.next
            n -= 1
        if n > 1:
            return []

        while fast and fast.next:
            slow = slow.next
            fast = fast.next
        
        slow.next = slow.next.next
        return dummy.next
206. 反转链表
# 递归
def reverseList(self, head):
		"""
		:type head: ListNode
		:rtype: ListNode
		"""
		# 递归终止条件是当前为空,或者下一个节点为空
		if(head==None or head.next==None):
			return head
		# 这里的cur就是最后一个节点
		cur = self.reverseList(head.next)
		# 这里请配合动画演示理解
		# 如果链表是 1->2->3->4->5,那么此时的cur就是5
		# 而head是4,head的下一个是5,下下一个是空
		# 所以head.next.next 就是5->4
		head.next.next = head
		# 防止链表循环,需要将head.next设置为空
		head.next = None
		# 每层递归函数都返回cur,也就是最后一个节点
		return cur

# 双指针迭代
class Solution(object):
	def reverseList(self, head):
		"""
		:type head: ListNode
		:rtype: ListNode
		"""
		# 申请两个节点,pre和 cur,pre指向None
		pre = None
		cur = head
		# 遍历链表,while循环里面的内容其实可以写成一行
		# 这里只做演示,就不搞那么骚气的写法了
		while cur:
			# 记录当前节点的下一个节点
			tmp = cur.next
			# 然后将当前节点指向pre
			cur.next = pre
			# pre和cur节点都前进一位
			pre = cur
			cur = tmp
		return pre	

92. 反转链表 II
# 返回 反转后的链表 
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        # 设置 dummyNode 是这一类问题的一般做法
        dummy_node = ListNode(-1)
        dummy_node.next = head
        pre = dummy_node
        for _ in range(left - 1):
            pre = pre.next

        cur = pre.next
        for _ in range(right - left):
            next = cur.next
            cur.next = next.next
            next.next = pre.next
            pre.next = next
        return dummy_node.next

147. 对链表进行插入排序
# 从前往后找插入点
def insertionSortList(self, head: ListNode) -> ListNode:
        if not head:
            return head
        
        dummyHead = ListNode(0)
        dummyHead.next = head
        lastSorted = head
        curr = head.next

        while curr:
            if lastSorted.val <= curr.val:
                lastSorted = lastSorted.next
            else:
                prev = dummyHead
                while prev.next.val <= curr.val:
                    prev = prev.next
                lastSorted.next = curr.next
                curr.next = prev.next
                prev.next = curr
            curr = lastSorted.next
        
        return dummyHead.next


23. 合并K个升序链表
def mergeKLists(self,lists):
        if not lists:
            return 
        n = len(lists)
        return self.merge(lists,0,n-1)
    def merge(self,lists,left,right):
        if left == right:
            return lists[left]
        mid = left + (right - left)//2
        l1 = self.merge(lists,left,mid)
        l2 = self.merge(lists,mid +1,right)
        return self.mergeTwoLists(l1,l2)
    def mergeTwoLists(self,l1,l2):
        if not l1:
            return l2
        if not l2:
            return l1
        if l1.val < l2.val:
            l1.next= self.mergeTwoLists(l1.next,l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1,l2.next)
            return l2
148. 排序链表
# 归并排序(递归法)
def sortList(self, head: ListNode) -> ListNode:
        if not head or not head.next: return head # termination.
        # cut the LinkedList at the mid index.
        slow, fast = head, head.next
        while fast and fast.next:
            fast, slow = fast.next.next, slow.next
        mid, slow.next = slow.next, None # save and cut.
        # recursive for cutting.
        left, right = self.sortList(head), self.sortList(mid)
        # merge `left` and `right` linked list and return it.
        h = res = ListNode(0)
        while left and right:
            if left.val < right.val: h.next, left = left, left.next
            else: h.next, right = right, right.next
            h = h.next
        h.next = left if left else right
        return res.next

# 归并排序(从底至顶直接合并)
 def sortList(self, head: ListNode) -> ListNode:
        h, length, intv = head, 0, 1
        while h: h, length = h.next, length + 1
        res = ListNode(0)
        res.next = head
        # merge the list in different intv.
        while intv < length:
            pre, h = res, res.next
            while h:
                # get the two merge head `h1`, `h2`
                h1, i = h, intv
                while i and h: h, i = h.next, i - 1
                if i: break # no need to merge because the `h2` is None.
                h2, i = h, intv
                while i and h: h, i = h.next, i - 1
                c1, c2 = intv, intv - i # the `c2`: length of `h2` can be small than the `intv`.
                # merge the `h1` and `h2`.
                while c1 and c2:
                    if h1.val < h2.val: pre.next, h1, c1 = h1, h1.next, c1 - 1
                    else: pre.next, h2, c2 = h2, h2.next, c2 - 1
                    pre = pre.next
                pre.next = h1 if c1 else h2
                while c1 > 0 or c2 > 0: pre, c1, c2 = pre.next, c1 - 1, c2 - 1
                pre.next = h 
            intv *= 2
        return res.next

86. 分隔链表
'''
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
'''
# 双链表合并
def partition(self, head, x):
        if not head:
            return head
        small = ListNode()
        sm = small
        large = ListNode()
        lg = large
        while head:
            if head.val < x:
                sm.next = head
                sm = sm.next
            else:
                lg.next = head
                lg = lg.next
            head = head.next
        lg.next = None
        sm.next = large.next
        return small.next
# 寻找第一个large链表头    
 def partition(self, head, x):
        tmp = ret = ListNode()
        li = head
        ins = None
        while li:
            if li.val < x:
                tmp.next = li
                tmp = tmp.next
                li = li.next
            else:
                ins = li
                break
        while li and li.next:
            if li.next.val < x:
                tmp.next = li.next
                tmp = li.next
                li.next = li.next.next
            else:
                li = li.next
        tmp.next = ins
        return ret.next

224. 基本计算器
def calculate(self, s: str) -> int:
        ops = [1]
        sign = 1

        ret = 0
        n = len(s)
        i = 0
        while i < n:
            if s[i] == ' ':
                i += 1
            elif s[i] == '+':
                sign = ops[-1]
                i += 1
            elif s[i] == '-':
                sign = -ops[-1]
                i+=1
            elif s[i] == '(':
                ops.append(sign)
                i +=1
            elif s[i] == ')':
                ops.pop()
                i += 1
            else:
                num = 0
                while i < n and s[i] .isdigit():
                    num = num * 10 + ord(s[i]) - ord('0')
                    i += 1
                ret += num * sign
        return ret
150. 逆波兰表达式求值
   def evalRPN(self, tokens: List[str]) -> int:
        op_to_binary_fn = {
            "+": add,
            "-": sub,
            "*": mul,
            "/": lambda x, y : int(x/y)
        }

        stack = list()
        for token in tokens:
            try:
                num = int(token)
            except ValueError:
                num2 = stack.pop()
                num1 = stack.pop()
                num = op_to_binary_fn[token](num1, num2)
            finally:
                stack.append(num)
            
        return stack[0]
20. 有效的括号
def isValid(self, s):
        stack = []
        paren_map = {')': '(', ']': '[', '}': '{'}
        for c in s:
            if c not in paren_map:
                stack.append(c)
                
            elif not stack or paren_map[c] !=stack.pop():
                return False
        return not stack
71. 简化路径
def simplifyPath(self, path):
        stack = []
        for p in path.split('/'):
            if p not in ['.', '..', '']:
                stack.append(p)
            elif p == '..' and stack:
                stack.pop()
        return f"/{'/'.join(stack)}"

数组

27. 移除元素
 def removeElement(self, nums: List[int], val: int) -> int:
        i = 0
        for num in nums:
            if num != val:
                nums[i] = num
                i += 1
            else:
                continue
        return i
48. 旋转图像
def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
       
        matrix[:] = [list(t)[::-1] for t in zip(*matrix)]
54. 螺旋矩阵
# 方法一:模拟
 def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        visited = [[False] * columns for _ in range(rows)]
        total = rows * columns
        order = [0] * total

        directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
        row, column = 0, 0
        directionIndex = 0
        for i in range(total):
            order[i] = matrix[row][column]
            visited[row][column] = True
            nextRow, nextColumn = row + directions[directionIndex][0], column + directions[directionIndex][1]
            if not (0 <= nextRow < rows and 0 <= nextColumn < columns and not visited[nextRow][nextColumn]):
                directionIndex = (directionIndex + 1) % 4
            row += directions[directionIndex][0]
            column += directions[directionIndex][1]
        return order

# 方法二:按层模拟
 def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

59. 螺旋矩阵 II
def generateMatrix(self, n: int) -> List[List[int]]:
        l, r, t, b = 0, n - 1, 0, n - 1
        mat = [[0 for _ in range(n)] for _ in range(n)]
        num, tar  = 1, n * n
        while num <= tar:
            for i in range(l, r + 1):
                mat[t][i] = num
                num +=1
            t += 1

            for i in range(t,b + 1):
                mat[i][r] = num
                num += 1
            r -= 1
            for i in range(r, l-1, -1):
                mat[b][i] = num
                num += 1
            b -= 1

            for i in range(b, t -1, -1):
                mat[i][l] = num
                num += 1
            l +=1
        return mat
56. 合并区间
 def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key=lambda x: x[0])

        merged = []
        for interval in intervals:
            # 如果列表为空,或者当前区间与上一区间不重合,直接添加
            if not merged or merged[-1][1] < interval[0]:
                merged.append(interval)
            else:
                # 否则的话,我们就可以与上一区间进行合并
                merged[-1][1] = max(merged[-1][1], interval[1])

        return merged

57. 插入区间
def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        left, right = newInterval
        placed = False
        ans = list()
        for li, ri in intervals:
            if li > right:
                # 在插入区间的右侧且无交集
                if not placed:
                    ans.append([left, right])
                    placed = True
                ans.append([li, ri])
            elif ri < left:
                # 在插入区间的左侧且无交集
                ans.append([li, ri])
            else:
                # 与插入区间有交集,计算它们的并集
                left = min(left, li)
                right = max(right, ri)
        
        if not placed:
            ans.append([left, right])
        return ans

73. 矩阵置零
# 方法一:使用标记数组
 def setZeroes(self, matrix: List[List[int]]) -> None:
        m, n = len(matrix), len(matrix[0])
        row, col = [False] * m, [False] * n

        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    row[i] = col[j] = True
        
        for i in range(m):
            for j in range(n):
                if row[i] or col[j]:
                    matrix[i][j] = 0
                    
# 方法二:使用两个标记变量
  def setZeroes(self, matrix: List[List[int]]) -> None:
        m, n = len(matrix), len(matrix[0])
        flag_col0 = any(matrix[i][0] == 0 for i in range(m))
        flag_row0 = any(matrix[0][j] == 0 for j in range(n))
        
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
        
        if flag_col0:
            for i in range(m):
                matrix[i][0] = 0
        
        if flag_row0:
            for j in range(n):
                matrix[0][j] = 0
      
# 方法三:使用一个标记变量
def setZeroes(self, matrix: List[List[int]]) -> None:
        m, n = len(matrix), len(matrix[0])
        flag_col0 = False
        
        for i in range(m):
            if matrix[i][0] == 0:
                flag_col0 = True
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        
        for i in range(m - 1, -1, -1):
            for j in range(1, n):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
            if flag_col0:
                matrix[i][0] = 0

88. 合并两个有序数组
方法一:直接合并后排序
  def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        nums1[m:] = nums2
        nums1.sort()

# 方法二:双指针
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        sorted = []
        p1, p2 = 0, 0
        while p1 < m or p2 < n:
            if p1 == m:
                sorted.append(nums2[p2])
                p2 += 1
            elif p2 == n:
                sorted.append(nums1[p1])
                p1 += 1
            elif nums1[p1] < nums2[p2]:
                sorted.append(nums1[p1])
                p1 += 1
            else:
                sorted.append(nums2[p2])
                p2 += 1
        nums1[:] = sorted
# 方法三:逆向双指针
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        p1, p2 = m - 1, n - 1
        tail = m + n - 1
        while p1 >= 0 or p2 >= 0:
            if p1 == -1:
                nums1[tail] = nums2[p2]
                p2 -= 1
            elif p2 == -1:
                nums1[tail] = nums1[p1]
                p1 -= 1
            elif nums1[p1] > nums2[p2]:
                nums1[tail] = nums1[p1]
                p1 -= 1
            else:
                nums1[tail] = nums2[p2]
                p2 -= 1
            tail -= 1

189. 旋转数组
# 三次反转
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        k=k%n
        def swap(l,r):
            while(l<r):
                nums[l],nums[r]=nums[r],nums[l]
                l=l+1
                r=r-1
        swap(0,n-k-1)
        swap(n-k,n-1)
        swap(0,n-1)

链接:https://leetcode-cn.com/problems/rotate-array/solution/san-ci-fan-zhuan-fu-yi-xie-pythonicde-jie-fa-pytho/

# 切片
def rotate(self, nums: List[int], k: int) -> None:
        n=len(nums)
        k%=n
        nums[:]=nums[n-k:]+nums[:n-k]

# 插入
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        for _ in range(k):
            nums.insert(0, nums.pop())



89. 格雷编码
 def grayCode(self, n: int) -> List[int]:
        res, head = [0], 1
        for i in range(n):
            for j in range(len(res) - 1, -1, -1):
                res.append(head + res[j])
            head <<= 1
        return res

字符串

6. Z 字形变换
 def convert(self, s: str, numRows: int) -> str:
        if numRows == 1: return s
        rows = [""] * numRows
        n = 2 * numRows - 2
        for i, char in enumerate(s):
            x = i % n
            rows[min(x, n - x)] += char
        return "".join(rows)
8. 字符串转换整数 (atoi)
def myAtoi(self, s: str) -> int:
        return max(min(int (* re.findall('^[\+\-]?\d+', s.lstrip())), 2 ** 31 - 1), -2 ** 31)
12. 整数转罗马数字
class Solution:
    VALUE_SYMBOLS = [(1000, "M"),
        (900, "CM"),(500, "D"),(400, "CD"),(100, "C"),
        (90, "XC"),(50, "L"),(40, "XL"),(10, "X"),
        (9, "IX"),(5, "V"),(4, "IV"),(1, "I")]

    def intToRoman(self, num: int) -> str:
        roman = list()
        for value, symbol in Solution.VALUE_SYMBOLS:
            while num >= value:
                num -= value
                roman.append(symbol)
            if num == 0:
                break
        return ''.join(roman)
13. 罗马数字转整数
class Solution:
    SYMBOL_VALUES = {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
    }

    def romanToInt(self, s: str) -> int:
        ans = 0
        n = len(s)
        for i, ch in enumerate(s):
            value = Solution.SYMBOL_VALUES[ch]
            if i < n -1 and value < Solution.SYMBOL_VALUES[s[i+1]]:
                ans -= value
            else:
                ans += value
        return ans
28. 实现 strStr()
# KMP
def strStr(self, haystack: str, needle: str) -> int:
        i = 0
        j = 0
        nxt = self.get_next(needle)
        while i < len(haystack) and j < len(needle):
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            elif j != 0:
                j = nxt[j-1]
            else:
                i += 1
        if j == len(needle):
            return i - j
        else:
            return -1
    
    def get_next(self, substr):
        i = 1
        j = 0
        nxt = [0] * len(substr)
        while i < len(substr):
            if substr[i] == substr[j]:
                nxt[i] = j + 1
                i += 1
                j += 1
            elif j != 0:
                j = nxt[j-1]
            else:
                nxt[i] = 0
                i += 1
        return nxt

# 直接搜索
def strStr(self, haystack: str, needle: str) -> int:
        for i in range(len(haystack) - len(needle) + 1):
            if needle == haystack[i:i+len(needle)]:
                return i
        return -1

    
    
58. 最后一个单词的长度
def lengthOfLastWord(self, s: str) -> int:
        x = s.split(' ')
        for i in x[::-1]:
            if i != '':
                return len(i)
        return 0
65. 有效数字
1626914918445
  def isNumber(self, s: str) -> bool:
        # DFA transitions: dict[action] -> successor
        states = [{},
                  # state 1
                  {"blank":1,"sign":2,"digit":3,"dot":4},
                  # state 2
                  {"digit":3,"dot":4},
                  # state 3
                  {"digit":3,"dot":5,"e|E":6,"blank":9},
                  # state 4
                  {"digit":5},
                  # state 5
                  {"digit":5,"e|E":6,"blank":9},
                  # state 6
                  {"sign":7,"digit":8},
                  # state 7
                  {"digit":8},
                  # state 8
                  {"digit":8,"blank":9},
                  # state 9
                  {"blank":9}]

        def strToAction(st):
            if '0' <= st <= '9':
                return "digit"
            if st in "+-":
                return "sign"
            if st in "eE":
                return "e|E"
            if st == '.':
                return "dot"
            if st == ' ':
                return "blank"
            return None

        currState = 1
        for c in s:
            action = strToAction(c)
            if action not in states[currState]:
                return False
            currState = states[currState][action]

        # ending states: 3,5,8,9
        return currState in {3,5,8,9}

# pattern("[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[Ee][+-]?\\d+)?")
68. 文本左右对齐
 def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
        res = []
        n = len(words)
        i = 0

        def one_row_words(i):
            # 至少 一行能放下一个单词, cur_row_len
            left = i
            cur_row_len = len(words[i])
            i += 1
            while i < n:
                # 当目前行 加上一个单词长度 再加一个空格
                if cur_row_len + len(words[i]) + 1 > maxWidth:
                    break
                cur_row_len += len(words[i]) + 1
                i += 1
            return left, i

        while i < n:
            left, i = one_row_words(i)
            # 该行几个单词获取
            one_row = words[left:i]
            # 如果是最后一行了
            if i == n :
                res.append(" ".join(one_row).ljust(maxWidth," "))
                break
            # 所有单词的长度
            all_word_len = sum(len(i) for i in one_row)
            # 至少空格个数
            space_num = i - left - 1
            # 可以为空格的位置
            remain_space = maxWidth - all_word_len
            # 单词之间至少几个空格,还剩几个空格没用
            if space_num:
                a, b = divmod(remain_space, space_num)
            # print(a,b)
            # 该行字符串拼接
            tmp = ""
            for word in one_row:
                if tmp:
                    tmp += " " * a
                    if b:
                        tmp += " "
                        b -= 1
                tmp += word
            #print(tmp, len(tmp))
            res.append(tmp.ljust(maxWidth, " "))
        return res

125. 验证回文串
 def isPalindrome(self, s: str) -> bool:
        sgood = "".join(ch.lower() for ch in s if ch.isalnum())
        return sgood == sgood[::-1]

 def isPalindrome(self, s: str) -> bool:
        sgood = "".join(ch.lower() for ch in s if ch.isalnum())
        n = len(sgood)
        left, right = 0, n - 1
        
        while left < right:
            if sgood[left] != sgood[right]:
                return False
            left, right = left + 1, right - 1
        return True


151. 翻转字符串里的单词
def reverseWords(self, s: str) -> str:
        return ' '.join(reversed(s.split()))
157. 用 Read4 读取 N 个字符
def read(self, buf, n):
        """
        :type buf: Destination buffer (List[str])
        :type n: Number of characters to read (int)
        :rtype: The number of actual characters read (int)
        """
        bi = 0
        for _ in range(0, n,4):
            temp = [None] * 4
            cur_len = read4(temp)
            for j in range(cur_len):
                buf[bi] = temp[j] 
                bi += 1
        return min(bi, n)
158. 用 Read4 读取 N 个字符 II
class Solution:
   
    def __init__(self):
        self.buf = []
    
    def read(self,buf,n):
        buf_len = len(self.buf)

        if len(self.buf) >= n:
            buf[:n] = self.buf[:n]
            self.buf = self.buf[n:]
            return n
        
        cur = buf_len
        while cur < n:
            cache =[''] * 4
            num = read4(cache)
            self.buf +=cache[:num]
            cur +=num
            if num < 4 or n <= 4:
                break

        res = min(cur, n)
        buf[:res] = self.buf[:res]
        self.buf = self.buf[res:]
        return res

dict & set

41. 缺失的第一个正数
# 方法一:哈希表
 def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            if nums[i] <= 0:
                nums[i] = n + 1
        
        for i in range(n):
            num = abs(nums[i])
            if num <= n:
                nums[num - 1] = -abs(nums[num - 1])
        
        for i in range(n):
            if nums[i] > 0:
                return i + 1
        
        return n + 1

# 方法二:置换
def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
                nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
        for i in range(n):
            if nums[i] != i + 1:
                return i + 1
        return n + 1
128. 最长连续序列
# 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元
# 素在原数组中连续)的长度。nums = [100,4,200,1,3,2], out: 4
# 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

def longestConsecutive(self, nums: List[int]) -> int:    
        ret = 0
        num_set = set(nums)
        for num in num_set:    # 此处要遍历的是num_set而不是num,否则会考虑很多重复情况
            if num - 1 not in num_set:
                cur_num = num
                cur_len = 1
                while cur_num + 1 in num_set:
                    cur_len += 1
                    cur_num += 1
                ret = max(ret, cur_len)
        return ret


# 并查集
import collections
class DSU:
    def __init__(self, nums):
        self.parent = {num: num for num in nums}
        self.cnt = collections.defaultdict(lambda: 1)
        #print(self.pre,self.cnt)

    def find(self, x):
        while x != self.parent[x]:
            x = self.parent[x]
        return x

    def union(self, x, y):
        if y not in self.parent:
            return 1
        # 寻找x, y的根节点,记为root1, root2
        root1, root2 = self.find(x), self.find(y)

        # 如果root1 == root2,直接返回self.cnt[root1]或者self.cnt[root2]
        # 表示当前的数与之前已经出现的一些数字能构成连续序列
        if root1 == root2:
            return self.cnt[root1]
        
        # 将root2的根节点改为root1,如下面步骤5中的图所示,将两棵子树合并
        self.parent[root2]=root1
        # 如下面步骤5中的图所示,两棵子树合并时,现在的树的元素个数就是这两棵树之和
        self.cnt[root1] += self.cnt[root2]
        return self.cnt[root1]

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        if len(nums)==0:return 0
        dsu = DSU(nums)
        res = 1
        for num in nums:
            #print(num)
            res = max(res, dsu.union(num, num + 1))
            #print(dsu.pre,dsu.cnt,res)
        return res
169. 多数元素
# 方法一:哈希表
def majorityElement(self, nums: List[int]) -> int:
        counts = collections.Counter(nums)
        return max(counts.keys(), key=counts.get)
        
# 方法二:排序
def majorityElement(self, nums: List[int]) -> int:
        nums.sort()
        return nums[len(nums) // 2]
        
# 方法三:随机化
 def majorityElement(self, nums: List[int]) -> int:
        majority_count = len(nums) // 2
        while True:
            candidate = random.choice(nums)
            if sum(1 for elem in nums if elem == candidate) > majority_count:
                return candidate
# 方法四:分治
 def majorityElement(self, nums: List[int]) -> int:
        def majority_element_rec(lo, hi) -> int:
            # base case; the only element in an array of size 1 is the majority
            # element.
            if lo == hi:
                return nums[lo]

            # recurse on left and right halves of this slice.
            mid = (hi - lo) // 2 + lo
            left = majority_element_rec(lo, mid)
            right = majority_element_rec(mid + 1, hi)

            # if the two halves agree on the majority element, return it.
            if left == right:
                return left

            # otherwise, count each element and return the "winner".
            left_count = sum(1 for i in range(lo, hi + 1) if nums[i] == left)
            right_count = sum(1 for i in range(lo, hi + 1) if nums[i] == right)

            return left if left_count > right_count else right

        return majority_element_rec(0, len(nums) - 1)

# 方法五:Boyer-Moore 投票算法
def majorityElement(self, nums: List[int]) -> int:
        count = 0
        candidate = None

        for num in nums:
            if count == 0:
                candidate = num
            count += (1 if num == candidate else -1)

        return candidate

170. 两数之和 III - 数据结构设计
class TwoSum(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.num_counts = {}


    def add(self, number):
        """
        Add the number to an internal data structure..
        :type number: int
        :rtype: None
        """
        if number in self.num_counts:
            self.num_counts[number] += 1
        else:
            self.num_counts[number] = 1

    def find(self, value):
        """
        Find if there exists any pair of numbers which sum is equal to the value.
        :type value: int
        :rtype: bool
        """
        for num in self.num_counts.keys():
            comple = value - num
            if num != comple:
                if comple in self.num_counts:
                    return True
            elif self.num_counts[num] > 1:
                return True
        
        return False

49. 字母异位词分组
# 方法一:排序
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        mp = collections.defaultdict(list)

        for st in strs:
            key = "".join(sorted(st))
            mp[key].append(st)
        
        return list(mp.values())
    
# 方法二:计数
 def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        mp = collections.defaultdict(list)

        for st in strs:
            counts = [0] * 26
            for ch in st:
                counts[ord(ch) - ord("a")] += 1
            # 需要将 list 转换成 tuple 才能进行哈希
            mp[tuple(counts)].append(st)
        
        return list(mp.values())

166. 分数到小数
def fractionToDecimal(self, numerator, denominator):
        if numerator == 0:
            return "0"
        res = []
        if (numerator < 0) ^ (denominator < 0): #正负号判断,异或
            res.append("-")

        numer = abs(numerator)      #取整
        denomin = abs(denominator)

        a, remaind = divmod(numer, denomin)
        res.append(str(a))
        if remaind == 0:            #整除,直接返回
            return "".join(res)

        res.append(".")             #添加小数点
        dic = {}
        while remaind != 0:
            if remaind in dic:      #如果有循环,添加括号
                res.insert(dic[remaind], "(")
                res.append(")")
                break
            
            dic[remaind] = len(res) #记录括号的位置
            remaind *= 10           #余数加0,继续除法
            a, remaind = divmod(remaind, denomin)
            res.append(str(a))

        return "".join(res)

168. Excel表列名称
def convertToTitle(self, columnNumber: int) -> str:
        ans = []
        while columnNumber > 0:
            columnNumber -=1
            ans.append(chr(columnNumber %26 + ord('A')))
            columnNumber //=26
        return ''.join(ans[::-1])
171. Excel表列序号
 def titleToNumber(self, columnTitle: str) -> int:
        number, multiple = 0, 1

        for i in range(len(columnTitle) -1, -1, -1):
            k = ord(columnTitle[i]) - ord("A") + 1
            number += k * multiple
            multiple *= 26
        return number
187. 重复的DNA序列
def findRepeatedDnaSequences(self, s: str) -> List[str]:
        L, n = 10, len(s)     
        seen, output = set(), set()

        # iterate over all sequences of length L
        for start in range(n - L + 1):
            tmp = s[start:start + L]
            if tmp in seen:
                output.add(tmp[:])
            seen.add(tmp)
        return output

141. 环形链表
 def hasCycle(self,head):
        fast = slow= head
        while slow and fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow is fast:
                return True
        return False
    
def hasCycle(self,head:ListNode)-> bool:
        seen = set()
        while head:
            if head in seen:
                return True
            seen.add(head)
            head = head.next
        return False
142. 环形链表 II
 def detectCycle(self,head):
            fast = slow= head
            while slow and fast and fast.next:
                slow = slow.next
                fast = fast.next.next
                if slow is fast:
                    ptr = head
                    while ptr is not slow:
                        ptr,slow= ptr.next, slow.next
                    return ptr
            return None
            
def detectCycle(self, head: ListNode) -> bool:
            seen = set()
            while head:
                if head in seen:
                    return head
                seen.add(head)
                head = head.next
            return None
146. LRU 缓存机制
'''
实现 LRUCache 类:
LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
'''
class LRUCache:
    def __init__(self, capacity):
        self.cache = dict()
        self.head = DLinkedNode()
        self.tail = DLinkedNode()
        self.head.next = self.tail
        self.tail.prev = self.head
        self.capacity = capacity
        self.size = 0

    def get(self, key):
        if key not in self.cache:
            return -1
        node = self.cache[key]
        self.moveToHead(node)
        return node.value

    def put(self, key, value):
        if key not in self.cache:
            node = DLinkedNode(key, value)
            self.cache[key] = node
            self.addToHead(node)
            self.size += 1
            if self.size > self.capacity:
                removed = self.removeTail()
                self.cache.pop(removed.key)
                self.size -= 1
        else:
            node = self.cache[key]
            node.value = value
            self.moveToHead(node)

    def addToHead(self, node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node

    def moveToHead(self, node):
        self.removeNode(node)
        self.addToHead(node)

    def removeTail(self):
        node = self.tail.prev
        self.removeNode(node)
        return node

    def removeNode(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev

208. 实现 Trie (前缀树)
'''
请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
'''
class Trie:
    def __init__(self):
        self.children = [None] * 26
        self.isEnd = False

    def searchPrefix(self, prefix):
        node = self
        for ch in prefix:
            ch = ord(ch)- ord('a')
            if not node.children[ch]:
                return None
            node = node.children[ch]
        return node

    def insert(self,word):
        node = self
        for ch in word:
            ch = ord(ch) - ord('a')
            if not node.children[ch]:
                node.children[ch] = Trie()
            node = node.children[ch]
        node.isEnd = True

    def search(self,word):
        node =self.searchPrefix(word)
        return node is not None and node.isEnd
149. 直线上最多的点数
def maxPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        ans = 1
        for i in range(n):
            k_dict = collections.defaultdict(int)
            max_count = 0
            for j in range(i + 1, n):
                x1 = points[i][0]
                y1 = points[i][1]
                x2 = points[j][0]
                y2 = points[j][1]
                a = x1 - x2
                b = y1 - y2
                k = self.gcd(a, b)
                key = str(a // k) + '_' + str(b //k)
                
                k_dict[key] += 1
                max_count = max(max_count, k_dict[key])

            ans = max(ans, max_count + 1)
        return ans

    def gcd(self, a, b):
        return a if b == 0 else self.gcd(b, a % b)
160. 相交链表
 def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        s = set()
        p, q = headA, headB
        while p:
            s.add(p)
            p = p.next
        while q:
            if q in s:
                return q
            q = q.next
        return None
    
# 双指针
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        A, B = headA, headB
        while A != B:
            A = A.next if A else headB
            B = B.next if B else headA
        return A


位运算

67. 二进制求和
def addBinary(self, a, b) -> str:
        x, y = int(a, 2), int(b, 2)
        while y:
            answer = x ^ y
            carry = (x & y) << 1
            x, y = answer, carry
        return bin(x)[2:]
def addBinary(self, a, b) -> str:
    return '{0:b}'.format(int(a, 2) + int(b, 2))

线性扫描

135. 分发糖果
def candy(self, ratings: List[int]) -> int:
        n = len(ratings)
        left = [0] * n
        for i in range(n):
            if i > 0 and ratings[i] > ratings[i -1]:
                left[i] = left[i -1] + 1
            else:
                left[i] =1 
        
        right = ret = 0
        for i in range(n -1, -1, -1):
            if i < n-1 and ratings[i] > ratings[i + 1]:
                right +=1
            else:
                right = 1
            ret += max(left[i],right)
            
        return ret
163. 缺失的区间
def findMissingRanges(self, nums: List[int], lower: int, upper: int) -> List[str]:
        res = []

        low = lower -1
        nums.append(upper +1)
        for num in nums:
            dif = num -low 
            if dif ==  2: res.append(str(low +1))
            elif dif >2: 
                res.append(str(low+1) + '->' + str(num -1))
            low = num
        return res
14. 最长公共前缀
def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:
            return ""
        
        prefix, count = strs[0], len(strs)
        for i in range(1, count):
            prefix = self.lcp(prefix, strs[i])
            if not prefix:
                break
        
        return prefix

    def lcp(self, str1, str2):
        length, index = min(len(str1), len(str2)), 0
        while index < length and str1[index] == str2[index]:
            index += 1
        return str1[:index]
32. 最长有效括号
def longestValidParentheses(self, s: str) -> int:
        left, right, res= 0, 0, 0
        
        def one_direction(s,left, right, lp):
            nonlocal res
            for i, ch in enumerate(s):
                if ch == lp:
                    left += 1
                else:
                    right += 1
                if left == right:
                    res = max(res, 2 * right)
                elif right > left:
                    left = right = 0

        one_direction(s, left, right, '(')
        one_direction(s[::-1],left,right,')')
        return res

排序

164. 最大间距
  def maximumGap(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2: return 0
        max_num = max(nums)
        min_num = min(nums)
        gap = math.ceil((max_num - min_num)/(n - 1))
        bucket = [[float("inf"), float("-inf")] for _ in range(n - 1)]
        #print(bucket)
        # 求出每个桶的最大值,和最小值
        for num in nums:
            if num == max_num or num == min_num:
                continue
            loc = (num - min_num) // gap
            bucket[loc][0] = min(num, bucket[loc][0])
            bucket[loc][1] = max(num, bucket[loc][1])
        ##print(bucket)
        # 遍历整个桶
        preMin = min_num
        res = float("-inf")
        for x, y in bucket:
            if x == float("inf") :
                continue
            res = max(res, x - preMin)
            preMin = y
        res = max(res, max_num - preMin)
        return res



def maximumGap(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2: return 0
        res = 0
        nums.sort()
        for i in range(1, n):
            res = max(res, nums[i] - nums[i - 1])
        return res


215. 数组中的第K个最大元素
# 基于快排的所有TopK问题简单python模板
def partition(nums, left, right):
    pivot = nums[left]#初始化一个待比较数据
    i,j = left, right
    while(i < j):
        while(i<j and nums[j]>=pivot): #从后往前查找,直到找到一个比pivot更小的数
            j-=1
        nums[i] = nums[j] #将更小的数放入左边
        while(i<j and nums[i]<=pivot): #从前往后找,直到找到一个比pivot更大的数
            i+=1
        nums[j] = nums[i] #将更大的数放入右边
    #循环结束,i与j相等
    nums[i] = pivot #待比较数据放入最终位置 
    return i #返回待比较数据最终位置

# 快速排序
def quicksort(nums, left, right):
    if left < right:
        index = partition(nums, left, right)
        quicksort(nums, left, index-1)
        quicksort(nums, index+1, right)

arr = [1,3,2,2,0]
quicksort(arr, 0, len(arr)-1)
print(arr) 
# topk切分
def topk_split(nums, k, left, right):
    #寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数
    if (left<right):
        index = partition(nums, left, right)
        if index==k:
            return 
        elif index < k:
            topk_split(nums, k, index+1, right)
        else:
            topk_split(nums, k, left, index-1)

# 获得前k小的数
def topk_smalls(nums, k):
    topk_split(nums, k, 0, len(nums)-1)
    return nums[:k]

# 获取第k小的数
def topk_small(nums, k):
    topk_split(nums, k, 0, len(nums)-1)
    return nums[k-1] #右边是开区间,需要-1

# 获得前k大的数
def topk_larges(nums, k):
    #parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数
    topk_split(nums, len(nums)-k, 0, len(nums)-1) #把k换成len(nums)-k
    return nums[len(nums)-k:] 

# 获得第k大的数
def topk_large(nums, k):
    #parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数
    topk_split(nums, len(nums)-k, 0, len(nums)-1) #把k换成len(nums)-k
    return nums[len(nums)-k] 

# 只排序前k个小的数
#获得前k小的数O(n),进行快排O(klogk)
def topk_sort_left(nums, k):
    topk_split(nums, k, 0, len(nums)-1) 
    topk = nums[:k]
    quicksort(topk, 0, len(topk)-1)
    return topk+nums[k:] #只排序前k个数字

# 只排序后k个大的数
#获得前n-k小的数O(n),进行快排O(klogk)
def topk_sort_right(nums, k):
    topk_split(nums, len(nums)-k, 0, len(nums)-1) 
    topk = nums[len(nums)-k:]
    quicksort(topk, 0, len(topk)-1)
    return nums[:len(nums)-k]+topk #只排序后k个数字

179. 最大数
 def largestNumber(self, nums: List[int]) -> str:
        from functools import cmp_to_key
        key = cmp_to_key(lambda x,y :int(y+x) -int(x+y))
        res = ''.join(sorted(map(str,nums),key=key)).lstrip('0')
        return res or '0'
253. 会议室 II
'''
给你一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,为避免会议冲突,同时要考虑充分利用会议室资源,请你计算至少需要多少间会议室,才能满足这些会议安排。
'''
def minMeetingRooms(self, intervals: List[List[int]]) -> int:
        intervals.sort()
        heap = [(intervals[0][1], intervals[0][0])]
        res = 1
        for i in range(1, len(intervals)):
            x, y = intervals[i]
            if x<heap[0][0]:
                if len(heap)>=res:
                    res+=1
            while heap and x>=heap[0][0]:
                heapq.heappop(heap)
            heapq.heappush(heap, (y, x))
            
        return res

数学

50. Pow(x, n)
def myPow(self, x: float, n: int) -> float:
       
        if n < 0:
            x = 1/x
            n = -n
        pow_val = 1
        while n:
            if n & 1:
                pow_val *= x
            x *= x
            n >>=1
        return pow_val
60. 排列序列
def getPermutation(self, n: int, k: int) -> str:
        factorial = [1]
        for i in range(1, n):
            factorial.append(factorial[-1] * i)

        k -= 1
        ans = list()
        valid = [1] * (n + 1)
        for i in range(1, n + 1):
            order = k // factorial[n - i] + 1
            for j in range(1, n + 1):
                order -= valid[j]
                if order == 0:
                    ans.append(str(j))
                    valid[j] = 0
                    break
            k %= factorial[n - i]
        return ''.join(ans)
31. 下一个排列
def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        if len(nums) == 1:
            return nums
        n = len(nums)
        left = -1
        right = left + 1
        for i in range(1, n):
            if nums[i] >= nums[i-1]:
                left = i
                if nums[i] < nums[right]:
                    right = i
                
        print(left)
        if left == -1:
            for i in range(0, n//2):
                nums[i],nums[n -i-1] = nums[n -i-1], nums[i]
        else:
            nums[left -1],nums[left] = nums[left], nums[left-1]
233. 数字 1 的个数
 def countDigitOne(self, n):
        """
        :type n: int
        :rtype: int
        """        
        if n < 1:
            return 0
        if n < 10:
            return 1
        
        # t需要能被10整除
        def countPart(t):      
            if t == 10:
                return 1            
            s = t/10
            return 10 * countPart(t/10) + s
        ans = 0        
        # 判断n是几位数,如n=388,l就是100
        y = 10
        while y <= n:
            y *= 10
        l = y / 10
        subn = n % l
        ans += self.countDigitOne(subn)
        c = n / l        
        ans += c * countPart(l) + (l if c != 1 else subn+1) # 这里要注意下以1开头的情况
        return ans

数位dp
ll dfs(int pos,int state,...,bool lead,bool limit){
    if(!pos) return ...; //返回填完的数是否满足条件
    //当前状态已经搜索过,直接使用dp值
    if(dp[pos][state]...!=-1&&!limit&&!lead) return dp[pos][state]...;
    ll ret=0; //暂时记录当前方案数
    int bound=limit?a[pos]:9; //当前位能取到的最大值
    for(int i=0;i<=bound;i++){
        //有前导0并且当前位也是前导0
        if(!i&&lead) ret+=dfs(pos-1,...,1,i==bound&&limit);
        //有前导0但当前位不是前导0,当前位就是最高位
        else if(i&&lead) ret+=dfs(pos-1,...,0,i==bound&&limit); 
        else if(...) ...;
    }
    if(!limit&&!lead) dp[pos][state]...=ret; //当前状态方案数记录
    return ret;
}
ll solve(ll x){
    len=0; //数位长度
    while(x) a[++len]=x%10,x/=10;
    memset(dp,-1,sizeof(dp)); //初始化-1(因为方案数可能为0)
    return dfs(len,...,1,1);
}

66. 加一
def plusOne(self, digits: List[int]) -> List[int]:
        num = int(''.join(list(map(str,digits)))) + 1
        return list(map(int,list(str(num))))

def plusOne(self, digits: List[int]) -> List[int]:
        n = len(digits)-1
        num = 0 
        for i in digits:
            if n == -1:
                break
            num += i*(10**n)
            n -= 1
        m = num + 1
        final = list(str(m))
        return list(map(int,final))

118. 杨辉三角
def generate(self, numRows: int) -> List[List[int]]:
        ret = list()
        for i in range(numRows):
            row = list()
            for j in range(0, i + 1):
                if j == 0 or j == i:
                    row.append(1)
                else:
                    row.append(ret[i - 1][j] + ret[i - 1][j - 1])
            ret.append(row)
        return ret

119. 杨辉三角 II
# 返回杨辉三角的第k行
def getRow(self, rowIndex: int) -> List[int]:
        res = [1] * (rowIndex + 1)
        for i in range(1, rowIndex + 1):
            res[i] = res[i - 1] * (rowIndex - i + 1) // i
        return res
136. 只出现一次的数字
# 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

def singleNumber(self, nums: List[int]) -> int:
        return reduce(lambda x, y: x ^ y, nums)
137. 只出现一次的数字 II
# 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出# 现三次 。请你找出并返回那个只出现了一次的元素。
def singleNumber(self, nums: List[int]) -> int:
        dic = dict(collections.Counter(nums))
        for k,v in dic.items():
            if v == 1:
                return k
204. 计数质数
def countPrimes(self, n: int) -> int:
        d = [True] * n
        count = 0
        for i in range(2, n):
            if d[i]:
                count += 1
                for j in range(i * i, n,i):
                    d[j] = False
        return count
43. 字符串相乘
# 方法一:做加法
def multiply(self, num1: str, num2: str) -> str:
        if num1 == "0" or num2 == "0":
            return "0"
        
        ans = "0"
        m, n = len(num1), len(num2)
        for i in range(n - 1, -1, -1):
            add = 0
            y = int(num2[i])
            curr = ["0"] * (n - i - 1)
            for j in range(m - 1, -1, -1):
                product = int(num1[j]) * y + add
                curr.append(str(product % 10))
                add = product // 10
            if add > 0:
                curr.append(str(add))
            curr = "".join(curr[::-1])
            ans = self.addStrings(ans, curr)
        
        return ans
    
    def addStrings(self, num1: str, num2: str) -> str:
        i, j = len(num1) - 1, len(num2) - 1
        add = 0
        ans = list()
        while i >= 0 or j >= 0 or add != 0:
            x = int(num1[i]) if i >= 0 else 0
            y = int(num2[j]) if j >= 0 else 0
            result = x + y + add
            ans.append(str(result % 10))
            add = result // 10
            i -= 1
            j -= 1
        return "".join(ans[::-1])

# 方法二:做乘法
def multiply(self, num1: str, num2: str) -> str:
        if num1 == "0" or num2 == "0":
            return "0"
        
        m, n = len(num1), len(num2)
        ansArr = [0] * (m + n)
        for i in range(m - 1, -1, -1):
            x = int(num1[i])
            for j in range(n - 1, -1, -1):
                ansArr[i + j + 1] += x * int(num2[j])
        
        for i in range(m + n - 1, 0, -1):
            ansArr[i - 1] += ansArr[i] // 10
            ansArr[i] %= 10
        
        index = 1 if ansArr[0] == 0 else 0
        ans = "".join(str(x) for x in ansArr[index:])
        return ans

29. 两数相除
def divide(self, divd: int, dior: int) -> int:
        res = 0
        sign =  1 if divd ^ dior >= 0 else -1
        #print(sign)
        divd = abs(divd)
        dior = abs(dior)
        while divd >= dior:
            tmp, i = dior, 1
            while divd >= tmp:
                divd -= tmp
                res += i
                i <<= 1
                tmp <<= 1
        res = res * sign 
        return min(max(-2**31, res), 2**31-1)

sql

197. 上升的温度
select weather.id as 'Id'
from weather
    join
    weather w on DATEDIFF (weather.recordDate, w.recordDate) = 1
    and weather.Temperature > w.Temperature;
196. 删除重复的电子邮箱
delete p1 from Person p1, Person p2
where p1.Email = p2.Email and p1.Id > p2.Id
194. 转置文件
COLS=`head -1 file.txt | wc -w`
for (( i = 1; i <= $COLS; i++ )); do
    awk -v col=$i '{print $col}' file.txt |xargs
done
192. 统计词频
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{print $2,$1}'
180. 连续出现的数字
SELECT DISTINCT
    l1.Num AS ConsecutiveNums
FROM
    Logs l1,
    Logs l2,
    Logs l3
WHERE
    l1.Id = l2.Id - 1
    AND l2.Id = l3.Id - 1
    AND l1.Num = l2.Num
    AND l2.Num = l3.Num
;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值