leetcode hot100 python实现

leetcode hot100 python实现

  • leetcode hot100 python实现
    • 平衡二叉树
    • 验证二叉搜索树
    • 从前序和中序遍历中构建二叉树
    • 路径总和
    • 全排列
    • 电话号码的字母组合
    • 组合总和
    • 括号生成
    • 单词搜索
    • 分割回文字符串
    • 搜索插入位置
    • 搜索二维矩阵
    • 路径总和
    • 二叉树的最近公共祖先
    • 岛屿数量
    • 腐烂的橘子
    • 课程表
    • 实现Trie前缀树
    • 在排序数组中找第一个和最后一个元素
    • 搜索旋转排序数组
    • 寻找旋转排序数组的最小值
    • 有效的括号
    • 最小栈
    • 每日温度
    • 买卖股票的最佳时机
    • 划分字母
    • 爬楼梯
    • 杨辉三角
    • 打家劫舍
    • 完全平方和
    • 乘积最大值
    • 分割等和子集
    • 零钱兑换
    • 不同路径
    • 最小路径和
    • 只出现一次的数字
    • 颜色分类
    • 最长回文字符串
    • 最长公共子序列
    • 编辑距离
    • 字符串解码
    • 组合总和,回溯思想
  • Definition for singly-linked list.
  • class ListNode:
  • def __init__(self, val=0, next=None):
  • self.val = val
  • self.next = next
  • Definition for singly-linked list.
  • class ListNode:
  • def __init__(self, val=0, next=None):
  • self.val = val
  • self.next = next
  • 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
  • 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

leetcode hot100 python实现

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

平衡二叉树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。
首先找到中间位置数据作为根节点,然后左边数组构建左子树,右边数组构建右子树,
通过递归调用就能实现

# 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]:
        if not nums:
            return 

        n = len(nums)
        mid = n//2

        root = TreeNode(val=nums[mid])
        root.left = self.sortedArrayToBST(nums[:mid])
        root.right = self.sortedArrayToBST(nums[mid+1:])

        return root
        

验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左
子树
只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:

        def isValidBSTnode(node,low=float('-inf'),high=float('inf')):
            if not node:
                return True
            
            val = node.val
            if val<low or val>high:
                return False

            return isValidBSTnode(node.left,low,val) and isValidBSTnode(node.right,val,high)


        return isValidBSTnode(root)

从前序和中序遍历中构建二叉树

题目:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

思路:根据preorder[0]找到根节点的数值,然后根据inorder确定根节点的位置,最后就可以知道两个数组中左右子树的索引。通过递归构建树

知识点
#获取inorder数组中数值root_val的index
index_in_inorder = inorder.index(root_val)

index_in_inorder就是左子树的长度

# 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, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        def buildTreesub(preorder,inorder):
            if not preorder or not inorder:
                return 
            rootval = preorder[0]
            node = TreeNode(val=rootval)

            index_in_inorder = inorder.index(rootval)

            node.left = buildTreesub(preorder[1:index_in_inorder+1],inorder[:index_in_inorder])
            node.right = buildTreesub(preorder[index_in_inorder+1:],inorder[index_in_inorder+1:])
            return node

        res = buildTreesub(preorder,inorder)
        return res

路径总和

知识点
prefix_sums.get(current_sum, 0)意思是从prefix_sums字典中获取current_sum索引的值,如果没有该索引则返回0

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

全排列

回溯算法
注意
current_list[:] 添加list的时候是创建该list的副本,避免修改原始list,

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        n=len(nums)

        def backtrack(index,current_list):
            if index==len(nums):
                res.append(current_list[:])
            for i in range(n):
                if nums[i] not in current_list:
                    current_list.append(nums[i])
                    backtrack(index+1,current_list)
                    current_list.pop()

        backtrack(0,[])
        return res
        

电话号码的字母组合

