Leetcode刷题

169 多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。

思考:这道题的价值在于充分利用了max函数,

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        counts = collections.Counter(nums)
        return max(counts.keys(), key=counts.get)

二叉树

102 二叉树的层序遍历

思考:下面可以作为层序遍历的模板

# 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 levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        queue=[]
        res=[]
        if root:
            queue.append(root)
        while queue:
            size=len(queue)
            temp=[]
            for i in range(size):
                r=queue.pop(0)
                temp.append(r.val)
                if r.left:
                    queue.append(r.left)
                if r.right:
                    queue.append(r.right)
            res.append(temp)
        return res

662 二叉树最大宽度

思考:这题不能一直动态调整queue,要有个辅助队列temp保存下一层的节点,避免了在遍历过程中修改当前队列 queue 的问题

# 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 widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        queue = []
        res = 0
        if root:
            queue.append([root,1])
        while queue:
            temp=[]
            for node,index in queue:
                if node.left:
                    temp.append([node.left,index*2])
                if node.right:
                    temp.append([node.right,index*2+1])
            res=max(res,queue[-1][1]-queue[0][1]+1)
            queue=temp
        return res

110 平衡二叉树

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        def height(root):
            if not root:
                return 0
            else:
                return max(height(root.left),height(root.right))+1

        if not root:
            return True
        else:
            return abs(height(root.left)-height(root.right))<=1 and self.isBalanced(root.left) and self.isBalanced(root.right)

112 路径总和

判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def hasPathSum(self, root, targetSum):
        """
        :type root: TreeNode
        :type targetSum: int
        :rtype: bool
        """
        if not root:
            return False
        elif not root.left and not root.right:
            return root.val==targetSum
        else:
            return self.hasPathSum(root.left,targetSum-root.val) or self.hasPathSum(root.right,targetSum-root.val)

129 求根节点到叶子节点数字之和

回溯和递归是一一对应的,有一个递归,就要有一个回溯

# 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 sumNumbers(self, root: Optional[TreeNode]) -> int:
        self.res=0
        r=[]
        def dfs(root):
            r.append(root.val)
            if not root.left and not root.right:
                num_str = ''.join(map(str, r))
                num = int(num_str)
                self.res=self.res+num
            if root.left:
                dfs(root.left)
                r.pop()
            if root.right:
                dfs(root.right)
                r.pop()

        if not root:
            return 0
        else:
            dfs(root)
        return self.res

226 翻转二叉树

思考:这题主要是在返回值上

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if not root:
            return root
        else:
            temp=root.left
            root.left=root.right
            root.right=temp
            self.invertTree(root.left)
            self.invertTree(root.right)
            return root

105 从前序与中序遍历序列构造二叉树

# 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]:
        # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
        if not preorder:
            return None

        # 第二步: 前序遍历的第一个就是当前的中间节点
        root=TreeNode(preorder[0])

        # 第三步: 找切割点
        index=inorder.index(preorder[0])

        # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
        left_inorder=inorder[:index]
        right_inorder=inorder[index+1:]

        # 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
        left_preorder=preorder[1:len(left_inorder)+1]
        right_preorder=preorder[len(left_inorder)+1:]

        # 第六步: 递归
        root.left=self.buildTree(left_preorder,left_inorder)
        root.right=self.buildTree(right_preorder,right_inorder)

        # 第七步: 返回答案
        return root

98 验证二叉搜素数

思考:这道题用双指针进行比较,在中序遍历的代码基础上进行了比较,这题要主要对返回值进行判断比较

# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
        self.pre=None
        def __isValidBST(root: TreeNode) -> bool:
            if not root:
                return True
            left=__isValidBST(root.left)
            if  self.pre and self.pre.val>=root.val:
                return False
            else:
                self.pre=root
            right=__isValidBST(root.right)
            return left and right
           
        return __isValidBST(root)

手撕快速排序

思考:这道题要对快速排序做个优化

  1. 随机选取分割值
  2. 要优化数值全部相同的问题
