coding_v2

动态规划

题目list【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        for coin in coins:
            for x in range(coin, amount+1):
                dp[x] = min(dp[x], dp[x - coin] + 1)
        if dp[amount] != float('inf'):
            return dp[amount]
        else:
            return -1

  1. LC322【零钱兑换】

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        for coin in coins:
            for x in range(coin, amount+1):
                dp[x] = min(dp[x], dp[x - coin] + 1)
        if dp[amount] != float('inf'):
            return dp[amount]
        else:
            return -1
  1. LC139【单词拆分】

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        n = len(s)
        dp = [False] * (n + 1)
        dp[0] = True
        dic = set(wordDict)
        for i in range(1, n+1):
            for j in range(i):
                if dp[j] and s[j:i] in dic:
                    dp[i] = True
                    break
        return dp[n]
  1. LC300:最长上升子序列【【LeetCode】最长上升子序列 python ★★★★★★_yingzoe的博客-CSDN博客_最长上升子序列python


def solve(nums):
    if not nums:
        return -1
    l = len(nums)
    dp = [1] * l
    max_len = 1 # 长度至少也是1
    for i in range(1, l):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[j]+1, dp[i])
                if dp[i] > max_len:
                    max_len = dp[i]
    return max_len
  1. 合唱团【合唱团(牛客) - 代码先锋网


def solve(nums):
    num1 = kernel(nums)
    print(num1)
    num2 = kernel(nums[::-1])
    print(num2)
    res = []
    ans = -1
    for i in range(len(num1)):
        cur = num1[i] + num2[i] - 1
        res.append(cur)
        ans = max(ans, res[i])
    return len(nums) - ans
def kernel(nums):
    n = len(nums)
    dp = [1] * n
    res = 1
    for i in range(1, n):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[j]+1, dp[i])
                res = max(res, dp[i])
    return dp
  1. LC674:最长连续递增序列【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


def solve(nums):
    if not nums:
        return -1
    ans = 1
    l = len(nums)
    start = 0
    for i in range(l):
        if i > 0 and nums[i] <= nums[i-1]:
            start = i
        ans = max(ans, i - start + 1)
    return ans
  1. LC718:最长重复子数组


def solve(nums1, nums2):
    m ,n = len(nums1), len(nums2)
    dp = [[0] * (n + 1) for i in range(m+1)]
    ans = 0
    for i in range(m-1, -1, -1):
        for j in range(n-1, -1, -1):
            if nums1[i] == nums2[j]:
                dp[i][j] = dp[i+1][j+1] + 1
            else:
                dp[i][j] = 0
            ans = max(ans, dp[i][j])
    return ans
    
  1. LC1143:最长公共子序列


def solve(text1, text2):
    m, n = len(text1), len(text2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if text1[i-1] == text2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]
  1. LC1035:不相交的线【本质为最长公共子序列】


def solve(nums1, nums2):
    m, n = len(nums1), len(nums2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if nums1[i-1] == nums2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]
  1. LC53:最大子序和【连续】


def solve(nums):
    pre = 0
    max_sum = nums[0]
    for each in nums:
        pre = max(pre + each, each) # 当前数字大,还是加上当前数字之前的一段大
        max_sum = max(pre, max_sum)
    return max_sum

def solve(nums):
    if not nums:
        return -1
    n = len(nums)
    dp = [0] * n
    dp[0] = nums[0]
    res = nums[0]
    for i in range(1, n):
        if dp[i-1] >= 0:
            dp[i] = dp[i-1] + nums[i]
        else:
            dp[i] = nums[i]
        res = max(res, dp[i])
    return res
  1. LC918【环形子数组最大和】

class Solution:
    def maxSubarraySumCircular(self, nums: List[int]) -> int:
        total = 0
        maxsum = nums[0]
        minsum = nums[0]
        cur_max = 0
        cur_min = 0
        for each in nums:
            cur_max = max(cur_max + each, each)
            maxsum = max(maxsum, cur_max)
            cur_min = min(cur_min + each, each)
            minsum = min(minsum, cur_min)
            total += each
        if maxsum < 0:
            return maxsum
        else:
            return max(maxsum, total - minsum)
  1. LC152【乘积最大子数组】

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        res = nums[0]
        pre_max = nums[0]
        pre_min = nums[0]
        for each in nums[1:]:
            cur_max = max(pre_max * each, pre_min * each, each)
            cur_min = min(pre_max * each, pre_min * each, each)
            res = max(res, cur_max)
            pre_max = cur_max
            pre_min = cur_min
        return res
  1. LC392:判断子序列


def solve(s, t):
    m, n = len(s), len(t)
    i = 0
    j = 0
    while i < m and j < n:
        if s[i] == t[j]:
            i += 1
        j += 1
    return i == m

# 动态规划(最长公共子序列,判断最长子序列长度是否等于m)
def solve(s, t):
    m, n = len(s), len(t)
    dp = [[0] * (n+1) for i in range(m+1)]
    max_len = 0
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
            max_len = max(max_len, dp[i][j])
    return max_len == m
  1. LC673:最长递增子序列个数


def solve(nums):
    n = len(nums)
    max_len = 0 # 最长长度
    ans = 0
    dp = [1] * n
    cnt = [1] * n
    for i in range(n):
        for j in range(i):
            if nums[i] > nums[j]:
                if dp[j] + 1 > dp[i]:
                    dp[i] = dp[j] + 1
                    cnt[i] = cnt[j]
                elif dp[j] + 1 == dp[i]:
                    cnt[i] += cnt[j]
        if dp[i] > max_len:
            max_len = dp[i]
            ans = cnt[i]
        elif dp[i] == max_len:
            ans += cnt[i]
    return ans
  1. LC72:编辑距离


def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m+1):
        dp[i][0] = dp[i-1][0] + 1
    for j in range(1, n + 1):
        dp[0][j] = dp[0][j-1] + 1
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j-1] + 1, dp[i][j-1] + 1, dp[i-1][j] + 1)
    return dp[m][n]
  1. 剪绳子【python--剑指offer--14- I. 剪绳子_python剪绳子问题-CSDN博客

  2. # jianshengzi
    def solve(nums):
        n = nums
        dp = [0] * (n + 1)
        dp[1], dp[2] = 1, 1
        for i in range(3, n+1):
            for j in range(i):
                dp[i] = max(dp[i], max(dp[i-j] * j, j * (i - j)))
        return dp[n]

  3. LC582:两个字符串的删除操作


# 方法1:dp
def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n+1) for i in range(m+1)]
    for i in range(1, m+1):
        dp[i][0] = dp[i-1][0] + 1
    for j in range(1, n+1):
        dp[0][j] = dp[0][j-1] + 1
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1)
    return dp[m][n]

# 方法2:最长公共子序列
def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n+1) for i in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
    max_len = dp[m][n]
    res = m - max_len + n - max_len
    return res
  1. LC115:不同子序列的个数


# 不同子序列的个数(t是s的子序列)
def solve(s, t):
    m, n = len(s), len(t)
    if m < n:
        return 0
    dp = [[0] * (n+1) for i in range(m+1)] # dp[i][j]表示s[i:]在t[j:]中不同子序列的个数
    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]
  1. LC516:最长回文子序列