题目:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
思路:回溯法,遍历digit第一个数字的字母,添加到path中,然后调用回溯函数遍历下一个字母。边界条件:digit为空时,将结果添加到res中
注意:
return res if digits else []
假如digits为空,res是[‘’],因此这一段添加了条件判断

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        string = ['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
        res = []
        path = []
        def backtracking(digits):
            if not digits:
                res.append(''.join(path))
                return
            index = int(digits[0])-2
            for i in string[index]:
                path.append(i)
                backtracking(digits[1:])
                path.pop()

        backtracking(digits)
        return res if digits else []

组合总和

题目:给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

思路:从index之后尝试逐个添加元素到组合中,同时维护路径,判断有无达到目标值。

注意:candidates.sort()这段代码能提前剪枝,并且避免重复组合

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        n = len(candidates)
        candidates.sort() #提前排序
        path = []

        def backtracking(target,index):
            if 0 == target:
                res.append(path.copy())
            for i in range(index,n):
                if candidates[i]>target:
                    return
                path.append(candidates[i])
                backtracking(target-candidates[i],i)
                path.pop()
        backtracking(target,0)
        return res

括号生成

题目:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
思路:定义一个left和right维护左右括号的数量,当left数量小于n时,添加左括号,当right数量小于left时,添加右括号。
注意:string对象添加字符串是用"+"操作

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        path = ""
        res = []

        def backtracking(path,left,right):
            if len(path)==2*n: 
                res.append(path)
            if left<n:
                backtracking(path+'(',left+1,right)
            if right<left:
                backtracking(path+')',left,right+1)

        backtracking("",0,0)
        return res

单词搜索

题目:给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

思路:
定义一个dfs
通过i,j,k来维护matrix行,列和word元素索引,当i j超出边界或者matrx和word当前元素不匹配返回False;
当k为word最后一个索引则返回True;
标记matrix当前元素,获取下一个方向的结果res,回溯matrix当前元素,返回res

遍历matrix所有元素,如果有满足条件的情况则返回True,如果都没有则返回False

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m=len(board)  #imax
        n=len(board[0]) #jmax
        def dfs(i,j,k):
            if not 0<=i<=m-1 or not 0<=j<=n-1 or not word[k]==board[i][j]:
                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

分割回文字符串

题目:给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是
回文串。返回 s 所有可能的分割方案。
思路:用start变量表示子串的初始位置,end表示子串的终止位置,判断s[start:end]字符串是否是回文字符串,如果是的话添加该子串到路径path中,然后继续对剩余子串进行同样的操作。
注意:添加结果是添加path.copy(),因为path是会变的,需要保存当前状态

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        res = []
        path = []

        def isvalid(string):
            return string==string[::-1]

        def backtracking(start,path):
            if start==len(s):
                res.append(path.copy())

            for end in range(start+1,len(s)+1):
                if isvalid(s[start:end]):
                    path.append(s[start:end])
                    backtracking(end,path)
                    path.pop()

        backtracking(0,[])
        return res

搜索插入位置

题目:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。
思路:二分法查找

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)-1

        while left<=right:
            m = (left+right)//2
            if nums[m]==target:
                return m
            if nums[m]>=target:
                right = m-1
            else:
                left = m+1
        return left

搜索二维矩阵

题目:给你一个满足下述两条属性的 m x n 整数矩阵:

每行中的整数从左到右按非严格递增顺序排列。
每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。
思路:将每一行矩阵拼接在一起实际就是一个递增数组,因此可以直接用二分法搜索,当然实际中不需要拼接成数组,数组索引a[mid]到matrix的索引为matrix[mid//n][mid%n]

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m = len(matrix) #imax
        n = len(matrix[0]) # jmax

        left = 0
        right = m*n-1

        while left<=right:
            mid = (left+right)//2
            val = matrix[mid//n][mid%n]
            if val==target:
                return True
            elif val>target:
                right=mid-1
            else:
                left=mid+1
        return False

路径总和

题目:给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
思路:哈希表+前缀和。定义current_sum表示当前节点到根节点路径的前缀和,通过哈希表维护前缀和出现的次数。通过predix_sum[current_sum-targetSum]获取前缀和为targetSum的路径总数。dfs所有节点就可更新所有路径总数。
注意:一定要初始化predix_sum[0]=1
生成哈希表的方式predix_sum = defalutdict(int)

# 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: Optional[TreeNode], targetSum: int) -> int:
        predix_sum = defaultdict(int)
        predix_sum[0] = 1
        def dfs(node,current_sum):
            if not node:
                return 0
            current_sum+=node.val
            count = predix_sum[current_sum-targetSum]
            predix_sum[current_sum]+=1
            count+=dfs(node.left,current_sum)
            count+=dfs(node.right,current_sum)
            predix_sum[current_sum]-=1
            return count

        return dfs(root,0)

二叉树的最近公共祖先

题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路:找到从root到p和q的路径path_p path_q,然后对比两个路径的数值,最后一个一样的就是最近公共祖先

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':

        def findPath(node,target,path):
            if not node:
                return False

            path.append(node)
            if node==target:
                return True
            if findPath(node.left,target,path) or findPath(node.right,target,path):
                return True
            path.pop()#回溯,移除当前路径
            return False

        path_p,path_q = [],[]
        findPath(root,p,path_p)
        findPath(root,q,path_q)

        i=0
        while i<len(path_p) and i<len(path_q) and path_p[i]==path_q[i]:
            i+=1
        return path_p[i-1]

岛屿数量

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

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

此外,你可以假设该网格的四条边均被水包围。
思路:把访问过的岛屿“插旗”。

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid)
        n=len(grid[0])
        def dfs(i,j):
            if not 0<=i<=m-1 or not 0<=j<=n-1 or not grid[i][j]=="1":
                return
            
            grid[i][j] = "2"
            dfs(i+1,j)
            dfs(i-1,j)
            dfs(i,j+1)
            dfs(i,j-1)

        count=0
        for i in range(m):
            for j in range(n):
                if grid[i][j]=="1":
                    dfs(i,j)
                    count+=1
        return count

腐烂的橘子

题目:在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

思路:将腐烂的橘子位置添加到队列里面,通过深度优先遍历不断更新队列直到队列为空。

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        m, n ,time = len(grid), len(grid[0]), 0
        direction = [(1,0),(-1,0),(0,1),(0,-1)]

        queue = deque()

        for i in range(m):
            for j in range(n):
                if grid[i][j]==2:
                    queue.append((i,j,time))
        
        while queue:
            i,j,time = queue.popleft()
            for di,dj in direction:
                inew,jnew = i+di,j+dj
                if 0<=inew<=m-1 and 0<=jnew<=n-1 and grid[inew][jnew]==1:
                    grid[inew][jnew] = 2
                    queue.append((inew,jnew,time+1))
        
        for row in grid:
            for ele in row:
                if ele==1:
                    return -1
        
        return time

课程表

题目:你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
思路:把数据看成一个图结构,使用拓扑排序解决该问题。
1、构建邻接矩阵
2、初始化每门课程的入度
3、将入度为0的课程加入队列中,弹出队列每门课程并将访问次数加1,然后将该课程的邻居入度减一,如果邻居入度为0则添加进队列,直至队列为空。
4、如果访问次数为课程数,则可能完成所有课程的学习。

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        adjcentlist = defaultdict(list)
        indegree = [0]*numCourses
        for first,second in prerequisites:
            adjcentlist[second].append(first)
            indegree[first]+=1
        queue = deque([k for k in range(numCourses) if indegree[k]==0])
        
        count = 0
        while queue:
            count+=1
            vertex = queue.popleft()
            print(vertex)
            for neighboor in adjcentlist[vertex]:
                indegree[neighboor]-=1
                if indegree[neighboor]==0:
                    queue.append(neighboor)

        if count==numCourses:
            return True
        else:
            return False     

实现Trie前缀树

题目:Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
思路:创建一个Trinode类,childen表示其子节点,is_end表示该节点是否为末尾。

class Trinode:
    def __init__(self):
        self.childen = {}
        self.is_end = False
    
class Trie:

    def __init__(self):
        self.root = Trinode()

    def insert(self, word: str) -> None:
        node = self.root
        for string in word:
            if string not in node.childen:
                node.childen[string] = Trinode()
            node = node.childen[string]
        node.is_end = True

    def search(self, word: str) -> bool:
        node = self.root
        for string in word:
            if string not in node.childen:
                return False
            node = node.childen[string]
        return node.is_end
        
    def startsWith(self, prefix: str) -> bool:
        node = self.root
        for string in prefix:
            if string not in node.childen:
                return False
            node = node.childen[string]
        return True
        


# 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)

在排序数组中找第一个和最后一个元素

题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
思路:二分法的变体

class Solution:

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

        n = len(nums)
        i = searchRangeleft(nums,target)
        j = searchRangeleft(nums,target+1)
        j-=1
        if i>=n or nums[i]!=target:
            i = -1
        if j<0 or nums[j]!=target:
            j=-1
        return [i,j]

搜索旋转排序数组

题目:整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思路:对正常排序的情况采用二分法的移动指针方式,其它情况移动指针操作相反

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

寻找旋转排序数组的最小值

题目:已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

思路:二分法。初始化left和right指针,当nums[mid]>nums[right]说明最小值在mid右侧,此时更新left=mid+1, nums[mid]<=nums[right]说明最小值在mid或者mid左侧,此时更新right=mid,当left和right相等时就是最小值。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        n = len(nums)
        left, right = 0 , n-1
        while left<right:
            mid = (left+right)//2
            if nums[mid]>nums[right]: 
                #最小值在右边
                left = mid+1
            else:
                #最小值在左边或者mid
                right = mid
        return nums[left] #当left等于right时,就是结果
        

有效的括号

题目:给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

思路:通过一个栈来存储左括号。
遍历所有字符,如果字符是左括号,则进栈,如果是右括号,当栈为空的时候或者出栈元素不匹配右括号,则返回False
最后栈是空则为True,否则为False

class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        s_dict = {"}":"{",")":"(","]":"["}
        left = ["(","[","{"]
        for ele in s:
            if ele in left:
                stack.append(ele)
            else:
                if not stack or stack.pop()!=s_dict[ele]:
                    return False
        return not stack

最小栈

题目:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
思路:构建一个栈用于存储所有元素,构建一个栈用于存储最小元素

class MinStack:

    def __init__(self):
        self.stack = []
        self.stackmin = []
        
    def push(self, val: int) -> None:
        self.stack.append(val)
        if not self.stackmin or val<=self.stackmin[-1]:
            self.stackmin.append(val)
        
    def pop(self) -> None:
        if self.stack:
            val=self.stack.pop()
            if val==self.stackmin[-1]:
                self.stackmin.pop()
        
    def top(self) -> int:
        if self.stack:
            return self.stack[-1]
        
    def getMin(self) -> int:
        if self.stackmin:
            return self.stackmin[-1]
        


# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

每日温度

题目:给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
思路:单调栈
遍历每个数字
当栈非空且当前数字大于栈顶索引对应的数字时
则不断弹出栈顶索引,更新栈顶索引对应的答案
结束时将栈顶索引条件到单调栈中

遍历完成后,返回结果

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        n=len(temperatures)
        ans = [0]*n
        stack = []

        for i in range(n):
            while stack and temperatures[i]>temperatures[stack[-1]]:
                prev_index = stack.pop()
                ans[prev_index] = i - prev_index
            stack.append(i)
        return ans
       

买卖股票的最佳时机

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

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

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
思路:用一个前缀最小值存储索引i之前的最小值,用一个后缀最大值存储索引i之后的最大值,然后两个数组之差的最大值就是答案。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)

        predix_min = [0]*n
        predix_max = [0]*n
        minp= prices[0]
        maxp= prices[n-1]

        for i in range(n):
            minp = min(minp,prices[i])
            maxp = max(maxp,prices[n-i-1])
            predix_min[i] = minp
            predix_max[n-i-1] = maxp

        res = predix_max[0]-predix_min[0]
        for i in range(n):
            res = max(res,predix_max[i]-predix_min[i])
        return res 