import random

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def partition(nums,low,high):
            mid_id=random.randint(low,high)
            nums[low],nums[mid_id]=nums[mid_id],nums[low]
            mid=nums[low]

            left,right=low,high
            while left<right:
                while left<right and nums[right]>=mid:
                    right-=1
                nums[left]=nums[right]
                while left<right and nums[left]<=mid:
                    left+=1
                nums[right]=nums[left]
            nums[left]=mid
            return left


        def quickSort(nums,low,high):
            if low >=high:
                return
            mid=partition(nums,low,high)
            templ=mid-1
            tempr=mid+1
            while templ>=0 and nums[templ]==nums[mid]:
                templ-=1
            while tempr <len(nums) and nums[tempr] == nums[mid]:
                tempr+=1
            quickSort(nums,low,templ)
            quickSort(nums,tempr,high)

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

15 三数之和

思考:去重的细节值得考究

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res=[]
        l=len(nums)
        for i in range(l-2):
            if nums[i]>0:
                break
            if i>0 and nums[i]==nums[i-1]:
                continue
            left=i+1
            right=l-1
            while left<right:
                temp=nums[i]+nums[left]+nums[right]
                if temp==0:
                    res.append([nums[i],nums[left],nums[right]])
                    while left<right and nums[left]==nums[left+1]:
                        left+=1
                    while left<right and nums[right]==nums[right-1]:
                        right-=1
                    left+=1
                    right-=1
                elif temp<0:
                    left+=1
                else:
                    right-=1
        return res

200 岛屿数量

思考:可以将下面代码记下作为处理岛屿问题的模板

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:

        lenr=len(grid)
        lenc=len(grid[0])
        res=0

        def inArea(grid,i,j):
            return 0<=i<lenr and 0<=j<lenc

        def dfs(grid,i,j):
            if not inArea(grid,i,j):
                return 0
            elif grid[i][j]!='1':
                return 0
            else:
                grid[i][j]='2'
                dfs(grid,i-1,j)
                dfs(grid,i+1,j)
                dfs(grid,i,j-1)
                dfs(grid,i,j+1)
                return 1


        for i in range(lenr):
            for j in range(lenc):
                res+=dfs(grid,i,j)

        return res

动态规划

1143 最长公共子序列

思考:这道题逻辑很难,解题的巧妙之处在于dp[i][j]处理的是到text1的i-1和text2的j-1的公共子序列,这样可以化简初始化,把所有工作交给递推公式
递推公式利用了三个方向的值做推导

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        l1=len(text1)+1
        l2=len(text2)+1
        dp=[[0]*l2 for _ in range(l1)] 
        
        for i in range(1,l1):
            for j in range(1,l2):
                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[l1-1][l2-1]

718. 最长重复子数组

class Solution:
    def findLength(self, nums1: List[int], nums2: List[int]) -> int:
        m=len(nums1)+1
        n=len(nums2)+1
        result=0
        dp=[[0]*n for _ in range(m)]

        for i in range(1,m):
            for j in range(1,n):
                if nums1[i-1]==nums2[j-1]:
                    dp[i][j]=dp[i-1][j-1]+1
                result=max(result,dp[i][j])

        return result

221 最大正方形

思考:就像 木桶的短板理论 那样——附近的最小边长,才与 ? 的最长边长有关。
并且本题和上面题的初始化有异曲同工之妙
在这里插入图片描述

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        r=len(matrix)+1
        c=len(matrix[0])+1

        dp=[[0]*c for _ in range(r)]
        res=0

        for i in range(1,r):
            for j in range(1,c):
                if matrix[i-1][j-1]=='1':
                    dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
                    res=max(res,dp[i][j])
        return res*res

链表

92. 反转链表 II