def solve(s):
    n = len(s)
    dp = [[0] * n for i in range(n)] # dp[i][j]表示s中i和j之间的字符串的最长回文子序列长度
    for i in range(n-1, -1, -1):
        dp[i][i] = 1
        for j in range(i+1, n):
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1] + 2
            else:
                dp[i][j] = max(dp[i+1][j], dp[i][j-1])
    return dp[0][n-1]
  1. LC5:最长回文子串


def solve(s):
    nums = s
    n = len(nums)
    if n < 2:
        return nums
    dp = [[0] * n for i in range(n)]
    max_len = 1
    begin = 0
    for i in range(n):
        dp[i][i] = 1
    for L in range(2, n+1):
        for i in range(n):
            j = i + L - 1
            if j >= n:
                break
            if nums[i] != nums[j]:
                dp[i][j] = 0
            else:
                if j - i < 3:
                    dp[i][j] = 1
                else:
                    dp[i][j] = dp[i+1][j-1]
            if dp[i][j] and L > max_len:
                max_len = L
                begin = i
    return nums[begin:begin+max_len]
  1. LC70:爬楼梯


def solve(n):
    if n < 3:
        return n
    f0 = 1
    f1 = 2
    for i in range(3, n+1):
        fn = f0 + f1
        f0 = f1
        f1 = fn
    return fn
  1. LC746:使用最小花费爬楼梯


def solve(cost):
    n = len(cost)
    dp = [0] * (n+1)
    for i in range(2, n+1):
        dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
    return dp[n]
  1. LC121:买卖股票最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。


def solve(prices):
    minPrice = 1e20
    maxProfit = -1
    for i in range(len(prices)):
        if prices[i] < minPrice:
            minPrice = prices[i]
        maxProfit = max(maxProfit, prices[i]-minPrice)
    return maxProfit
  1. LC122:买卖股票最佳时机2

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。


def solve(prices):
    n = len(prices)
    dp = [[0] * 2 for i in range(n)]
    dp[0][0] = 0
    dp[0][1] = -prices[0]
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
        dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
    return dp[n-1][0]
  1. LC309:买卖股票最佳时机【含冷冻期】


'''
dp[i][0]:持有股票
dp[i][1]:不持有股票(不在冷冻期)
dp[i][2]:不持有股票(在冷冻期)
'''
def solve(prices):
    n = len(prices)
    dp = [[0] * 3 for i in range(n)]
    dp[0][0] = -prices[0]
    dp[0][1] = 0
    dp[0][2] = 0
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
        dp[i][1] = max(dp[i-1][1], dp[i-1][2])
        dp[i][2] = dp[i-1][0] + prices[i]
    return max(dp[n-1][1], dp[n-1][2])
  1. LC714:买卖股票最佳时机【含手续费】


'''
dp[i][0]:有股票
dp[i][1]:没有股票
'''
def solve(prices, fee):
    n = len(prices)
    dp = [[0] * 2 for i in range(n)]
    dp[0][0] = -prices[0]
    dp[0][1] = 0
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
        dp[i][1] = max(dp[i-1][0] + prices[i] - fee, dp[i-1][1])
    return dp[n-1][1]
  1. LC198:打家劫舍


def solve(nums):
    if not nums:
        return 0
    n = len(nums)
    if n == 1:
        return nums[0]
    dp = [0] * n
    dp[0] = nums[0]
    dp[1] = max(nums[0]. nums[1])
    for i in range(2, n):
        dp[i] = max(dp[i-1], dp[i-2]+nums[i])
    return dp[-1]
  1. LC337:树形打家劫舍

# 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 rob(self, root: Optional[TreeNode]) -> int:
        def dfs(root):
            if not root:
                return 0, 0
            l_rob, l_not_rob = dfs(root.left)
            r_rob, r_not_rob = dfs(root.right)
            rob = l_not_rob + r_not_rob + root.val
            not_rob = max(l_rob, l_not_rob) + max(r_rob, r_not_rob)
            return rob, not_rob
        return max(dfs(root))
  1. LC739【每日温度】

class Solution:
    def dailyTemperatures(self, nums: List[int]) -> List[int]:
        n = len(nums)
        res = [0] * n
        stack = []
        for i in range(n - 1, -1, -1):
            while stack and nums[i] >= nums[stack[-1]]:
                stack.pop()
            if stack:
                res[i] = stack[-1] - i
            stack.append(i)
        return res
  1. LC983:最低票价


def solve(days, costs):
    maxDays = days[-1]
    dp = [0] * (maxDays + 31) #防止越界
    for d in range(maxDays, -1, -1):
        if d in days:
            dp[d] = min(dp[d+1] + costs[0], dp[d+7]+costs[1], dp[d+30]+costs[2])
        else:
            dp[d] = dp[d+1]
    return dp[0]

多维动态规划

1. LC120【三角形最小路径和】

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        f = [[0] * n for i in range(n)]
        f[0][0] = triangle[0][0]
        # res = float('inf')
        for i in range(1, n):
            f[i][0] = f[i-1][0] + triangle[i][0]
            for j in range(1, i):
                f[i][j] = min(f[i-1][j-1], f[i-1][j]) + triangle[i][j]
            f[i][i] = f[i-1][i-1] + triangle[i][i]
            # res = min(res, f[i])
        return min(f[n-1])

2. LC64【最小路径和】

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m ,n = len(grid), len(grid[0])
        dp = [[0] * (n) for i in range(m)]
        dp[0][0] = grid[0][0]
        for i in range(1, m):
            dp[i][0] = dp[i-1][0] + grid[i][0]
        for j in range(1, n):
            dp[0][j] = dp[0][j-1] + grid[0][j]
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
        return dp[m-1][n-1]

3. LC62【不同路径】

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

 4、LC63【不同路径有障碍物】

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        dp = [[0] * n for i in range(m)]
        if obstacleGrid[0][0] == 1:
            dp[0][0] = 0
        else:
            dp[0][0] = 1
        for i in range(1, m):
            if obstacleGrid[i][0] == 1:
                dp[i][0] = 0
            else:
                dp[i][0] = dp[i-1][0] 
        for j in range(1, n):
            if obstacleGrid[0][j] == 1:
                dp[0][j] = 0
            else:
                dp[0][j] = dp[0][j-1]
        for i in range(1, m):
            for j in range(1, n):
                if obstacleGrid[i][j] == 1:
                    dp[i][j] = 0
                else:
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[m-1][n-1]

 5. LC221【最大正方形】

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        res = 0
        m, n = len(matrix), len(matrix[0])
        dp = [[0] * n for i in range(m)]
        for i in range(m):
            for j in range(n):
                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-1][j-1], dp[i][j-1]) + 1
                    res = max(res, dp[i][j])
        return res * res
                    

位运算、数组

  1. LC41【缺失的第一个正数】