划分字母

题目:给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。
思路:贪心算法
第一次遍历得到所有字母出现的最后位置
定义start和end分别代表片段的开始和结束位置
第二次遍历,
更新end
当下标==end时,说明当前片段到头,计算当前片段的长度添加到答案中,并更新start

最后返回答案

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        last_index = {char:i for i, char in enumerate(s)}

        res = []
        start, end = 0,0

        for i,char in enumerate(s):
            end = max(end,last_index[char])
            if i==end:
                res.append(i-start+1)
                start=end+1

        return res
        

爬楼梯

题目:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
思路:用数组实现递归关系 dp[i]=dp[i-1]+dp[i-2]
注意:长度为1的时候直接返回结果,避免越界

class Solution:
    def climbStairs(self, n: int) -> int:
        if n==1:
            return 1
        res = [0]*n
        res[0]=1
        res[1]=2
        for i in range(2,n):
            res[i] = res[i-1]+res[i-2]
        return res[n-1]

杨辉三角

题目:给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。
思路:动态规划
定义trangle保存最终结果
遍历每一层,构建一个长度为(len_row+1)的全1向量,然后处理中间的元素,动态规划关系为trangle[len_row][i]=trangle[len_row-1][i]+trangle[len_row-1][i-1]

返回trangle

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        trangle = []

        for len_row in range(numRows):
            tmp = [1]*(len_row+1)
            trangle.append(tmp)
            for i in range(1,len_row):
                trangle[len_row][i]=trangle[len_row-1][i]+trangle[len_row-1][i-1]
            
        return trangle

打家劫舍

题目:
思路:动态规划,dp[i] = max(dp[i-1],dp[i-2]+nums[i])当前状态最大现金=max(前种状态最大现金,打劫当前现金+前前种状态最大现金)

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0]*n

        if n==1:
            return nums[0]
        elif n==2:
            return max(nums[0],nums[1])

        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[n-1]

完全平方和

题目:给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
思路:动态规划,dp[i] = min(dp[i],1+dp[i-j*j])

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float("inf")]*(n+1)

        dp[0] = 0

        for i in range(n+1):
            j=0
            while j*j<=i:
                dp[i] = min(dp[i],1+dp[i-j*j])
                j+=1
        return dp[n]

乘积最大值

