Leetcode Hot 200 下

本文介绍了LeetCode中排名前200的热门算法题目,包括IP地址验证、子数组和、链表操作、二叉树问题、动态规划等,帮助提升编程技能和职场竞争力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

468. 验证IP地址

class Solution:
    def validIPAddress(self, queryIP: str) -> str:
        def isIPv4(ip: str) -> bool:
            return all(s and s.isdigit() and not(s[0] == '0' and len(s) > 1) and 0 <= int(s) <= 255 for s in sp) if len(sp := ip.split(".")) == 4 else False
        
        def isIPv6(ip: str) -> bool:
            return all(s and len(s) <= 4 and all(c in "0123456789ABCDEFabcdef" for c in s) for s in sp) if len(sp := ip.split(":")) == 8 else False

        if "." in queryIP and ":" not in queryIP and isIPv4(queryIP):
            return "IPv4"
        elif ":" in queryIP and "." not in queryIP and isIPv6(queryIP):
            return "IPv6"
        return "Neither"

560. 和为 K 的子数组

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        s = 0; res = 0
        # # 哨兵,起始边界条件
        d = defaultdict(int); d[0] = 1
        for num in nums:
            s += num
            res += d[s-k]
            d[s] += 1
        return res

# 一维前缀和
# 前缀和 + hash表
# s[i] = s[i-1] + num[i]
# 找使 s[i] - s[j] == k 的 j 的个数
# hash表记录前缀和出现的次数
# 时间复杂度:O(n),其中 n 为数组的长度。我们遍历数组的时间复杂度为 O(n),中间利用哈希表查询删除的复杂度均为 O(1),因此总时间复杂度为 O(n)。
# 空间复杂度:O(n)

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 copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if not head: return None
        d = dict()
        p = head
        while p:
            d[p] = Node(p.val)
            p = p.next
        p = head
        while p:
            d[p].next = d.get(p.next)
            d[p].random = d.get(p.random)
            p = p.next
        return d[head]

209. 长度最小的子数组

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n = len(nums)
        res = n + 1; s = 0
        i = j = 0
        while j < n:
            s += nums[j]
            while s >= target:
                res = min(res, j - i + 1)
                s -= nums[i]
                i += 1
            j += 1
        return res if res != n + 1 else 0

# 时间复杂度:O(n)
# 空间复杂度:O(1)

739. 每日温度

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        s = []
        res = [0] * len(temperatures)
        for i, v in enumerate(temperatures):
            while s and v > s[-1][1]:
                s_i, s_v = s.pop()
                res[s_i] = i - s_i
            s.append((i, v))
        return res

# 1.若栈为空或当日温度小于栈顶温度,则直接入栈
# 2.若当日温度大于栈顶温度,说明栈顶元素升温日找到,将栈顶元素出栈,计算其与当日相差的天数

136. 只出现一次的数字

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        res = 0
        for num in nums:
            res ^= num
        return res

498. 对角线遍历

class Solution:
    def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:
        res = []
        m = len(mat); n = len(mat[0])
        for k in range(m+n-1):
            if k % 2 == 0:
                res += [mat[x][k-x] for x in range(min(m-1,k), max(-1,k-n), -1)]
            else:
                res += [mat[x][k-x] for x in range(max(0,k-n+1),min(m,k+1))]
        return res

剑指 Offer 36. 二叉搜索树与双向链表

"""
# Definition for a Node.
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
"""
class Solution:
    def dfs(self, root: 'Node') -> 'Node':
        if not root: return
        self.dfs(root.left)
        # 双向链表
        root.left = self.pre
        self.pre.right = root
        # 右移指针
        self.pre = root
        self.dfs(root.right)
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        if not root: return
        self.pre = head = Node()
        self.dfs(root)
        # 首尾相连
        self.pre.right, head.right.left = head.right, self.pre
        return head.right

224. 基本计算器

class Solution:
    def calculate(self, s: str) -> int:
        ops = [1]
        sign = 1

        res = 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
                res += num * sign
        return res

剑指 Offer 09. 用两个栈实现队列

class CQueue:

    def __init__(self):
        self.s1, self.s2 = [], []

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

    def deleteHead(self) -> int:
        if not self.s2:
            while self.s1: self.s2.append(self.s1.pop())
        return self.s2.pop() if self.s2 else -1


# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()

460. LFU 缓存

class Node:
    def __init__(self, key, val, pre=None, nex=None, freq=0):
        self.pre = pre
        self.nex = nex
        self.freq = freq
        self.val = val
        self.key = key
        
    def insert(self, nex):
        nex.pre = self
        nex.nex = self.nex
        self.nex.pre = nex
        self.nex = nex
    
def create_linked_list():
    head = Node(0, 0)
    tail = Node(0, 0)
    head.nex = tail
    tail.pre = head
    return (head, tail)

class LFUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.size = 0
        self.minFreq = 0
        self.freqMap = collections.defaultdict(create_linked_list)
        self.keyMap = {}

    def delete(self, node):
        if node.pre:
            node.pre.nex = node.nex
            node.nex.pre = node.pre
            if node.pre is self.freqMap[node.freq][0] and node.nex is self.freqMap[node.freq][-1]:
                self.freqMap.pop(node.freq)
        return node.key
        
    def increase(self, node):
        node.freq += 1
        self.delete(node)
        self.freqMap[node.freq][-1].pre.insert(node)
        if node.freq == 1:
            self.minFreq = 1
        elif self.minFreq == node.freq - 1:
            head, tail = self.freqMap[node.freq - 1]
            if head.nex is tail:
                self.minFreq = node.freq

    def get(self, key: int) -> int:
        if key in self.keyMap:
            self.increase(self.keyMap[key])
            return self.keyMap[key].val
        return -1

    def put(self, key: int, value: int) -> None:
        if self.capacity != 0:
            if key in self.keyMap:
                node = self.keyMap[key]
                node.val = value
            else:
                node = Node(key, value)
                self.keyMap[key] = node
                self.size += 1
            if self.size > self.capacity:
                self.size -= 1
                deleted = self.delete(self.freqMap[self.minFreq][0].nex)
                self.keyMap.pop(deleted)
            self.increase(node)