class Solution:
    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
  1. LC151【反转字符串中的单词】

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.strip()
        left = right = len(s) - 1
        res = []
        while left >= 0:
            while left >= 0 and s[left] != ' ':
                left -= 1
            res.append(s[left + 1:right + 1])
            while left >= 0 and s[left] == ' ':
                left -= 1
                right = left
        return ' '.join(res)
  1. LC14【最长公共前缀】

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        prefix = strs[0]
        n = len(strs)
        for i in range(1, n):
            prefix = self.kernel(prefix, strs[i])
            if not prefix:
                break
        return prefix
    def kernel(self, s1, s2):
        n = min(len(s1), len(s2))
        count = 0
        while count < n and s1[count] == s2[count]:
            count += 1
        return s1[:count]
  1. LC42【接雨水】

class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        left = [0] * n
        left[0] = height[0]
        for i in range(1, n):
            left[i] = max(left[i-1], height[i])
        right = [0] * n
        right[n-1] = height[-1]
        for j in range(n-2,-1,-1):
            right[j] = max(right[j+1], height[j])
        res = 0
        for i in range(n):
            cur = min(left[i], right[i]) - height[i]
            res += cur
        return res
  1. LC135【分发糖果】

class Solution:
    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 = 0
        res = 0
        for i in range(n-1, -1, -1):
            if i < n - 1 and ratings[i] > ratings[i+1]:
                right = right + 1
            else:
                right = 1
            res = res + max(left[i], right)
        return res
  1. LC238【除自身以外数组的乘积】

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        n = len(nums)
        res1 = [1] * n
        for i in range(1, n):
            res1[i] = res1[i-1] * nums[i-1]
        res2 = [1] * n
        for i in range(n-2, -1, -1):
            res2[i] = res2[i+1] * nums[i+1]
        res = []
        for i in range(n):
            res.append(res1[i] * res2[i])
        return res
  1. LC55【跳跃游戏】

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n = len(nums)
        most = 0
        for i in range(n):
            if i <= most:
                most = max(most, i + nums[i])
                if most >= n - 1:
                    return True
        return False
  1. LC45【跳跃游戏2】

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        most = 0
        res = 0
        end = 0
        for i in range(n-1):
            if i <= most:
                most = max(most, i + nums[i])
                if i == end:
                    end = most
                    res += 1
        return res
  1. LC136:只出现一次的数字(只有一个数字出现一次,其他均出现两次)


def solve(nums):
    res = nums[0]
    n = len(nums)
    for i in range(1, n):
        res = res ^ nums[i]
    return res
  1. LC268:丢失的数字(给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。)


def solve(nums):
    ans = 0
    for i in range(len(nums)):
        ans = ans ^ nums[i]
    for i in range(len(nums)+1):
        ans = ans ^ i
#         print(i, nums[i])
#         print(ans)
    return ans
  1. LC141:环形链表


# 哈希
def solve(head):
    seen = set()
    while head:
        if head in seen:
            return True
        else:
            seen.add(head)
            head = head.next
    return False

# 快慢指针
def solve(head):
    if not head or not head.next:
        return False
    slow = head
    fast = head.next
    while slow != fast:
        if not fast or not fast.next:
            return False
        slow = slow.next
        fast = fast.next.next
    return True
  1. LC142:环形链表2【若有环,寻找环的入口】


def solve(head):
    fast, slow = head, head
    while True:
        if not fast or not fast.next:
            return None
        fast = fast.next.next
        slow = slow.next
        if fast == slow:
            break
    fast = head
    while fast != slow:
        fast = fast.next
        slow = slow.next
    return fast

数组、二分、双指针

  1. LC713【乘积小于k的子数组个数】

class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        if k <= 1:
            return 0
        target = k
        left, right = 0, 0
        n = len(nums)
        res = 0
        total = 1
        for i in range(n):
            total *= nums[right]
            while total >= target:
                total /= nums[left]
                left += 1
            res += right - left + 1
            right += 1
        return res
  1. LC209【长度最小的子数组】

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        left, right = 0, 0
        n = len(nums)
        res = n + 1
        total = 0
        while right < n:
            total += nums[right]
            while total >= target:
                res = min(res, right - left + 1)
                total -= nums[left]
                left += 1
            right += 1
        if res == n + 1:
            return 0
        else:
            return res
  1. LC15【三数之和】

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        res = []
        for k in range(n - 2):
            if nums[k] > 0:
                break
            if k > 0 and nums[k] == nums[k-1]:
                continue
            i, j = k + 1, n - 1
            while i < j:
                s = nums[i] + nums[j] + nums[k]
                if s > 0:
                    j -= 1
                    while i < j and nums[j] == nums[j+1]:
                        j -= 1
                elif s < 0:
                    i += 1
                    while i < j and nums[i] == nums[i-1]:
                        i += 1
                else:
                    res.append([nums[i], nums[j], nums[k]])
                    i += 1
                    j -= 1
                    while i < j and nums[i] == nums[i-1]:
                        i += 1
                    while i < j and nums[j] == nums[j+1]:
                        j -= 1
        return res
  1. LC11【盛水最多的容器】

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left, right = 0, len(height)-1
        res = 0
        while left < right:
            if height[left] < height[right]:
                res = max(res, height[left] * (right - left))
                left += 1
            else:
                res = max(res, height[right] * (right - left))
                right -= 1
        return res
  1. LC392【判断子序列】

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        m, n = len(s), len(t)
        i, j = 0, 0
        while i < m and j < n:
            if s[i] == t[j]:
                i += 1
                j += 1
            else:
                j += 1
        return i == m
  1. LC26:原地删除有序数组重复值


def solve(nums):
    n = len(nums)
    slow, fast = 1, 1
    while fast < n:
        if nums[fast] != nums[fast-1]:
            nums[slow] = nums[fast]
            slow += 1
        fast += 1
    return slow
  1. LC3:无重复字符的最长子串

  2. def solve(s):
        dic = set()
        right = -1
        res = 0
        n = len(s)
        for i in range(n):
            if i != 0:
                dic.remove(s[i-1])
            while (right + 1) < n and s[right+1] not in dic:
                dic.add(s[right+1])
                right += 1
            res = max(res, right - i + 1)
        return res

  3. 排序数组目标值的起始位置和结束位置

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        start = self.kernel(nums, target)
    #     print(start)
        if start == len(nums) or nums[start] != target:
        # if start == len(nums):
            return [-1, -1]
        right = self.kernel(nums, target + 1) - 1
        return [start, right]
    def kernel(self, nums, target):
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
    #         if nums[mid ] < target:
    #             left = mid + 1
    #         else:
    #             right = mid - 1
            if nums[mid ] >= target:
                right = mid - 1
            else:
                left = mid + 1
        return left
  1. 剑指11:旋转数组最小值


def solve(numbers):
    low, high = 0, len(numbers) - 1
    while low <= high:
        if numbers[low] < numbers[high]:
            return numbers[low] # 如果是有序数组 直接返回numbers[low]
        mid = (low + high) // 2
        if numbers[mid] > numbers[low]:
            low = mid + 1
        elif numbers[mid] < numbers[low]:
            high = mid
        else:
            low += 1
    return numbers[mid]
  1. LC33:搜索排序旋转数组【无重复值】