题目:给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续
子数组
(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。
思路:用max_current和min_current维护以当前索引数值为乘积的最大值和最小值,最小值要维护是因为最小值乘以负数会变最大值。
遍历数组所有数
用max_current和min_current维护以当前索引数值为乘积的最大值和最小值,更新答案res
返回res

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        maxnum = nums[0]
        minnum = nums[0]
        maxProduct = nums[0]
        n=len(nums)

        for i in range(1,n):
            tmp_maxnum = max(nums[i],nums[i]*maxnum,nums[i]*minnum)
            minnum = min(nums[i],nums[i]*maxnum,nums[i]*minnum)
            maxnum = tmp_maxnum
            maxProduct=max(maxProduct,maxnum)

        return maxProduct

分割等和子集

题目:给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
思路:动态规划
获取数组和,如果是奇数则返回False,是偶数则除以2得到target,此时的问题转化为数组元素和是否构成target,初始化dp状态转移数组,dp[i]表示数组里的元素是否可以构成i
遍历nums里每一个num
i从target到num遍历一遍,如果dp[i-num]为True说明i可以通过i-num和num两个数构建出来,因此dp[i]为True

返回dp[target]

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        sum_n = sum(nums)

        if sum_n%2==1:
            return False
        target = int(sum_n/2)
        dp = [False]*(target+1)
        dp[0] = True

        for num in nums:
            for i in range(target,num-1,-1):
                if dp[i-num]:
                    dp[i] = True
                if dp[target]:
                    return True
        return dp[target]

零钱兑换

题目:给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。
思路:动态规划dp[i] = min(dp[i],dp[i-coin]+1)
遍历所有的硬币,
遍历一遍dp,从coin开始,dp[i] = min(dp[i],dp[i-coin]+1)

如果dp[amount]不是无穷大返回dp[amount],否则返回-1

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        n = len(coins)
        dp = [float("inf")]*(amount+1)
        dp[0] = 0

        for coin in coins:
            for i in range(coin,amount+1):
                dp[i] = min(dp[i],dp[i-coin]+1)
        return dp[amount] if dp[amount]!=float("inf") else -1   

#单词拆分
题目:
思路:动态规划,定义dp[i]表示s的前i个字符能否通过字典拼接,dp[0]=True表示空字符可以通过没有单词拼接

初始化dp
遍历所有字符下标i
遍历s[j:i],如果dp[j]为True,且s[j:i]在字典中,则dp[i]为True(s前j个字符可以通过单词拼接且s[j:i]在字典中)

返回结果

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        n = len(s)
        dp= [False]*(n+1)
        dp[0] = True #0个字符,可以通过没有单词拼接到

        for i in range(n+1):
            for j in range(i):
                if dp[j] and s[j:i] in wordDict:
                    dp[i] = True
        
        return dp[n]

不同路径

题目:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?
思路:动态规划,状态转移方程
dp[i][j] = dp[i-1][j]+dp[i][j-1]

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

        for i in range(n):
            dp[0][i] = 1
        for i in range(m):
            dp[i][0] = 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]

最小路径和

题目:给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。
思路:动态规划,状态转移方程
dp[i][j] = grid[i][j] + min(dp[i-1][j],dp[i][j-1])
注意:为了正确创造一个二维矩阵,需要正确格式,dp = [[0]*n for i in range(m)]

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m = len(grid)
        n = 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] = grid[i][j] + min(dp[i-1][j],dp[i][j-1])
        return dp[m-1][n-1]

只出现一次的数字

题目:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
思路:使用 位运算 XOR 的特性 res = res^num

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        res = 0

        for num in nums:
            res = res^num
        return res

颜色分类

题目:给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。
思路:直接统计0 1 2的数量,然后重写nums

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        count = [0]*3
        n=len(nums)

        for num in nums:
            count[num]+=1

        for i in range(n):
            if i<count[0]:
                nums[i] = 0
            elif count[0]<=i<count[0]+count[1]:
                nums[i] =1
            else:
                nums[i]=2
        return nums

最长回文字符串

题目:给你一个字符串 s,找到 s 中最长的
回文

子串
子字符串
子字符串 是字符串中连续的 非空 字符序列。

思路:动态规划
dp[i][j]表示s i到j中的字符串是否为回文字符串,因此如果首位字符串相等且中间字符串是回文字符串,则dp[i][j]也是回文字符串

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp =  [[False]*n for _ in range(n)]

        if n<=1:
            return s
        
        max_len = 1
        start = 0

        for i in range(n):
            dp[i][i] = True

        for i in range(n-1):
            if (s[i]==s[i+1]):
                dp[i][i+1] = True
                max_len = 2
                start = i

        for length in range(3,n+1):
            #length从3到n
            for i in range(n-length+1):
                #i+length-1
                j = i+length-1
                if s[i]==s[j] and dp[i+1][j-1]:
                    dp[i][j] = True
                    max_len = length
                    start = i
        return s[start:start+max_len]

最长公共子序列

题目:给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
思路:动态规划,定义dp[i][j]为text1前i个字符和text2前j个字符的最长公共序列,那么递推关系为
if text1[i-1]==text2[j-1]:
dp[i][j] = 1 + dp[i-1][j-1]
else:
dp[i][j] = max(dp[i][j-1],dp[i-1][j])
注意:遍历的时候i j从1开始取值,取到m和n

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        m = len(text1)
        n = len(text2)

        dp = [[0]*(n+1) for i in range(m+1)]
        dp[0][0] = 0

        for i in range(1,m+1):
            for j in range(1,n+1):
                if text1[i-1]==text2[j-1]:
                    dp[i][j] = 1 + dp[i-1][j-1]
                else:
                    dp[i][j] = max(dp[i][j-1],dp[i-1][j])

        return dp[m][n]  

编辑距离

题目:给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
思路:动态规划,定义dp[i][j]为word1前i个字符转成word2前j个字符的操作数量,动态规划关系为
if word1[i-1]==word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1+min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        m = len(word1)
        n = len(word2)

        dp = [[0]*(n+1) for _ in range(m+1)]

        for i in range(1,m+1):
            #删除
            dp[i][0] = i

        for j in range(1,n+1):
            #插入
            dp[0][j] = j
        
        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] = 1+min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])

        return dp[m][n]