912. 排序数组

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def merge_sort(a: list, l: int, r: int) -> list:
            if l >= r: return a
            m = l + r >> 1
            i = l; j = m + 1
            tmp = []
            merge_sort(a, l, m); merge_sort(a, m + 1, r)
            while i <= m and j <= r:
                if a[i] < a[j]:
                    tmp.append(a[i])
                    i += 1
                else:
                    tmp.append(a[j])
                    j += 1
            tmp += a[i:m+1]
            tmp += a[j:r+1]
            a[l:r+1] = tmp
            return a      
        return merge_sort(nums, 0, len(nums) - 1)

207. 课程表

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        edges = collections.defaultdict(list)
        indeg = [0] * numCourses
 
        for info in prerequisites:
            edges[info[1]].append(info[0])
            indeg[info[0]] += 1
        
        q = collections.deque([u for u in range(numCourses) if indeg[u] == 0])
        visited = 0
 
        while q:
            visited += 1
            u = q.popleft()
            for v in edges[u]:
                indeg[v] -= 1
                if indeg[v] == 0:
                    q.append(v)
 
        return visited == numCourses

402. 移掉 K 位数字

class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        numStack = []
        
        # 构建单调递增的数字串
        for digit in num:
            while k and numStack and numStack[-1] > digit:
                numStack.pop()
                k -= 1
        
            numStack.append(digit)
        
        # 如果 K > 0,删除末尾的 K 个字符
        finalStack = numStack[:-k] if k else numStack
        
        # 抹去前导零
        return "".join(finalStack).lstrip('0') or "0"

958. 二叉树的完全性检验

# 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(object):
    def isCompleteTree(self, root):
        q = [(root, 1)]
        i = 0
        while i < len(q):
            node, v = q[i]
            if node:
                q.append((node.left, 2*v))
                q.append((node.right, 2*v+1))
            i += 1
        return  q[-1][1] == len(q)

# 时间复杂度:O(N)
# 空间复杂度:O(N)

61. 旋转链表

class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        # 若链表为空,返回head
        if not head:
            return head
        # 获取链表的长度
        n = 0
        cur = head
        while cur:
            n += 1
            cur = cur.next
        # 若k的长度大于n,将k对n求余
        k = k % n
        # 若k==0表示循环了一整遍,直接返回head
        if k == 0:
            return head
        # 创建快慢指针
        slow = fast = head
        # fast指针先走k步
        while k:
            fast = fast.next
            k -= 1
        # 让fast指针走到队尾
        while fast.next:
            fast = fast.next
            slow = slow.next
        # 此时show.next为新的链表头
        h = slow.next
        # 断开slow.next
        slow.next = None
        # 链表首位相接
        fast.next = head
        # 返回新的链表头
        return h

11. 盛最多水的容器

class Solution:
    def maxArea(self, height: List[int]) -> int:
        res = 0
        l = 0; r = len(height) - 1
        while l < r:
            # 相同条件下边界距离越远,面积越大,所以设置左右指针从两边向中间移动;哪个边界小,哪个边界移动重新寻找机会,希望用边界高度的增加弥补两边界距离的减小
            if height[l] < height[r]:
                res = max(res, (r - l) * height[l])
                l += 1
            else:
                res = max(res, (r - l) * height[r])
                r -= 1
        return res

剑指 Offer 54. 二叉搜索树的第k大节点

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        #先尝试中序遍历保存所有节点,再找倒数第k个节点
        def inOrder(root):
            if not root: return
            inOrder(root.left)
            self.inorder.append(root.val)
            inOrder(root.right)        
        self.inorder = []
        inOrder(root)
        return self.inorder[-k]

剑指 Offer 10- II. 青蛙跳台阶问题

class Solution:
    def numWays(self, n: int) -> int:
        p = 0; q = 1
        for i in range(n):
            p, q = q, p+q
        return q % 1000000007

79. 单词搜索

class Solution(object):
    
    # 定义上下左右四个行走方向
    directs = [(0, 1), (0, -1), (1, 0), (-1, 0)]
    
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        m = len(board)
        if m == 0:
            return False
        n = len(board[0])
        visited = [[0 for _ in range(n)] for _ in range(m)]
                
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] == word[0]:
                    # 将该元素标记为已使用
                    visited[i][j] = 1
                    if self.backtrack(i, j, visited, board, word[1:]) == True:
                        return True
                    else:
                        # 回溯
                        visited[i][j] = 0
        return False
        
        
    def backtrack(self, i, j, visited, board, word):
        if len(word) == 0:
            return True
        
        for direct in self.directs:
            cur_i = i + direct[0]
            cur_j = j + direct[1]
            
            if cur_i >= 0 and cur_i < len(board) and cur_j >= 0 and cur_j < len(board[0]) and board[cur_i][cur_j] == word[0]:
                # 如果是已经使用过的元素,忽略
                if visited[cur_i][cur_j] == 1:
                    continue
                # 将该元素标记为已使用
                visited[cur_i][cur_j] = 1
                if self.backtrack(cur_i, cur_j, visited, board, word[1:]) == True:
                    return True
                else:
                    # 回溯
                    visited[cur_i][cur_j] = 0
        return False

剑指 Offer 51. 数组中的逆序对