# 先寻找有序的一部分
def solve(nums, target):
    low, high = 0, len(nums) - 1
    while low <= high:
        mid = (low + high) // 2
        if nums[mid] == target:
            return mid
        if nums[mid] >= nums[low]: # 注意等号
            if target < nums[mid] and target >= nums[low]:
                high = mid - 1
            else:
                low = mid + 1
        else:
            if target > nums[mid] and target <= nums[len(nums)-1]:
                low = mid + 1
            else:
                high = mid - 1
    return -1
  1. LC81:搜索排序旋转数组【有重复值】


# 先寻找有序的一部分
def solve(nums, target):
    low, high = 0, len(nums) - 1
    while low <= high:
        mid = (low + high) // 2
        if nums[mid] == target:
            return True
        if nums[low] == nums[mid] and nums[mid] == nums[high]:
            low += 1
            high -= 1
        elif nums[mid] >= nums[low]: # 注意等号
            if target < nums[mid] and target >= nums[low]:
                high = mid - 1
            else:
                low = mid + 1
        else:
            if target > nums[mid] and target <= nums[len(nums)-1]:
                low = mid + 1
            else:
                high = mid - 1
    return False
  1. LC240:搜索二维矩阵2(行升序、列升序)


# z型搜索
def solve(matrix, target):
    row, col = len(matrix), len(matrix[0])
    x, y = 0, col-1
    while x < row and y >= 0:
        if matrix[x][y] == target:
            return True
        elif matrix[x][y] > target:
            y -= 1
        else:
            x += 1
    return False
  1. LC88:合并两个有序数组(非递减顺序)


# 双指针
def solve(nums1, m, nums2, n):
    res = []
    p1, p2 = 0, 0
    while p1 < m or p2 < n:
        if p1 == m:
            res.append(nums2[p2])
            p2 += 1
        elif p2 == n:
            res.append(nums1[p1])
            p1 += 1
        elif nums1[p1] < nums2[p2]:
            res.append(nums1[p1])
            p1 += 1
        else:
            res.append(nums2[p2])
            p2 += 1
    nums1[:] = res

滑动窗口

1、LC3【无重复字符的最长字串】

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = set()
        right = -1
        n = len(s)
        res = 0
        for i in range(n):
            if i != 0:
                dic.remove(s[i-1])
            while right + 1 < n and s[right + 1] not in dic:
                dic.add(s[right + 1])
                right += 1
            res = max(res, right - i + 1)
        return res

链表

  1. LC86【分隔链表】

# 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]:
        small_dummy, big_dummy = ListNode(), ListNode()
        small, big = small_dummy, big_dummy
        while head:
            if head.val < x:
                small.next = head
                small = small.next
            else:
                big.next = head
                big = big.next
            head = head.next
        small.next = big_dummy.next
        big.next = None
        return small_dummy.next
  1. LC82【删除排序链表的重复元素】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head:
            return head
        dummy = ListNode(0, head)
        cur = dummy
        while cur.next and cur.next.next:
            if cur.next.val == cur.next.next.val:
                x = cur.next.val
                while cur.next and cur.next.val == x:
                    cur.next = cur.next.next
            else:
                cur = cur.next
        return dummy.next
  1. LC19【删除链表的倒数第N个节点】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(next = head)
        cur = dummy
        cur1 = head
        k = 0
        while cur1:
            k += 1
            cur1 = cur1.next
        # cur = dummy/
        for i in range(1, k - n + 1):
            cur = cur.next
        cur.next = cur.next.next
        return dummy.next
  1. LC2【两数相加】

# 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]:
        cur = dummy = ListNode(0)
        carry = 0
        while l1 or l2 or carry:
            carry += (l1.val if l1 else 0) + (l2.val if l2 else 0)
            cur.next = ListNode(carry % 10)
            carry //= 10
            cur = cur.next
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        return dummy.next
  1. LC25【k个一组反转链表】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        n = 0
        cur = head
        while cur:
            n += 1
            cur = cur.next
        p0 = dummy = ListNode(next = head)
        cur, pre = head, None
        while n >= k:
            n -= k
            for i in range(k):
                tmp = cur.next
                cur.next = pre
                pre = cur
                cur = tmp
            tmp = p0.next
            tmp.next = cur
            p0.next = pre
            p0 = tmp
        return dummy.next
  1. LC206【反转链表】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur, pre = head, None
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
  1. LC92【反转链表2】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
        p0 = dummy = ListNode(next = head)
        for _ in range(left - 1):
            p0 = p0.next
        pre = None
        cur = p0.next
        for _ in range(right - left + 1):
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        '''
        比如(例子1)原来1后连着2(1->next=2),现在2到后面去了,我想要2连着5,那就是2->next=5,合起来就是1->next->next=5。第二句是1后连着4,也就是当前的pre位置
        '''
        p0.next.next = cur
        p0.next = pre
        return dummy.next
  1. LC21:合并两个有序链表


# 递归
def solve(list1, list2):
    if list1 is None:
        return list2
    elif list2 is None:
        return list1
    elif list1.val < list2.val:
        list1.next = solve(list1.next, list2)
        return list1
    else:
        list2.next = solve(list1, list2.next)
        return list2

# 迭代
def solve(list1, list2):
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next
  1. LC148:排序链表


# 归并法 递归
def solve(head):
    def sortKernel(head, tail):
        if not head:
            return head
        if head.next == tail:
            head.next = None
            return head
        slow = fast = head # 寻找中点
        while fast != tail:
            slow = slow.next
            fast = fast.next
            if fast != tail:
                fast = fast.next
        mid = slow
        return merge(sortKernel(head, mid), sortKernel(mid, tail))
    def merge(list1, list2):
        prehead = ListNode(-1)
        prev = prehead
        while list1 and list2:
            if list1.val <= list2.val:
                prev.next = list1
                list1 = list1.next
            else:
                prev.next = list2
                list2 = list2.next
            prev = prev.next
        if not list1:
            prev.next = list2
        if not list2:
            prev.next = list1
        return prehead.next
    return sortKernel(head, None)
  1. LC23:合并k个有序链表


# 暴力 顺序合并 时间复杂度O(K^2*n)
def solve(lists):
    ans = None
    for i in range(len(lists)):
        ans = kernel(ans, lists[i])
    return ans
def kernel(list1, list2):
    if list1 is None:
        return list2
    if list2 is None:
        return list1
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next

# 分治合并
def solve(lists):
    return merge(lists, 0, len(lists)-1)

def merge(lists, left, right):
    if left == right:
        return lists[left]
    if left > right:
        return None
    mid = (left + right) // 2
    return kernel(merge(lists, left, mid), merge(lists, mid+1, right))
def kernel(list1, list2):
    if list1 is None:
        return list2
    if list2 is None:
        return list1
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next
        
  1. LC19【删除倒数第k个链表】

  2. # shanchudaoshudikgejiedian
    def solve(head, n):
        dummy = ListNode(0, head)
        first = head
        second = dummy
        for i in range(n):
            first = first.next
        while first:
            first = first.next
            second = second.next
        second.next = second.next.next
        return dummy.next

  3. LC160:相交链表