字符串解码

题目:给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
思路:用一个栈存储当前的数字k和字符串current_string
遍历所有字符:
当字符为数字时,将字符串转化成数字并累加到临时变量k中
当字符为[时,将临时变量k和当前的字符串current_string添加到栈中,然后清空所有临时变量
当字符为]时,将栈顶元素弹出获取先前的字符串和数字,将当前字符串复制k次,接到先前字符串后面。
当字符为字母时,将字符添加到当前字符串中
最后返回的current_string就是答案。
注意:char.isdigit()函数就是判断char是否是数字的字符串

class Solution:
    def decodeString(self, s: str) -> str:
        stack = []
        k = 0
        current_string = ""

        for char in s:
            if char.isdigit():
                k = k*10+int(char)
            elif char=="[":
                stack.append((current_string,k))
                k=0
                current_string=""
            elif char=="]":
                prev_string,num = stack.pop()
                current_string = prev_string + current_string*num
            else:
                current_string = current_string+char
        return current_string

组合总和,回溯思想

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:

    res = []
    n = len(candidates)

    def dfs(start,current_combination,current_sum):
        if current_sum==target:
            res.append(list(current_combination))
            return
        elif current_sum>target:
            return 

        for i in range(start,n):
            current_combination.append(candidates[i])
            dfs(i,current_combination,current_sum+candidates[i])
            current_combination.pop()

    dfs(0,[],0)
    return res

旋转矩阵
定义四个方向
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m = len(matrix)
n = len(matrix[0])
top=0
bottom=m-1
left =0
right = n-1
res = [0](mn)
row, col = 0, 0
direction = [[0,1],[1,0],[0,-1],[-1,0]]
visited = [[False]*n for _ in range(m)]
direction_index = 0

    for i in range(len(res)):
        res[i] = matrix[row][col]
        #print(row,col)
        visited[row][col] = True
        next_row , next_col = row+direction[direction_index][0], col + direction[direction_index][1]
        if not (0<=next_row<=m-1 and 0<=next_col<=n-1 and not visited[next_row][next_col]):
            direction_index = (direction_index+1)%4
        row , col = row+direction[direction_index][0], col + direction[direction_index][1]
    return res

旋转矩阵
先装置然后镜像
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
“”"
Do not return anything, modify matrix in-place instead.
“”"
rows = len(matrix)
cols = len(matrix[0])

    def transpose(matrix,rows):
        for i in range(rows):
            for j in range(i+1):
                #print(i,j)
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

        return matrix
    def minnor(matrix,rows):
        for i in range(rows):
            for j in range(0,int((rows+1)/2)):
                matrix[i][j], matrix[i][rows-j-1] = matrix[i][rows-j-1], matrix[i][j]
        return matrix

    matrix = transpose(matrix,rows)
    matrix = minnor(matrix,rows)
    return matrix

搜索二维矩阵II
从右上角开始遍历
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
rows = len(matrix)
cols = len(matrix[0])
row , col = 0, cols-1

    while row<=rows-1 and col>=0:
        if target==matrix[row][col]:
            return True
        elif target>matrix[row][col]:
            row+=1
        elif target

相交链表
双指针同时走完两个链表,直到相交
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
h1 = headA
h2 = headB
while True:
if not h1 and not h2:
return
if not h1:
h1 = headB
if not h2:
h2 = headA
if h1==h2:
return h1
h1 = h1.next
h2 = h2.next

反转链表

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
current_node = head
res = None
while current_node:
next_node = current_node.next
current_node.next = res
res = current_node
current_node = next_node
return res

    return res

判断回文链表
把链表的值存在数组上
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
temp = head
list_tmp = []

    while temp:
        list_tmp.append(temp.val)
        temp = temp.next
    
    middle = (len(list_tmp)+1)/2
    n = len(list_tmp)
    for i in range(int(middle)):
        if list_tmp[i]==list_tmp[n-i-1]:
            continue
        else:
            return False
    return True

LRU缓存
双向链表,哈希表
class Listnode:
def init(self,key=0,value=0):
self.key=key
self.value=value
self.pre = None
self.next = None

class LRUCache:

def __init__(self, capacity: int):
    self.capacity= capacity
    self.cache={}
    self.head = Listnode()
    self.tail = Listnode()
    self.head.next = self.tail
    self.tail.prev = self.head

def remove(self,node):
    prev_node = node.prev
    next_node = node.next
    prev_node.next = next_node
    next_node.prev = prev_node

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

def get(self, key: int) -> int:
    if key in self.cache:
        node = self.cache[key]
        self.remove(node)
        self.add(node)
        return node.value
    else:
        return -1

def put(self, key: int, value: int) -> None:
    if key in self.cache:
        node = self.cache[key]
        self.remove(node)
    else:
        node = Listnode(key, value)
        self.cache[key] = node
    
    node.value = value
    self.add(node)

    if len(self.cache)>self.capacity:
        tail_node = self.tail.prev
        self.remove(tail_node)
        del self.cache[tail_node.key]