class Solution:
    def merge_sort(self, a: list, l: int, r: int) -> int:
        if l >= r: return 0
        tmp = []
        m = l + r >> 1
        i = l; j = m + 1
        res = self.merge_sort(a, l, m) + self.merge_sort(a, m + 1, r)
        while i <= m and j <= r:
            if a[i] <= a[j]:
                tmp.append(a[i])
                i += 1
            else:
                res += m - i + 1
                tmp.append(a[j])
                j += 1
        tmp += a[i: m + 1]; tmp += a[j: r + 1]
        a[l: r + 1] = tmp
        return res
 
    def reversePairs(self, nums: List[int]) -> int:
        return self.merge_sort(nums, 0, len(nums) - 1)

59. 螺旋矩阵 II

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        l, r, t, b = 0, n - 1, 0, n - 1
        res = [[0 for _ in range(n)] for _ in range(n)]
        num, tar = 1, n * n
        while num <= tar:
            for i in range(l, r + 1): # left to right
                if num <= tar:
                    res[t][i] = num
                    num += 1
            t += 1
            for i in range(t, b + 1): # top to bottom
                if num <= tar:
                    res[i][r] = num
                    num += 1
            r -= 1
            for i in range(r, l - 1, -1): # right to left
                if num <= tar:
                    res[b][i] = num
                    num += 1
            b -= 1
            for i in range(b, t - 1, -1): # bottom to top
                if num <= tar:
                    res[i][l] = num
                    num += 1
            l += 1
        return res

47. 全排列 II

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        n = len(nums)
        nums.sort()
        visited = [False for _ in range(n)]
 
        def backtrace(idx: int) -> None:
            if idx == n:
                res.append(path[:])
                return            
            for i in range(0, n):
                if visited[i] == True or (0 < i and nums[i - 1] == nums[i] and visited[i - 1] == False): continue
                path.append(nums[i])
                visited[i] = True
                backtrace(idx + 1)               
                path.pop()
                visited[i] = False
 
        backtrace(0)
        return res

55. 跳跃游戏

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        end = 0
        for i in range(len(nums)):
            if i > end: return False
            end = max(end, i+nums[i])
        return True

40. 组合总和 II

from typing import List
 
class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        def dfs(begin, path, residue):
            if residue == 0:
                res.append(path[:])
                return
 
            for index in range(begin, size):
                if candidates[index] > residue:
                    break
 
                if index > begin and candidates[index - 1] == candidates[index]:
                    continue
 
                path.append(candidates[index])
                dfs(index + 1, path, residue - candidates[index])
                path.pop()
 
        size = len(candidates)
        if size == 0:
            return []
 
        candidates.sort()
        res = []
        dfs(0, [], target)
        return res

123. 买卖股票的最佳时机 III

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices: return 0
        k = 2
        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)

26. 删除有序数组中的重复项

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        j = 0
        for i in range(len(nums)):
            if nums[i] != nums[j]:
                j += 1
                nums[j] = nums[i]
        return j + 1

# 时间复杂度:O(n)
# 空间复杂度:O(1)

剑指 Offer 42. 连续子数组的最大和

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0] * n
        dp[0] = nums[0]
        # dp 以下标 i 结尾的最大和的连续子数组
        for i in range(1, n):
            if dp[i-1] > 0:
                dp[i] = dp[i-1] + nums[i]
            else:
                dp[i] = nums[i]
        return max(dp)

50. Pow(x, n)

class Solution:
    def myPow(self, x: float, n: int) -> float:
        res = 1
        if n < 0: n = -n; x = 1 / x
        while n:
            if n % 2 == 1: res *= x
            # if n & 1: res *= x
            x = x * x
            n //= 2
            # n >>= 1
        return res

518. 零钱兑换 II

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        # dp[x] 表示金额之和等于 x 的硬币组合数
        # 动态规划的边界是 dp[0]=1。只有当不选取任何硬币时,金额之和才为 0,因此只有 1 种硬币组合
        dp = [0] * (amount + 1)
        dp[0] = 1
        for coin in coins:
            for i in range(coin, amount + 1):
                dp[i] += dp[i - coin]
        return dp[amount]

145. 二叉树的后序遍历

# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        def dfs(root: TreeNode):
            if root is None: return         
            dfs(root.left)
            dfs(root.right)
            res.append(root.val)
        res = []
        dfs(root)
        return res

剑指 Offer 40. 最小的k个数

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        def quick_sort(a, l, r):
            if l >= r: return a
            i = l - 1; j = r + 1
            x = a[l + r >> 1]
            while i < j:
                i += 1
                while a[i] < x: i += 1
                j -= 1
                while a[j] > x: j -= 1
                if i < j: a[i], a[j] = a[j], a[i]
            quick_sort(a, l, j); quick_sort(a, j + 1, r)
            return a
        if k >= len(arr): return arr
        res = quick_sort(arr, 0, len(arr) - 1)
        return res[:k]

7. 整数反转

class Solution:
    def reverse(self, x: int) -> int:
        res = int((str(x) if x > 0 else str(-x) + "-")[::-1])
        return res if -2**31 < res < 2**31 else 0