#空间复杂度o(m),m为headA长度
def solve(headA, headB):
    seen = set()
    while headA:
        seen.add(headA)
        headA = headA.next
    while headB:
        if headB in seen:
            return headB
        headB = headB.next
    return None

# 空间复杂度o(1)
def solve(headA, headB):
    if headA is None or headB is None:
        return None
    pa, pb = headA, headB
    while pa != pb:
        if pa is not None:
            pa = pa.next
        else:
            pa = headB
        if pb is not None:
            pb = pb.next
        else:
            pb = headA
    return pa

深度优先、广度优先、并查集

  1. LC200:岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。


# 深度优先
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    res = 0
    for x in range(row):
        for y in range(col):
            if grid[x][y] == '1':
                res += 1
                dfs(grid, x, y)
    return res

def dfs(grid, x, y):
    grid[x][y] = 0
    row = len(grid)
    col = len(grid[0])
    for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
#         print(i, j)
        if i >= 0  and i < row and j >= 0 and j < col and grid[i][j] == '1': # 注意grid[i][j] == '1'的判断要放到最后, 否则数组越界
            dfs(grid, i, j)

# 广度优先
import collections
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    res = 0
    for x in range(row):
        for y in range(col):
            if grid[x][y] == '1':
                res += 1
                grid[x][y] = '0'
                neighbours = collections.deque([(x, y)])
                while neighbours:
                    r, c = neighbours.popleft()
                    for i, j in ([r-1, c], [r+1, c], [r, c-1], [r, c+1]):
                        if i >= 0 and i < row and j >= 0 and j < col and grid[i][j] == '1':
                            grid[i][j] = '0'
                            neighbours.append([i, j])
    return res
  1. LC130:被围绕的区域


# 深度优先
def solve(board):
    row = len(board)
    col = len(board[0])
    def dfs(x, y):
        if not (x >= 0 and x < row) or not(y >= 0 and y < col) 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(row):
        dfs(i, 0)
        dfs(i, col-1)
    for i in range(col-1):
        dfs(0, i)
        dfs(row-1, i)
    for i in range(row):
        for j in range(col):
            if board[i][j] == 'A':
                board[i][j] = 'O'
            elif board[i][j] == 'O':
                board[i][j] = 'X'
                

# 广度优先
def solve(board):
    row, col = len(board), len(board[0])
    quene = collections.deque()
    for i in range(row):
        if board[i][0] == 'O':
            board[i][0] = 'A'
            quene.append((i, 0))
        if board[i][col-1] == 'O':
            board[i][col-1] = 'A'
            quene.append((i, col-1))
    for i in range(col):
        if board[0][i] == 'O':
            board[0][i] = 'A'
            quene.append((0, i))
        if board[row-1][i] == 'O':
            board[row-1][i] = 'A'
            quene.append((row-1, i))
    while quene:
        x, y = quene.popleft()
        for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
            if i >= 0 and i < row and j >= 0 and j < col and board[i][j] == 'O':
                board[i][j] = 'A'
                quene.append((i, j))
    for i in range(row):
        for j in range(col):
            if board[i][j] == 'A':
                board[i][j] = 'O'
            elif board[i][j] == 'O':
                board[i][j] = 'X'
  1. LC695:岛屿最大面积


# 深度优先
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            ans = max(dfs(grid, i, j), ans)
    return ans
def dfs(grid, x, y):
    row, col = len(grid), len(grid[0])
    if x < 0 or y < 0 or x == row or y == col or grid[x][y] != 1:
        return 0
    grid[x][y] = 0
    ans = 1
    for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
        ans += dfs(grid, i, j)
    return ans

# 广度优先
# 广度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            cur = 0
            quene = collections.deque([(i, j)])
            while quene:
                x, y = quene.popleft()
                if x < 0 or x == row or y < 0 or y == col or grid[x][y] != 1:
                    continue
                grid[x][y] = 0
                cur += 1
                for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
                    quene.append([tmp_x, tmp_y])
            ans = max(ans, cur)
    return ans
  1. LC463:岛屿的周长(只有一个岛屿)


# 深度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            if grid[i][j] == 1:
                ans += dfs(i, j, grid)
    return ans
def dfs(i, j, grid):
    row, col = len(grid), len(grid[0])
    if i < 0 or i == row or j < 0 or j == col or grid[i][j] == 0:
        return 1
    if grid[i][j] == 2:
        return 0
    grid[i][j] = 2
    ans = 0
    for x, y in [(i-1, j),(i+1, j), (i, j-1), (i, j+1)]:
        ans += dfs(x, y, grid)
    return ans

# 广度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            if grid[i][j] == 1:
                cur = 0
                quene = collections.deque([(i, j)])
                while quene:
                    x, y = quene.popleft()
                    grid[x][y] = 2
                    for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
                        if tmp_x < 0 or tmp_x == row or tmp_y < 0 or tmp_y == col or grid[tmp_x][tmp_y] == 0:
                            cur += 1
                        elif grid[tmp_x][tmp_y] == 1:
                            grid[tmp_x][tmp_y] = 2
                            quene.append([tmp_x, tmp_y])
                ans += cur
                return ans
  1. LC102:二叉树的层序遍历


# bfs
def solve(root):
    if not root:
        return []
    res = []
    quene = [root]
    while quene:
        size = len(quene)
        tmp = []
        for i in range(size):
            r = quene.pop(0)
            tmp.append(r.val)
            if r.left:
                quene.append(r.left)
            if r.right:
                quene.append(r.right)
        res.append(tmp)
    return res

# dfs
def solve(root):
    if not root:
        return []
    res = []
    def dfs(index, r):
        if len(res) < index:
            res.append([])
        res[index-1].append(r.val)
        if r.left:
            dfs(index+1, r.left)
        if r.right:
            dfs(index+1, r.right)
    dfs(1, root)
    return res
  1. LC103:二叉树锯齿形遍历


# bfs
def solve(root):
    if not root:
        return []
    res = []
    quene = [root]
    flag = 1
    while quene:
        size = len(quene)
        tmp = []
        for i in range(size):
            r = quene.pop(0)
            tmp.append(r.val)
            if r.left:
                quene.append(r.left)
            if r.right:
                quene.append(r.right)
        if flag:
            res.append(tmp)
            flag = 0
        else:
            res.append(tmp[::-1])
            flag = 1
    return res
  1. LC297:二叉树序列化反序列化


# bfs
class Solve:
    def serialize(self, root):
        if not root:
            return ''
        quene = [root]
        res = []
        while quene:
            node = quene.pop(0)
            if node:
                res.append(str(node.val))
                quene.append(node.left)
                quene.append(node.right)
            else:
                res.append('null')
        return '[' + ','.join(res) + ']'
    def deserialize(self, data):
        if not data:
            return []
        lst = data[1:-1].strip().split(',')
        root = TreeNode(int(lst[0]))
        quene = [root]
        i = 1
        while quene:
            node = quene.pop(0)
            if lst[i] != 'null':
                node.left = TreeNode(int(lst[i]))
                quene.append(node.left)
            i += 1
            if lst[i] != 'null':
                node.right = TreeNode(int(lst[i]))
                quene.append(node.right)
            i += 1
        return root