中序遍历
递归

class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []

    def traversal(node):
        if node:
            
            traversal(node.left)
            result.append(node.val)
            traversal(node.right)
    
    traversal(root)
    return result

二叉树最大深度

class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:

    def maxDepthnode(node):
        res=0
        if node:
            tmp =1+ max(maxDepthnode(node.right),maxDepthnode(node.left))
            res = max(tmp,res)
            return res
        else:
            return 0

    return maxDepthnode(root)

翻转二叉树

class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:

    def invertTreenode(node):
        if node:
            tmp = node.left
            node.left=invertTreenode(node.right)
            node.right=invertTreenode(tmp)
            return node
        else:
            return
        

    return invertTreenode(root)

对称二叉树
递归

class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def isSymmetricnode(l1,l2):
if not l1 and not l2:
return True
if not l1 or not l2:
return False
if l1.val==l2.val and isSymmetricnode(l1.left,l2.right) and isSymmetricnode(l1.right,l2.left):
return True
else:
return False

    return isSymmetricnode(root.left,root.right)

二叉树的直径

class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:

    self.res = 0
    def dfs(node):
        if node:
            left_depth = dfs(node.left)
            right_depth = dfs(node.right)
            self.res = max(self.res,left_depth+right_depth)
            return 1+max(left_depth,right_depth)
        else:
            return 0
    dfs(root)
    return self.res

二叉树展开为链表

class Solution:
def flatten(self, root: Optional[TreeNode]) -> None:
“”"
Do not return anything, modify root in-place instead.
“”"
if not root:
return
def dfs(node):
if not node:
return
#将左子树放到右子树
right_node = node.right
node.right = node.left
node.left = None

        #将原右子树放当前右子树的末端
        tmp = node
        while tmp.right:
            tmp = tmp.right
        tmp.right = right_node
        
        dfs(node.right)
    dfs(root)

子集
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []

    def backtrace(start,current_com):
        res.append(current_com[:])
        for i in range(start,n):
            current_com.append(nums[i])
            backtrace(i+1,current_com)
            current_com.pop()

    backtrace(0,[])
    return res

    n = len(nums)
    left,right = 0, n-1
    while left<=right:
        mid = (left+right)//2
        if nums[left]<=nums[mid]:
            if nums[left]<=target

class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
d = defaultdict(list)
for s in strs:
d[‘’.join(sorted(s))].append(s) # sorted(s) 相同的字符串分到同一组
return list(d.values())

最长连续序列
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
nums = sorted(nums)
mx = 1
ans = 1
for i in range(len(nums)-1):
if nums[i]==nums[i+1]-1:
mx+=1
ans = max(mx,ans)
elif nums[i]==nums[i+1]:
continue
else:
mx = 1
return ans

移动0
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
“”"
Do not return anything, modify nums in-place instead.
“”"
count = 0
inz = 0
for i in range(len(nums)):
if nums[i] !=0:
nums[inz] = nums[i]
inz+=1
else:
count+=1
for i in range(count):
nums[len(nums)-i-1]=0
#print(nums)
return nums

最大容器
class Solution:
def maxArea(self, height: List[int]) -> int:
res =0
left = 0
right = len(height)-1
res = 0
while left 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

三数之和
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
n= len(nums)

    for i in range(n-2):
        if i>0 and nums[i]==nums[i-1]:
            continue
        
        left = i+1
        right = n-1

        while left0:
                right-=1
    return res

接雨水
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
left = 0
right = n-1
max_left = height[left]
max_right = height[right]
res = 0

    while left=max_left:
                max_left = height[left]
            else:
                res += max_left - height[left]
            left+=1
        else:
            if height[right]>=max_right:
                max_right = height[right]
            else:
                res+= max_right-height[right]
            right-=1
    return res

无重复字符串的最长子串
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
chatset = set()
left = 0
n = len(s)
res = 0

    for right in range(n):
        while s[right] in chatset:
            chatset.remove(s[left])
            left+=1
            
        chatset.add(s[right])
        res = max(res,right-left+1)
    return res

找到字符串中的所有字母异位词
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
n_s = len(s)
n_p = len§
res = []
p_count = Counter§

    for left in range(0,n_s-n_p+1):
        ele_s = s[left:left+n_p]
        s_count = Counter(ele_s)
        if s_count==p_count:
            res.append(left)
    return res

统计给定整数数组 nums 中和为 k 的子数组的个数,使用前缀和与哈希表
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
n = len(nums)

    current_sum = 0
    prefix_sum = {0:1}
    res = 0

    for i in range(n):
        current_sum+=nums[i]
        if current_sum-k in prefix_sum:
            res+= prefix_sum[current_sum-k]
        
        #update the prefix_sum
        if current_sum in prefix_sum:
            prefix_sum[current_sum]+=1
        else:
            prefix_sum[current_sum] = 1
            
    return res