74. 搜索二维矩阵

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        row = len(matrix); col = len(matrix[0])
        l = 0; r = row * col - 1
        while l <= r:
            m = l + r >> 1
            num = matrix[m//col][m%col]
            if num == target:
                return True
            elif num < target:
                l = m + 1
            else:
                r = m - 1
        return False
 
# 展开成一维数组,全局有序
# 时间复杂度:O(logmn),其中 m 和 n 分别是矩阵的行数和列数。
# 空间复杂度:O(1)
 

剑指 Offer 10- I. 斐波那契数列
 

class Solution:
    def fib(self, n: int) -> int:
        p = 0; q = 1
        for i in range(n):
            p, q = q, p+q
        return p % 1000000007

440. 字典序的第K小数字

class Solution:
    def getSteps(self, cur: int, n: int) -> int:
        steps, first, last = 0, cur, cur
        while first <= n:
            steps += min(last, n) - first + 1
            first *= 10
            last = last * 10 + 9
        return steps

    def findKthNumber(self, n: int, k: int) -> int:
        cur = 1
        k -= 1
        while k:
            steps = self.getSteps(cur, n)
            if steps <= k:
                k -= steps
                cur += 1
            else:
                cur *= 10
                k -= 1
        return cur

450. 删除二叉搜索树中的节点

# 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 deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        if not root: return None
        if root.val > key: root.left = self.deleteNode(root.left, key) # 去左子树删除
        elif root.val < key: root.right = self.deleteNode(root.right, key) # 去右子树删除
        # 当前节点就是要删除的节点
        else:
            if not root.left: return root.right # 当前节点无左子树,不要写成 root = root.right,这样会多走一步报空值异常
            if not root.right: return  root.left # 当前节点无右子树,不要写成 root = root.left,这样会多走一步报空值异常
            else: # 当前节点左右子树都有
                node = root.right
                while node.left: # 寻找欲删除节点右子树的最左节点
                    node = node.left
                node.left = root.left # 将欲删除节点的左子树成为其右子树最左节点的左子树
                root = root.right # 欲删除节点的右子树顶替其位置,节点被删除
        return root

# 根据二叉搜索树的性质:
# 1. 如果目标节点大于当前节点值,则去右子树中删除;
# 2. 如果目标节点小于当前节点值,则去左子树中删除;
# 3. 如果目标节点就是当前节点,分为以下三种情况:
# 3.1 其无左子:其右子顶替其位置,删除了该节点;
# 3.2 其无右子:其左子顶替其位置,删除了该节点;
# 3.3 其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。

# 时间复杂度:O(H),H是树的高度,寻找目标节点最坏情况需要O(H),删除操作最坏情况也需要O(H);
# 空间复杂度:O(H),递归栈的深度最坏情况为树的高度;

剑指 Offer 04. 二维数组中的查找

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix: return False
        m = len(matrix); n = len(matrix[0])
        i = 0; j = n - 1
        while i < m and j >= 0:
            if matrix[i][j] == target: return True
            elif matrix[i][j] < target: i += 1
            else: j -= 1
        return False

75. 颜色分类

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        if len(nums) < 2: return
        # 循环不变量确定循环变量 
        # 0 in [0, p0), 1 in [p0, p1), 2 in [p2, len(nums)]
        p1 = 0; p0 = 0; p2 = len(nums) - 1
        # 循环变量 p1 > p2 时, 跳出循环
        while p1 <= p2:
            if nums[p1] == 0: # 0, 1交换,由于交换到右边的是1, 所以根据第二个if条件p1++
                nums[p1], nums[p0] = nums[p0], nums[p1]
                p0 += 1
                p1 += 1
            elif nums[p1] == 1:
                p1 += 1
            else: # nums[p1] == 2
                nums[p1], nums[p2] = nums[p2], nums[p1]
                # 由于不知道交换回来的nums[p2]的值,所以不对循环变量 p1 操作,进入下一次循环判断
                p2 -= 1
 
# 归并排序思想

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        l = 0; r = len(nums) - 1
        while l <= r:
            while l <= r and nums[l] % 2 == 1:
                l += 1
            while l <= r and nums[r] % 2 == 0:
                r -= 1
            if l > r: break
            nums[l], nums[r] = nums[r], nums[l]
        return nums

230. 二叉搜索树中第K小的元素

# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        def dfs(root):
            if not root: return
            dfs(root.left)
            self.res.append(root.val)
            dfs(root.right)
        self.res = []
        dfs(root)
        return self.res[k-1]

225. 用队列实现栈

class MyStack:
 
    def __init__(self):
        self.q = []
 
    def push(self, x: int) -> None:
        n = len(self.q)
        self.q.append(x)   
        for _ in range(n):
            self.q.append(self.q.pop(0))
 
    def pop(self) -> int:
        return self.q.pop(0)
 
    def top(self) -> int:
        return self.q[0]
 
    def empty(self) -> bool:
        return not self.q
 
 
 
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
 
# 入栈操作时,首先获得入栈前的元素个数 nn,然后将元素入队到队列,再将队列中的前 nn 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

135. 分发糖果

class Solution:
    def candy(self, ratings: List[int]) -> int:
        left = [1 for _ in range(len(ratings))]
        right = left[:]
        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i - 1]: left[i] = left[i - 1] + 1
        count = left[-1]
        for i in range(len(ratings) - 2, -1, -1):
            if ratings[i] > ratings[i + 1]: right[i] = right[i + 1] + 1
            count += max(left[i], right[i])
        return count

剑指 Offer 62. 圆圈中最后剩下的数字

class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        f = 0
        for i in range(2, n+1):
            # dp[n,m] = 0                      n = 1
            # dp[n,m] = (dp[n-1,m] + m) % n    n > 1
            f = (f + m) % i
        return f

45. 跳跃游戏 II

class Solution:
    def jump(self, nums: List[int]) -> int:
        res = 0
        end = max_v = 0
        for i in range(len(nums)-1):
            max_v = max(max_v, i+nums[i])
            if i == end:
                end = max_v
                res += 1
        return res
# 1.维护几个变量:当前所能达到的最远位置 end,下一步所能跳到的最远位置 max_pos,最少跳跃次数 setps。
# 2.遍历数组 nums 的前 len(nums) - 1 个元素:
# 每次更新第 i 位置下一步所能跳到的最远位置 max_pos。
# 如果索引 i 到达了 end 边界,则:更新 end 为新的当前位置 max_pos,并令步数 setps 加 1。
# 3.最终返回跳跃次数 steps。
 