# dfs
class Solve:
    def serialize(self, root):
        if not root:
            return 'null'
        return str(root.val) + ',' + str(self.serialize(root.left)) + ',' + str(self.serialize(root.right))
    def deserialize(self, data):
        def dfs(lst):
            val = lst.pop(0)
            if val == 'null':
                return None
            root = TreeNode(int(val))
            root.left = dfs(lst)
            root.right = dfs(lst)
            return root
        lst = data.strip().split(',')
        return dfs(lst)

排序

  1. 山峰数组最大值索引


class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        n = len(nums)
        left, right = 0, len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] > nums[mid + 1]:
                right = mid
            else:
                left = mid + 1
        return right
# shanfengshuzu
def solve(nums):
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] > nums[mid + 1]:
            right = mid - 1
        else:
            left = mid + 1
    return left

 

  1. LC215:数组中第k大元素


# 快排 (时间复杂度期望为o(n))
def solve(nums, k):
    k = len(nums) - k
    start = 0
    end = len(nums) - 1
    while True:
        loc = quickKernel(nums, start, end)
        if loc == k:
            return nums[loc]
        elif loc < k:
            start = loc + 1
        else:
            end = loc - 1
def quickKernel(nums, start, end):
    low = start
    high = end
    base = nums[start]
    while low < high:
        while low < high and nums[high] >= base:
            high -= 1
        nums[low] = nums[high]
        while low < high and nums[low] < base:
            low += 1
        nums[high] = nums[low]
    nums[low] = base
    return low
    

def solve(nums, k):
    n = len(nums)
    build_heap(nums, n)
    for i in range(n-1, n-k-1, -1):
        nums[i], nums[0] = nums[0], nums[i]
        heapify(nums, i, 0)
    return nums[n-k]
def build_heap(nums, n):
    i = n // 2
    while i >= 0:
        heapify(nums, n, i)
        i -= 1
def heapify(nums, n, i):
    left = 2 * i
    right = 2 * i + 1
    largest = i
    if left < n and nums[left] > nums[i]:
        largest = left
    if right < n and nums[right] > nums[largest]:
        largest = right
    if largest != i:
        nums[largest], nums[i] = nums[i], nums[largest]
        heapify(nums, n, largest)
  1. 快排


def quickSort(nums, low, high):
    if low >= high:
        return nums
    loc = kernel(nums, low, high)
    quickSort(nums, low, loc-1)
    quickSort(nums, loc+1, high)
def kernel(nums, start, end):
    low = start
    high = end
    base = nums[start]
    while low < high:
        while low < high and nums[high] >= base:
            high -= 1
        nums[low] = nums[high]
        while low < high and nums[low] <= base:
            low += 1
        nums[high] = nums[low]
    nums[low] = base
    return low
  1. 剑指offer40:最小的k个数


# 快排 (时间复杂度期望为o(n))
def quickSort_kernel(arr, start, end):
#     if start > end:
#         return
    base = arr[start]
    low = start
    high = end
    while low < high:
        while low < high and arr[high] >= base: # 若是最大的改这里
            high -= 1
        arr[low] = arr[high]
        while low < high and arr[low] <= base: # 若是最大的改这里
            low += 1
        arr[high] = arr[low]
    arr[low] = base
    return low
def solve(arr, k):
    if k > len(arr) or k <= 0:
        return []
    start = 0
    end = len(arr) - 1
    loc = quickSort_kernel(arr, start, end)
    while loc != k-1:
#         loc = quickSort_kernel(arr, start, end)
        if loc > k - 1:
            end = loc - 1
        else:
            start = loc + 1
        loc = quickSort_kernel(arr, start, end)
    return arr[:k]

# 堆排序
def getLeastNumbers(arr,k):
    if k == 0 or k > len(arr) or k < 0:
        return []
    data = arr[:k]
    build_heap(data,len(data))  ##实现
    for each in arr[k:]:
        if data[0] > each:
            data[0] = each
            heapify(data,len(data),0)
    return data
def build_heap(arr,n):
    i = n // 2
    while i >= 0:
        heapify(arr,n,i)
        i -= 1
def heapify(arr,n,i):
    left = 2 * i
    right = 2 * i + 1
    largest = i
    if left < n and arr[left] > arr[i]:
        largest = left
    if right < n and arr[right] > arr[largest]:
        largest = right
    if largest != i:
        arr[i],arr[largest] = arr[largest],arr[i]
        heapify(arr,n,largest)
  1. LC703:数据流中第k大元素


class Heap:
    def __init__(self,desc=False):
        """
        初始化,默认创建一个小顶堆
        """
        self.heap = []
        self.desc = desc
    
    @property
    def size(self):
        return len(self.heap)
    
    def top(self):
        if self.size:
            return self.heap[0]
        return None
    
    def push(self,item):
        """
        添加元素
        第一步,把元素加入到数组末尾
        第二步,把末尾元素向上调整
        """
        self.heap.append(item)
        self._sift_up(self.size-1)
    
    def pop(self):
        """
        弹出堆顶
        第一步,记录堆顶元素的值
        第二步,交换堆顶元素与末尾元素
        第三步,删除数组末尾元素
        第四步,新的堆顶元素向下调整
        第五步,返回答案
        """
        item = self.heap[0]
        self._swap(0,self.size-1)
        self.heap.pop()
        self._sift_down(0)
        return item
    
    def _smaller(self,lhs,rhs):
        return lhs > rhs if self.desc else lhs < rhs
    
    def _sift_up(self,index):
        """
        向上调整
        如果父节点和当前节点满足交换的关系
        (对于小顶堆是父节点元素更大,对于大顶堆是父节点更小),
        则持续将当前节点向上调整
        """
        while index:
            parent = (index-1) // 2
            
            if self._smaller(self.heap[parent],self.heap[index]):
                break
                
            self._swap(parent,index)
            index = parent
    
    def _sift_down(self,index):
        """
        向下调整
        如果子节点和当前节点满足交换的关系
        (对于小顶堆是子节点元素更小,对于大顶堆是子节点更大),
        则持续将当前节点向下调整
        """
        # 若存在子节点
        while index*2+1 < self.size:
            smallest = index
            left = index*2+1
            right = index*2+2
            
            if self._smaller(self.heap[left],self.heap[smallest]):
                smallest = left
                
            if right < self.size and self._smaller(self.heap[right],self.heap[smallest]):
                smallest = right
                
            if smallest == index:
                break
            
            self._swap(index,smallest)
            index = smallest
    
    def _swap(self,i,j):
        self.heap[i],self.heap[j] = self.heap[j],self.heap[i]

class KthLargest:

    def __init__(self, k: int, nums: List[int]):
        self.heap = Heap()
        self.k = k
        for num in nums:
            self.heap.push(num)
            if self.heap.size > k:
                self.heap.pop()


    def add(self, val: int) -> int:
        self.heap.push(val)
        if self.heap.size > self.k:
            self.heap.pop()
        return self.heap.top()
  1. LC414:第三大的数