class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        def reverse_linked_list(head: ListNode):
            # 也可以使用递归反转一个链表
            pre = None
            cur = head
            while cur:
                next = cur.next
                cur.next = pre
                pre = cur
                cur = next

        # 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
        dummy_node = ListNode(-1)
        dummy_node.next = head
        pre = dummy_node
        # 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
        # 建议写在 for 循环里,语义清晰
        for _ in range(left - 1):
            pre = pre.next

        # 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
        right_node = pre
        for _ in range(right - left + 1):
            right_node = right_node.next
        # 第 3 步:切断出一个子链表(截取链表)
        left_node = pre.next
        curr = right_node.next

        # 注意:切断链接
        pre.next = None
        right_node.next = None

        # 第 4 步:同第 206 题,反转链表的子区间
        reverse_linked_list(left_node)
        # 第 5 步:接回到原来的链表中
        pre.next = right_node
        left_node.next = curr
        return dummy_node.next

回溯

回溯算法的模板

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

93 复原ip地址

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        res = []
        current=""
        pointsum = 0
        length = len(s)

        def isvalid(s, startindex, n):
            if n - startindex + 1 > 1 and s[startindex] == '0':
                return False
            substring=s[startindex:n+1]
            if substring.isdigit():
                num= int(substring)
                return 0<=num<=255
            else:
                return None


        def backtraking(startindex, pointsum,current):
            if pointsum == 3:
                if isvalid(s, startindex, length - 1):
                    res.append(current+s[startindex:])
                return
            for i in range(startindex, min(startindex+3,length)):
                if isvalid(s, startindex, i):
                    sub=s[startindex:i + 1] + '.'
                    backtraking(i + 1, pointsum+1,current+sub)
                     # pointsum+1,current+sub可不是简洁写法,这就是回溯,相当于pointsum-1,current-sub


        backtraking(0, pointsum,current)
        return res

39 组合总和

这道题注意剪枝操作,还有一个总是犯错的点:

res.append(path) 将 path 列表的引用添加到 res 中,而不是添加 path 的副本。要解决这个问题,需要在将path 添加到 res 列表时,使用 path.copy() 或者 path[:] 来创建 path的副本。这样,每个路径都将独立存储,不会受到后续修改 path 的影响。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        path=[]
        res=[]
        def backtracking(startindex,sum):
            if sum==target:
                res.append(path[:]) # 添加 path 的副本到结果列表

            for i in range(startindex,len(candidates)):
                if sum+candidates[i]>target:
                    break    #剪枝
                path.append(candidates[i])
                backtracking(i,sum+candidates[i])
                path.pop()
        backtracking(0,0)
        return res

394 字符串解码

用一个栈保存之前的res,和现在的nums

class Solution:
    def decodeString(self, s: str) -> str:
        stack=[]
        num=0
        res=''

        for i in range(len(s)):
            if  s[i]>='0' and s[i]<='9':
                num=num*10+int(s[i])
            elif s[i]=="[":
                stack.append([res,num])
                res=''
                num=0
            elif s[i].isalpha():
                res=res+s[i]
            else:
                last_res,last_num=stack.pop()
                res=last_res+res*last_num

        return res

二分搜索

34. 在排序数组中查找元素的第一个和最后一个位置

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n=len(nums)
        i,j=0,n-1
        while i<=j:
            mid=i+(j-i)//2
            if nums[mid]>target:
                j=mid-1
            elif nums[mid]<target:
                i=mid+1
            else:
                i=j=mid
                while i-1>=0 and nums[i-1]==target:
                    i=i-1
                while j+1<n and nums[j+1]==target:
                    j=j+1
                return [i,j]
        return [-1,-1]

240. 搜索二维矩阵 II

思考:bisect.bisect和bisect.bisect_right返回大于x的第一个下标(相当于C++中的upper_bound),bisect.bisect_left返回大于等于x的第一个下标(相当于C++中的lower_bound)。

import bisect

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        for row in matrix:
            tar_id=bisect.bisect_left(row,target)
            if tar_id<len(row) and row[tar_id]==target:
                return True
        return False
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值