# 时间复杂度:O(n)O(n)。一重循环遍历的时间复杂度是 O(n)O(n),所以总体时间复杂度为 O(n)O(n)。
# 空间复杂度:O(1)O(1)。只用到了常数项的变量,所以总体空间复杂度为 O(1)O(1)。
 

91. 解码方法

class Solution:
    def numDecodings(self, s: str) -> int:
        n = len(s)
        dp = [1] + [0] * n
        for i in range(1, n + 1):
            if s[i - 1] != '0':
                dp[i] += dp[i - 1]
            if i > 1 and s[i - 2] != '0' and int(s[i-2:i]) <= 26:
                dp[i] += dp[i - 2]
        return dp[n]

329. 矩阵中的最长递增路径

class Solution:
    def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
        if not matrix:
            return 0

        h,w = len(matrix),len(matrix[0])

        store = [[None]*(w) for i in range(h)]

        m = 0 #储存max路径值

        def search_nearby(i,j):
            nonlocal m

            compare = [] #储存可以比较的候选人

            #这个楼主很懒,还没想怎么简化下面的代码
            #反正下面四个代码块就是分别看一下上、下、左、右哪些格子的值可以当做候选人比较

            #上
            if i != 0 and matrix[i-1][j] < matrix[i][j]: #有上边且上边小于当前数的话
                compare.append(store[i-1][j]) if store[i-1][j] else compare.append(search_nearby(i-1,j))

            #左
            if j != 0 and matrix[i][j-1] < matrix[i][j]: #有左边且左边小于当前数的话
                compare.append(store[i][j-1]) if store[i][j-1] else compare.append(search_nearby(i,j-1))

            #下
            if i != h-1 and matrix[i+1][j] < matrix[i][j]: #有下边且下边小于当前数的话
                compare.append(store[i+1][j]) if store[i+1][j] else compare.append(search_nearby(i+1,j))

            #右
            if j != w-1 and matrix[i][j+1] < matrix[i][j]: #有右边且右边小于当前数的话
                compare.append(store[i][j+1]) if store[i][j+1] else compare.append(search_nearby(i,j+1))
            
            store[i][j] = max(compare)+1 if compare else 1
            #如果没有compare说明这是一个很小的数,是一个起始点,能组成的长度只有1
            #有的话就原来最长路径+1

            m = max(m,store[i][j])
            return (store[i][j])
        
        for i in range(h):
            for j in range(w):
                if not store[i][j]:
                    search_nearby(i,j)
        
        return m

572. 另一棵树的子树

# 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 dfs(self, p, q):
        if not p and not q: return True
        if not p or not q: return False
        return p.val == q.val and self.dfs(p.left, q.left) and self.dfs(p.right, q.right)

    def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
        if not root and not subRoot: return True
        if not root or not subRoot: return False
        return self.dfs(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

328. 奇偶链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head:
            return head
        
        odd = head; even = evenHead = head.next
        while even and even.next:
            odd.next = even.next
            odd = odd.next
            even.next = odd.next
            even = even.next
        odd.next = evenHead
        return head

114. 二叉树展开为链表

# 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 flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        res = []
        def dfs(root):
            if root is None: return
            res.append(root)
            dfs(root.left)           
            dfs(root.right)
        dfs(root)
        for i in range(1, len(res)):
            pre, cur = res[i-1], res[i]
            pre.left = None
            pre.right = cur

# 前序遍历
# 时间复杂度:O(n)
# 空间复杂度:O(n)

208. 实现 Trie (前缀树)

class Trie:
    def __init__(self):
        self.children = [None] * 26
        self.isEnd = False
    
    def searchPrefix(self, prefix: str) -> "Trie":
        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: str) -> None:
        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: str) -> bool:
        node = self.searchPrefix(word)
        return node is not None and node.isEnd
 
    def startsWith(self, prefix: str) -> bool:
        return self.searchPrefix(prefix) is not None
 
 
 
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

9. 回文数

class Solution:
    def isPalindrome(self, x: int) -> bool:
        return str(x) == str(x)[::-1]

剑指 Offer 26. 树的子结构

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
#1.先序遍历树A中的每个节点, 2.再判断A中每个节点是否包含B
 
class Solution:
    #子结构
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        #包含
        def dfs(A: TreeNode, B: TreeNode) -> bool:
            # 当节点B为空:说明树B已匹配完成(越过叶子节点),因此返回True;
            if not B: return True
            # 当节点A为空:说明已经越过树A叶子节点,即匹配失败,返回False; 
            # 当节点A和B的值不同:说明匹配失败,返回False;
            if not A or A.val != B.val: return False
            return dfs(A.left,B.left) and dfs(A.right,B.right)
        if not A or not B: return False
        return dfs(A,B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)

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 %= n
        tmp = nums[-k:] + nums[:-k]
        nums[:] = tmp[:]

384. 打乱数组

class Solution:
    def __init__(self, nums: List[int]):
        self.nums = nums
        self.original = nums.copy()

    def reset(self) -> List[int]:
        self.nums = self.original.copy()
        return self.nums

    def shuffle(self) -> List[int]:
        for i in range(len(self.nums)):
            j = random.randrange(i, len(self.nums))
            self.nums[i], self.nums[j] = self.nums[j], self.nums[i]
        return self.nums

# Your Solution object will be instantiated and called as such:
# obj = Solution(nums)
# param_1 = obj.reset()
# param_2 = obj.shuffle()

125. 验证回文串

class Solution:
    def isPalindrome(self, s: str) -> bool:
        # isalnum() 方法检测字符串是否由字母和数字组成。
        t = ''.join(c.lower() for c in s if c.isalnum())
        return t == t[::-1]

10. 正则表达式匹配

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