# a最大 b次大 c第三大
def solve(nums):
    a, b, c = float('-inf'), float('-inf'), float('-inf')
    for each in nums:
        if each > a:
            a, b, c = each, a, b
        elif each > b and each < a:
            b, c = each, b
        elif each > c and each < b:
            c = each
    if c == float('-inf'):
        return a
    else:
        return c
  1. LC4:两个正序数组的中位数


def solve(nums1, nums2):
    def kernel(k):
        index1, index2 = 0, 0
        while True:
            if index1 == m:
                return nums2[index2+k-1]
            if index2 == n:
                return nums1[index1+k-1]
            if k == 1:
                return min(nums1[index1], nums2[index2])
            
            newIndex1 = min(index1 + k//2 -1, m-1)
            newIndex2 = min(index2 + k//2 -1, n-1)
            pivot1, pivot2 = nums1[newIndex1], nums2[newIndex2]
            if pivot1 <= pivot2:
                k = k - (newIndex1 - index1 + 1)
                index1 = newIndex1 + 1
            else:
                k = k- (newIndex2 - index2 + 1)
                index2 = newIndex2 + 1
    m, n = len(nums1), len(nums2)
    totalLength = m + n
    if totalLength % 2 == 1:
        return kernel((totalLength+1)//2)
    else:
        return (kernel(totalLength//2) + kernel(totalLength//2+1)) / 2

回溯

  1. LC79【单词搜索】

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m, n = len(board), len(board[0])
        def dfs(i, j, k):
            if not 0 <= i < m or not 0 <= j < n or board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True
            board[i][j] = ''
            res = dfs(i+1, j, k+1) or dfs(i-1, j, k+1) or dfs(i, j+1, k+1) or dfs(i, j-1, k+1)
            board[i][j] = word[k]
            return res
        for i in range(m):
            for j in range(n):
                if dfs(i, j, 0):
                    return True
        return False
  1. LC46:全排列【不包含重复数字】


# 回溯
def solve(nums):
    n = len(nums)
    res = []
    def back(first):
        if first == n:
            res.append(nums[:])
        for i in range(first, n):
            nums[i], nums[first] = nums[first], nums[i]
            back(first+1)
            nums[i], nums[first] = nums[first], nums[i]
    back(0)
    return res
  1. LC47:全排列2【包含重复数字】


# 回溯2【含重复数字】
def solve(nums):
    res = []
    n = len(nums)
    used = [0] * n
    def back(nums, used, path):
        if len(path) == n:
            res.append(path[:])
#             return
        for i in range(n):
            if not used[i]:
                if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
                    continue
                used[i] = 1
                path.append(nums[i])
                back(nums, used, path)
                used[i] = 0
                path.pop()
    back(sorted(nums), used, [])
    return res
  1. LC77:组合

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


def solve(n, k):
    res = []
    path = []
    def back(i):
        d = k - len(path)
        if d == 0:
            res.append(path[:])
            return
        for j in range(i, d-1, -1):
            path.append(j)
            back(j-1)
            path.pop()
    back(n)
    return res
  1. LC77:组合

  2. # zuhe
    def solve(nums, k):
        res, path = [], [] 
        n = len(nums)
        def back(i):
            d = k - len(path)
            if d == 0:
                res.append(path[:])
                return
            for j in range(i, d-1, -1):
                path.append(nums[j-1])
                back(j-1)
                path.pop()
        back(n)
        return res

  3. LC39:组合总和


def solve(candidates, target):
    res = []
    n = len(candidates)
    path = []
    def back(begin, target):
        if target < 0:
            return
        if target == 0:
            res.append(path[:])
            return
        for i in range(begin, n):
            target -= candidates[i]
            path.append(candidates[i])
            back(i, target)
            target += candidates[i]
            path.pop()
    back(0, target)
    return res

def solve(candidates, target):
    res, path = [], []
    dfs(candidates, target, 0, res, path)
    return res
def dfs(nums, target, index, res, path):
    if target < 0:
        return
    if target == 0:
        res.append(path[:])
        return
    for i in range(index, len(nums)):
        dfs(nums, target-nums[i], i, res, path+[nums[i]])
  1. LC90:子集2【可能含有重复值】

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


def solve(nums, target):
    res, path = [], []
    nums.sort() # 不sort的话会有重复值
    dfs(nums, 0, res, path, target)
    return res
def dfs(nums, index, res, path, target):
    if sum(path[:]) == target:
        res.append(path[:])
    for i in range(index, len(nums)):
        if i > index and nums[i] == nums[i-1]:
            continue
        path.append(nums[i])
        dfs(nums, i+1, res, path, target)
        path.pop()
        
  1. LC:112路径总和


# 递归
def solve(root, target):
    if not root:
        return False
    if not root.left and not root.right:
        return root.val == target
    return solve(root.left, target-root.val) or solve(root.right, target-root.val)

# 回溯
def solve(root, target):
    if not root:
        return False
    res = []
    return dfs(root, target, res, [root.val])
def dfs(root, target, res, path):
    if not root:
        return False
    if sum(path) == target and not root.left and not root.right:
        return True
    left_flag, right_flag = False, False
    if root.left:
        left_flag = dfs(root.left, target, res, path+[root.left.val])
    if root.right:
        right_flag = dfs(root.right, target, res, path+[root.right.val])
    return left_flag or right_flag
  1. LC113:路径总和2


def solve(root, target):
    res = []
    path = []
    dfs(root, target, res, path)
    return res
def dfs(root, target, res, path):
    if not root:
        return
    path.append(root.val)
    target = target - root.val
    if not root.left and not root.right and target == 0:
        res.append(path[:])
    dfs(root.left, target, res, path)
    dfs(root.right, target, res, path)
    path.pop()

二叉树

  1. LC124【二叉树的最大路径和】

# 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 maxPathSum(self, root: Optional[TreeNode]) -> int:
        ans = float('-inf')
        def dfs(root):
            nonlocal ans
            if not root:
                return 0
            left = dfs(root.left)
            right = dfs(root.right)
            ans = max(ans, left + right + root.val)
            return max(max(left, right) + root.val, 0)
        dfs(root)
        return ans
  1. LC236:二叉树的最近公共祖先


def solve(root, p, q):
    if not root or root == p or root == q:
        return root
    left = solve(root.left, p, q)
    right = solve(root.right, p, q)
    if not left:
        return right
    if not right:
        return left
    return root
  1. LC235:二叉搜索树的最近公共祖先


def solve(root, p, q):
    res = root
    while True:
        if p.val < res.val and q.val < res.val:
            res = res.left
        elif p.val > res.val and q.val > res.val:
            res = res.right
        else:
            break
    return res
  1. LC94:二叉树的中序遍历


# 递归
def solve(root):
    res = []
    def dfs(root):
        if not root:
            return None
        dfs(root.left)
        res.append(root.val)
        dfs(root.right)
    dfs(root)
    return res

# 迭代
def solve(root):
    res = []
    quene = []
    while quene or root:
        while root:
            quene.append(root)
            root = root.left
        root = quene.pop()
        res.append(root.val)
        root = root.right
    return res
        

  1. LC433【最小基因变化】

class Solution:
    def minMutation(self, startGene: str, endGene: str, bank: List[str]) -> int:
        if startGene == endGene:
            return 0
        bank = set(bank)
        if endGene not in bank:
            return -1
        quene = [(startGene, 0)]
        while quene:
            cur, step = quene.pop(0)
            for i, x in enumerate(cur):
                for y in 'ACGT':
                    if y != x:
                        nxt = cur[:i] + y + cur[i+1:]
                        if nxt in bank:
                            if nxt == endGene:
                                return step + 1
                            bank.remove(nxt)
                            quene.append((nxt, step+1))
        return -1
  1. LC210【课程表2】

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        edges = collections.defaultdict(list)
        visited = [0] * numCourses
        result = []
        valid = True
        for each in prerequisites:
            edges[each[1]].append(each[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 []
        return result[::-1]
  1. LC207【课程表】

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        edges = collections.defaultdict(list)
        visited = [0] * numCourses
        result = []
        valid = True
        for each in prerequisites:
            edges[each[1]].append(each[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)
        return valid
  1. LC130【被围绕的区域】

class Solution:
    def solve(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        row, col = len(board), len(board[0])
        def dfs(i, j):
            board[i][j] = 'B'
            for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
                if 0 < x < row and 0 < y < col and board[x][y] == 'O':
                    dfs(x, y)
        for i in range(col):
            if board[0][i] == 'O':
                dfs(0, i)
            if board[row-1][i] == 'O':
                dfs(row-1, i)
        for i in range(row):
            if board[i][0] == 'O':
                dfs(i, 0)
            if board[i][col-1] == "O":
                dfs(i, col-1)
        for i in range(row):
            for j in range(col):
                if board[i][j] == 'O':
                    board[i][j] = 'X'
                if board[i][j] == 'B':
                    board[i][j] = "O"
                

  1. LC797:所有可能路径


def solve(graph):
    path = []
    res = []
    def back(x):
        if x == len(graph) - 1:
            res.append(path[:])
        for y in graph[x]:
            path.append(y)
            back(y)
            path.pop()
    path.append(0)
    back(0)
    return res
  1. LC210、LC207 课程表


def solve(num, condition):
    edges = collections.defaultdict(list)
    visited = [0] * num
    valid = True
    result = []
    for info in condition:
        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(num):
        if valid and not visited[i]:
            dfs(i)
    if not valid:
        res = []
    else:
        res = result[::-1]
    return res, valid
  1. LC1514:概率最大的路径【无向加权图】


def solve(n, edges, succProb, start, end):
    graph = collections.defaultdict(list)
    for i, (x, y) in enumerate(edges):
        graph[x].append((succProb[i], y))
        graph[y].append((succProb[i], x))
    quene = [(-1.0, start)]
    prob = [0.0] * n
    prob[start] = 1.0
    while quene:
        p, node = quene.pop(0)
        p = -p
        if p < prob[node]:
            continue
        for p_next, node_next in graph[node]:
            if prob[node_next] < prob[node] * p_next:
                prob[node_next] = prob[node] * p_next
                quene.append((-prob[node_next], node_next))
    return prob[end]
  1. LC1971:寻找图中是否存在路径


def solve(n, edges, source, destination):
    graph = [[] * n for i in range(n)]
    for edge in edges:
        x, y = edge[0], edge[1]
        graph[x].append(y)
        graph[y].append(x)
    visited = [0] * n
    quene = [source]
    visited[source] = 1
    while quene:
        node = quene.pop(0)
        if node == destination:
            break
        for each in graph[node]:
            if not visited[each]:
                quene.append(each)
                visited[each] = 1
    if visited[destination] == 1:
            res = True
        else:
            res = False
    return res
    

哈希表

1、LC128【最长连续序列】

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        n = len(nums)
        dic = set(nums)
        res = 0
        for each in nums:
            if each - 1 not in dic:
                cur_len = 1
                while (each + 1) in dic:
                    cur_len += 1
                    each += 1
                res = max(res, cur_len)
        return res

区间

1、LC228【汇总区间】

class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        res = []
        i = 0
        n = len(nums)
        while i < n:
            start = i
            while i < n - 1 and nums[i] + 1 == nums[i+1]:
                i += 1
            s = str(nums[start])
            if start < i:
                s += '->' + str(nums[i])
            res.append(s)
            i += 1
        return res

2、LC56【合并区间】

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key = lambda x:x[0])
        n = len(intervals)
        i = 0
        res = []
        while i < n:
            left, right = intervals[i]
            while i < n - 1 and right >= intervals[i + 1][0]:
                right = max(right, intervals[i + 1][1])
                i += 1
            res.append([left, right])
            i += 1
        return res

 3、LC57【插入区间】

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        res = []
        n = len(intervals)
        start, end = newInterval
        i = 0
        while i < n and intervals[i][1] < start:
            res.append(intervals[i])
            i += 1
        while i < n and intervals[i][0] <= end:
            start = min(start, intervals[i][0])
            end = max(end, intervals[i][1])
            i += 1
        res.append([start, end])
        while i < n:
            res.append(intervals[i])
            i += 1
        return res

 4、LC452【最少数量的箭射气球】

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        points.sort(key = lambda x:x[1])
        pos = points[0][1]
        res = 1
        for each in points:
            if each[0] > pos:
                pos = each[1]
                res += 1
        return res

分治

1. LC108【将有序数组转换为二叉搜索树】

# 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 sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        return self.kernel(nums, 0, len(nums) - 1)
    def kernel(self, nums, left, right):
        if left > right:
            return None
        mid = (left + right) // 2
        res = TreeNode(nums[mid])
        res.left = self.kernel(nums, left, mid - 1)
        res.right = self.kernel(nums, mid + 1, right)
        return res

二分法

1. LC35【搜索插入位置】

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        res = n
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] >= target:
                right = mid - 1
                res = mid
            else:
                left = mid + 1
        return res

2. LC74【搜索二维矩阵】

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

3. LC34【在排序数组中查找元素的起始和结束位置】

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def findLeft(nums, target):
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] == target:
                    if mid == 0 or nums[mid - 1] < target:
                        return mid
                    else:
                        right = mid - 1
                elif nums[mid] > target:
                    right = mid - 1
                else:
                    left = mid + 1
            return -1
        def findright(nums, target):
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] == target:
                    if mid == len(nums) - 1 or nums[mid + 1] > target:
                        return mid
                    else:
                        left = mid + 1
                elif nums[mid] > target:
                    right = mid - 1
                else:
                    left = mid + 1
            return -1
        return [findLeft(nums, target), findright(nums, target)]

数学

1. LC50【x的指数幂】

class Solution:
    def myPow(self, x: float, n: int) -> float:
        def kernel(N):
            if N == 0:
                return 1
            y = kernel(N // 2)
            return y * y if N % 2 == 0 else y * y * x
        return kernel(n) if n >= 0 else 1 / kernel(-n)
         

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值