滑动窗口最大值
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
res = []

    n = len(nums)
    if n==0:
        return []
    elif n==1:
        return nums

    dq = deque()

    for i in range(k):
        
        while dq and nums[i]>=nums[dq[-1]]:
            dq.pop()
        dq.append(i)
    
    

    for i in range(k,n):
        res.append(nums[dq[0]])
        if dq and i-dq[0]>k-1:
            dq.popleft()

        while dq and nums[i]>=nums[dq[-1]]:
            dq.pop()
        dq.append(i)

    res.append(nums[dq[0]])

    return res

最大子数组和
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_current = nums[0]
max_global = nums[0]
n=len(nums)

    for i in range(1,n):
        max_current = max(max_current+nums[i],nums[i])
        max_global = max(max_current,max_global)

    return max_global

合并区间 排序

class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key=lambda x: x[0])
res = [intervals[0]]

    n = len(intervals)

    for i in range(1,n):
        interval = intervals[i]
        if interval[0]<=res[-1][-1]:
            res[-1][-1] = max(res[-1][-1],interval[-1])
        else:
            res.append(interval)
    return res

轮转数组
容易出错的地方 k>n时情况不能忽视 k=k%n
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
“”"
Do not return anything, modify nums in-place instead.
“”"
n = len(nums)
k=k%n

    res = []
    for i in range(k-1,-1,-1):
        res.append(nums[n-i-1])

    for i in range(n-k):
        res.append(nums[i])

    nums[:] = res

    return res

除自身以外数组的乘积 前缀法和后缀法
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [1]*n
left = 1
right = 1

    for i in range(n):
        res[i] = left
        left*=nums[i]

    for j in range(n-1,-1,-1):
        res[j] *= right
        right*= nums[j]

    return res

找出最小正整数 将list转化成集合
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)

    nums = set(nums)

    for i in range(1,len(nums)+2):
        if i not in nums:
            return i

矩阵置0
暴力方法
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
“”"
Do not return anything, modify matrix in-place instead.
“”"
m = len(matrix)
n = len(matrix[0])

    a = set()
    b = set()

    for i in range(m):
        for j in range(n):
            if matrix[i][j]==0:
                a.add(i)
                b.add(j)
    
    for i in a:
        for j in range(n):
            matrix[i][j]=0

    for j in b:
        for i in range(m):
            matrix[i][j]=0

    return matrix

合并两个有序链表
递归法
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
if not list1:
return list2
if not list2:
return list1
if list1.val<=list2.val:
list1.next = self.mergeTwoLists(list1.next,list2)
return list1
else:
list2.next = self.mergeTwoLists(list1,list2.next)
return list2

两式相加
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
p = dummy
cn = 0
while (l1 or l2 or cn):
l1val = l1.val if l1 else 0
l2val = l2.val if l2 else 0
current_sum, cn = (l1val+l2val+cn)%10, (l1val+l2val+cn)//10
p.next = ListNode(current_sum)
p=p.next

        l1 = l1.next if l1 else None
        l2=l2.next if l2 else None

    return dummy.next

删除链表的倒数第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_head = ListNode(0)
dummy_head.next = head

    slow = dummy_head
    fast = dummy_head

    for i in range(n):
        if not fast:
            return head
        fast = fast.next
    
    while fast.next:
        slow = slow.next
        fast = fast.next

    slow.next = slow.next.next

    return dummy_head.next

两两交换链表当中的节点

Definition for singly-linked list.

class ListNode:

def init(self, val=0, next=None):

self.val = val

self.next = next

class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
if not head.next:
return head

    dummy_head = ListNode()
    dummy_head.next = head
    p = dummy_head

    while head and head.next:
        first = head
        second = head.next

        #swap
        p.next = second
        first.next = second.next
        second.next = first

        p = first
        head=head.next

    return dummy_head.next

二叉树直径
dfs

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 diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
self.res = 0

    def dfs(node):
        if node:
            leftD=dfs(node.left)
            rightD=dfs(node.right)
            self.res = max(self.res,leftD+rightD)
            return 1+max(leftD,rightD)
        else:
            return 0
    dfs(root)
    return self.res

层序遍历
deque([root]) # 初始化队列,根节点入队
queue.popleft() # 从队列中取出节点
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []

    res = []
    init_queue = deque([root])

    while init_queue:
        n = len(init_queue)
        current_res = []

        for _ in range(n):
            node = init_queue.popleft()
            current_res.append(node.val)

            if node.left:
                init_queue.append(node.left)
            if node.right:
                init_queue.append(node.right)
        res.append(current_res)
    return res

将有序数组转化成二叉搜索树

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]:
if not nums:
return

    n = len(nums)
    mid = n//2

    root = TreeNode(val=nums[mid])
    root.left = self.sortedArrayToBST(nums[:mid])
    root.right = self.sortedArrayToBST(nums[mid+1:])

    return root

你可能感兴趣的:(leetcode,python,算法)