295. 数据流的中位数

from sortedcontainers import SortedList

class MedianFinder:

    def __init__(self):
        self.nums = SortedList()

    def addNum(self, num: int) -> None:
        self.nums.add(num)

    def findMedian(self) -> float:
        n = len(self.nums)
        return (self.nums[n // 2] + self.nums[(n - 1) // 2]) / 2


# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()

445. 两数相加 II

# 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: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
        # 利用栈先进后出实现由低位向高位加      
        s1, s2 = [], []
        while l1:
            s1.append(l1.val)
            l1 = l1.next
        while l2:
            s2.append(l2.val)
            l2 = l2.next
        # 当前指针,结果链表
        res = None
        # 进位项
        carry = 0
 
        # 非空满足循环条件
        while s1 or s2 or carry != 0:
            n1 = s1.pop() if s1 else 0
            n2 = s2.pop() if s2 else 0
 
            n = n1 + n2 + carry
            carry = n // 10
            cur = ListNode(n % 10)
            cur.next = res
            res = cur
 
        return res

剑指 Offer 27. 二叉树的镜像

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        # 递归函数的终止条件,节点为空时返回
        if not root: return None
        # 将当前节点的左右子树交换
        root.left, root.right = root.right, root.left
        # 递归交换当前节点的 左子树和右子树
        self.mirrorTree(root.left)
        self.mirrorTree(root.right)
        # 函数返回时就表示当前这个节点,以及它的左右子树
        # 都已经交换完了		
        return root

16. 最接近的三数之和

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        res = nums[0] + nums[1] + nums[2]
        nums.sort()
        for i in range(len(nums)):
            l = i + 1; r = len(nums) - 1
            while l < r:
                sums = nums[i] + nums[l] + nums[r]
                if abs(sums-target) < abs(res-target): res = sums
                if sums < target: l += 1
                elif sums > target: r -= 1
                else: return res
        return res

287. 寻找重复数

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        slow = 0; fast = 0
        while True:
            # 先走一步再判断,要不然刚开始就退出了
            slow = nums[slow]
            fast = nums[nums[fast]]
            if slow == fast: break
        slow = 0
        while slow != fast:
            slow = nums[slow]
            fast = nums[fast]
        return slow
    
# 转换为图论,之后用 142. 环形链表 II 解法
# 数字都在 [1, n],因此0一定没有环
# 从0开始走一定会走到环里
# 环的入口表示至少有2个数存的环的入口,即重复数

# 时间复杂度:O(n)。Floyd 判圈算法时间复杂度为线性的时间复杂度。
# 空间复杂度:O(1)O(1)

106. 从中序与后序遍历序列构造二叉树

# 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 buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        if not postorder: return None
        root = TreeNode(postorder[-1])
        cur = inorder.index(root.val)
        root.left = self.buildTree(inorder[0:cur], postorder[0:cur])
        root.right = self.buildTree(inorder[cur+1:], postorder[cur:-1])
        return root

剑指 Offer 29. 顺时针打印矩阵

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix: return []
        m = len(matrix); n = len(matrix[0])
        l = 0; r = n - 1; t = 0; b = m - 1
        num = 1; tt = m * n
        res = []
        while num <= tt:
            for i in range(l, r + 1):
                if num <= tt:
                    res.append(matrix[t][i])
                    num += 1
            t += 1
            for i in range(t, b + 1):
                if num <= tt:
                    res.append(matrix[i][r])
                    num += 1
            r -= 1
            for i in range(r, l - 1, -1):
                if num <= tt:
                    res.append(matrix[b][i])
                    num += 1
            b -= 1
            for i in range(b, t - 1, -1):
                if num <= tt:
                    res.append(matrix[i][l])
                    num += 1
            l += 1
        return res

96. 不同的二叉搜索树

class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0] = 1
        for i in range(1, n + 1):
            for j in range(1, i+1):
                dp[i] += dp[j-1] * dp[i-j]
        return dp[n]

# 动态规划,dp[n] 表示整数 n 对应的二叉搜索树种类
# 时间复杂度 : O(n^2),其中 n 表示二叉搜索树的节点个数。
# 空间复杂度 : O(n)

213. 打家劫舍 II

class Solution:
    def rob(self, nums: [int]) -> int:
        def my_rob(nums):
            cur, pre = 0, 0
            for num in nums:
                cur, pre = max(pre + num, cur), cur
            return cur
        return max(my_rob(nums[:-1]),my_rob(nums[1:])) if len(nums) != 1 else nums[0]

400. 第 N 位数字

class Solution:
    def findNthDigit(self, n: int) -> int:
        d, count = 1, 9
        while n > d * count:
            n -= d * count
            d += 1
            count *= 10
        index = n - 1
        start = 10 ** (d - 1)
        num = start + index // d
        digitIndex = index % d
        return num // 10 ** (d - digitIndex - 1) % 10

349. 两个数组的交集

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1.sort(); nums2.sort()
        res = []
        p1 = 0; p2 = 0
        while p1 < len(nums1) and p2 < len(nums2):
            n1 = nums1[p1]; n2 = nums2[p2]
            if n1 == n2:
                if not res or n1 != res[-1]: res.append(n1)
                p1 += 1
                p2 += 1
            elif n1 < n2:
                p1 += 1
            else:
                p2 += 1
        return res

# 排序 + 双指针
# 时间复杂度:O(mlogm+nlogn),其中 m 和 n 分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O(mlogm) 和 O(nlogn),双指针寻找交集元素的时间复杂度是 O(m+n)O(m+n),因此总时间复杂度是O(mlogm+nlogn)。
# 空间复杂度:O(logm+logn),其中 mm 和 nn 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。

120. 三角形最小路径和

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        for i in range(n - 2, -1, -1):
            for j in range(len(triangle[i])):
                triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
        return triangle[0][0]

347. 前 K 个高频元素

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        c = collections.Counter(nums)
        print(c)
        h = []
        for key, val in c.items():
            heapq.heappush(h, (val, key))
            if len(h) > k:
                heapq.heappop(h)
        return [x[1] for x in h]

887. 鸡蛋掉落

class Solution:
    def superEggDrop(self, k: int, n: int) -> int:
        if n == 1:
            return 1
        f = [[0] * (k + 1) for _ in range(n + 1)]
        for i in range(1, k + 1):
            f[1][i] = 1
        res = -1
        for i in range(2, n + 1):
            for j in range(1, k + 1):
                f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j]
            if f[i][k] >= n:
                res = i
                break
        return res

168. Excel表列名称

class Solution:
    def convertToTitle(self, columnNumber: int) -> str:
        res = list()
        while columnNumber > 0:
            columnNumber -= 1
            res.append(chr(columnNumber % 26 + ord("A")))
            columnNumber //= 26
        return "".join(res[::-1])

剑指 Offer 61. 扑克牌中的顺子

class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        joker = 0
        nums.sort() # 数组排序
        for i in range(4):
            if nums[i] == 0: joker += 1 # 统计大小王数量
            elif nums[i] == nums[i + 1]: return False # 若有重复,提前返回 false
        return nums[4] - nums[joker] < 5 # 最大牌 - 最小牌 < 5 则可构成顺子

面试题 02.05. 链表求和

# 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: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        dummpy = cur = ListNode()
        carry = 0
        while l1 or l2 or carry != 0:
            n1 = l1.val if l1 else 0
            n2 = l2.val if l2 else 0
 
            n = n1 + n2 + carry
            carry = n // 10
            cur.next = ListNode(n % 10)
 
            if l1: l1 = l1.next
            if l2: l2 = l2.next
            cur = cur.next
        
        return dummpy.next

678. 有效的括号字符串

class Solution:
    def checkValidString(self, s: str) -> bool:
        def help(a):
            cnt = 0
            for c in s if a == 1 else reversed(s):
                if c == '(': cnt += a 
                if c == ')': cnt += -a
                if c == '*': cnt += 1
                if cnt < 0:
                    return False
            return True
        return help(1) and help(-1)

剑指 Offer 52. 两个链表的第一个公共节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        p = headA; q = headB
        while p != q:
            p = p.next if p else headB
            q = q.next if q else headA
        return p

111. 二叉树的最小深度

# 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 minDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        l = self.minDepth(root.left)
        r = self.minDepth(root.right)
        if root.left is None or root.right is None: return l + r + 1
        return min(l, r) + 1
# 叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点
# 当 root 节点左右孩子都为空时,返回 1
# 当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度
# 当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值

679. 24 点游戏

class Solution:
    def judgePoint24(self, cards: List[int]) -> bool:
        if len(cards) == 1:
            return math.isclose(cards[0], 24)
        
        for _ in range(len(cards)):
            a = cards.pop(0) # 摸一张 (queue 操作)
            for _ in range(len(cards)):
                b = cards.pop(0) # 再摸一张 (queue 操作)
                for value in [a + b, a - b, a * b, b and a / b]: # 算一下
                    cards.append(value) # 记下来 (stack 操作)
                    if self.judgePoint24(cards):
                        return True
                    cards.pop() # (stack 操作)
                cards.append(b) # (queue 操作)
            cards.append(a) # (queue 操作)
        return False

134. 加油站

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        # 跑完全程再回到起点,总油量剩余值的任意部分都需要在X轴以上; 且跑到终点时:总剩余汽油量 >= 0。
        n = len(gas)
        cur = 0; minindex= 0; mingas = 0
        for i in range(n):
            cur += gas[i] - cost[i]
            if cur < mingas:
                mingas = cur
                minindex = i + 1
        return -1 if cur < 0 else minindex

1004. 最大连续1的个数 III

class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        res = 0; cnt = 0; j = 0
        for i in range(len(nums)):
            if nums[i] == 0: cnt += 1
            while cnt > k:
                if nums[j] == 0: cnt -= 1
                j += 1
            res = max(res, i - j + 1)
        return res

# 时间复杂度:O(n)
# 空间复杂度:O(1)

611. 有效三角形的个数

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        res = 0
        nums.sort()
        # k是最短边,j是次短边,i是最长边
        # nums[k] + nums[j] > nums[i]
        for i in range(2, len(nums)):
            j = i - 1; k = 0
            while j > 0 and j > k:
                while k < j and nums[k] + nums[j] <= nums[i] : k += 1
                # [k, j-1]都是最短边的选法,j-1-k+1
                res += j - k
                j -= 1
        return res
# 时间复杂度:O(n*n)
# 空间复杂度:O(logn)

剑指 Offer 39. 数组中出现次数超过一半的数字

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        votes = 0
        for num in nums:
            if votes == 0: x = num
            votes += 1 if num == x else -1
        return x

673. 最长递增子序列的个数


class Solution:
    def findNumberOfLIS(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:
            return 0
        
        # 定义状态数组
        # dp[i][0] 表示以 nums[i] 结尾的最长递增子序列的长度
        # dp[i][1] 表示以 nums[i] 结尾的最长递增子序列的个数
        dp = [[1, 1] for _ in range(n)]
        max_length = 1  # 最长递增子序列的长度
        for i in range(1, n):
            for j in range(i):
                if nums[j] < nums[i]:
                    if dp[j][0] + 1 > dp[i][0]:  # 如果长度更长,则更新
                        dp[i][0] = dp[j][0] + 1
                        dp[i][1] = dp[j][1]
                    elif dp[j][0] + 1 == dp[i][0]:  # 如果长度相等,则累加个数
                        dp[i][1] += dp[j][1]
            max_length = max(max_length, dp[i][0])  # 更新最长递增子序列长度
        res = 0
        for i in range(n):
            if dp[i][0] == max_length:  # 如果长度等于最长递增子序列长度,则累加个数
                res += dp[i][1]
        return res

71. 简化路径

class Solution:
    def simplifyPath(self, path: str) -> str:
        stack = []
        path = path.split("/")

        for item in path:
            if item == "..":
                if stack : stack.pop()
            elif item and item != ".":
                stack.append(item)
        return "/" + "/".join(stack)

442. 数组中重复的数据

class Solution:
    def findDuplicates(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            while nums[i] != nums[nums[i]-1]:
                nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]
        return [num for i, num in enumerate(nums) if num-1 != i]

# 时间复杂度:O(n)
# 空间复杂度:O(1)

509. 斐波那契数

class Solution:
    def fib(self, n: int) -> int:
        p = 0; q = 1
        for i in range(n):
            p, q = q, p+q
        return p % 1000000007

1047. 删除字符串中的所有相邻重复项

class Solution:
    def removeDuplicates(self, s: str) -> str:
        stk = list()
        for ch in s:
            if stk and stk[-1] == ch:
                stk.pop()
            else:
                stk.append(ch)
        return "".join(stk)

剑指 Offer 45. 把数组排成最小的数

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        nums = sorted(map(str, nums), key=cmp_to_key(lambda x, y: int(x+y) - int(y+x)))
        return '0' if nums[0] == 0 else ''.join(nums)

37. 解数独

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        self.backtracking(board)

    def backtracking(self, board: List[List[str]]) -> bool:
        # 若有解,返回True;若无解,返回False
        for i in range(len(board)): # 遍历行
            for j in range(len(board[0])):  # 遍历列
                # 若空格内已有数字,跳过
                if board[i][j] != '.': continue
                for k in range(1, 10):  
                    if self.is_valid(i, j, k, board):
                        board[i][j] = str(k)
                        if self.backtracking(board): return True
                        board[i][j] = '.'
                # 若数字1-9都不能成功填入空格,返回False无解
                return False
        return True # 有解

    def is_valid(self, row: int, col: int, val: int, board: List[List[str]]) -> bool:
        # 判断同一行是否冲突
        for i in range(9):
            if board[row][i] == str(val):
                return False
        # 判断同一列是否冲突
        for j in range(9):
            if board[j][col] == str(val):
                return False
        # 判断同一九宫格是否有冲突
        start_row = (row // 3) * 3
        start_col = (col // 3) * 3
        for i in range(start_row, start_row + 3):
            for j in range(start_col, start_col + 3):
                if board[i][j] == str(val):
                    return False
        return True

459. 重复的子字符串

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        def kmp(pattern: str) -> bool:
            n = len(pattern)
            fail = [-1] * n
            for i in range(1, n):
                j = fail[i - 1]
                while j != -1 and pattern[j + 1] != pattern[i]:
                    j = fail[j]
                if pattern[j + 1] == pattern[i]:
                    fail[i] = j + 1
            return fail[n - 1] != -1 and n % (n - fail[n - 1] - 1) == 0
        
        return kmp(s)

剑指 Offer 34. 二叉树中和为某一值的路径

# 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 pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        res = list(); path = list()     
        def dfs(root: TreeNode, targetSum: int):
            if not root: return
            path.append(root.val)
            targetSum -= root.val
            if not root.left and not root.right and targetSum == 0:
                res.append(path[:])
            dfs(root.left, targetSum)
            dfs(root.right, targetSum)
            path.pop()    
        dfs(root, targetSum)
        return res

剑指 Offer 53 - I. 在排序数组中查找数字 I

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        def helper(t):
            l = 0; r = len(nums)
            while l < r:
                m = (l + r) // 2
                if nums[m] <= t: l = m + 1
                else: r = m
            # 模板2.3寻找右侧边界本来是返回 l-1, 这里返回 l 起始是目标值大一个数的左侧边界
            return l
        return helper(target) - helper(target - 1)
# 先找到第一个比target大的数的位置。
# 再找到第一个比target-1大的数的位置。
# 两个位置之差为结果
 
# 时间复杂度: O(logn) ,其中 n 为数组的长度。二分查找的时间复杂度为 O(logn),一共会执行两次,因此总时间复杂度为 O(logn)。
# 空间复杂度:O(1) 。只需要常数空间存放若干变量。

86. 分隔链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
        l0 = l = ListNode(0); r0 = r = ListNode(0)
        p = head
        while p:
            if p.val < x:
                l.next = p
                l = l.next
            else:
                r.next = p
                r = r.next
            p = p.next
        l.next = r0.next
        r.next = None
        return l0.next
# 时间复杂度: O(n)
# 空间复杂度: O(1)

395. 至少有 K 个重复字符的最长子串

class Solution:
    def longestSubstring(self, s: str, k: int) -> int:
        if len(s) < k: return 0
        for c in set(s):
            if s.count(c) < k:
                return max(self.longestSubstring(t, k) for t in s.split(c))
        return len(s)

# 时间复杂度:O(N∗26∗26)
# 空间复杂度:O(26∗26)

210. 课程表 II

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        # 存储有向图
        edges = collections.defaultdict(list)
        # 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
        visited = [0] * numCourses
        # 用数组来模拟栈,下标 0 为栈底,n-1 为栈顶
        result = list()
        # 判断有向图中是否有环
        valid = True

        for info in prerequisites:
            edges[info[1]].append(info[0])
        
        def dfs(u: int):
            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()
        
        # 如果没有环,那么就有拓扑排序
        # 注意下标 0 为栈底,因此需要将数组反序输出
        return result[::-1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值