Python剑指offer打卡-31

本文解析了Python剑指Offer中的四个重点问题:分发糖果的双指针策略、验证二叉搜索树的性质、动态规划解决最长重复子数组和不同路径II,以及在旋转排序数组中搜索目标值的高效算法。通过实例演示和代码实现,深入探讨了这些经典算法的原理和应用。
摘要由CSDN通过智能技术生成

Python剑指offer打卡-31

分发糖果(重点

题目类型:双指针

题目难度:🌟🌟

  • 问题描述

    问题描述:
        老师想给孩子们分发糖果,有 N个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
    你需要按照以下要求,帮助老师给这些孩子分发糖果:每个孩子至少分配到 1 个糖果。评分更高的孩子必须
    比他两侧的邻位孩子获得更多的糖果。那么这样下来,老师至少需要准备多少颗糖果呢?
    
    解题方法:
    双指针
    时间复杂度:O(N)
    空间复杂度:O(N)
    
  • 代码

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

验证二叉搜索树

题目类型:树

题目难度:🌟🌟

  • 问题描述

    问题描述:
    给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
    
    解题方法:
    BFS和DFS
    
  • 代码

    class Solution1:
        def isValidBST(self, root: TreeNode) -> bool:
    
            if root is None: False
    
            deque = []
            cur = root
            pre_val = float("-inf")
            while deque or cur:
                while cur:
                    deque.append(cur)
                    cur = cur.left
    
                node = deque.pop()
                if node.val <= pre_val:
                    return False
                pre_val = node.val
                cur = node.right
    
            return True
    
    class Solution2:
        def __init__(self):
            self.pre = float('-inf')
        def isValidBST(self, root: TreeNode) -> bool:
            if root is None: return True
            if not self.isValidBST(root.left): return False
            if root.val <= self.pre:  return False
            self.pre = root.val
            return self.isValidBST(root.right)
    

最长重复子数组(重点

题目类型:动态规划

题目难度:🌟🌟🌟🌟

  • 问题描述

    给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
    
    解题思路:
    动态规划
    dp[i][j]代表以A[i-1]与B[j-1]结尾的公共字串的长度,公共字串必须以A[i-1],B[j-1]结束,
    即当A[i-1] == B[j-1]时,dp[i][j] = dp[i-1][j-1] + 1; 当A[i-1] != B[j-1]时,
    以A[i-1]和B[j-1]结尾的公共字串长度为0,dp[i][j] = 0。输出最大的公共字串的长度即为最
    长重复字串。
    时间复杂度:O(M*N)
    空间复杂度:O(M*N)
    注意:
    记住,子序列默认不连续,子数组默认连续
    
  • 代码

    class Solution:
        def findLength(self, nums1: List[int], nums2: List[int]) -> int:
    
            m, n = len(nums1), len(nums2)
    
            # 定义状态和起始值
            dp = [[0]*(n + 1) for _ in range(m + 1)]
            ans = 0
    
            # 状态转移
            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
                        ans = max(ans, dp[i][j])
            return ans
    

不同路径II(重点

题目类型:动态规划

题目难度:🌟🌟🌟🌟

  • 问题描述

    问题描述:
        一个机器人位于一个 m x n 网格的左上角(起始点在下图中标记为“Start” )。
    机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为
    “Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路
    径?网格中的障碍物和空位置分别用1和0来表示。
    
    解题方法:
    动态规划
    (1) 定义状态:dp[i][j]表示到达i, j的不同路径
    (2) 初始值:dp[0][j] = 1, dp[i][0] = 1,遇见障碍 break
    (3) 转态转移: dp[i][j] = dp[i][j - 1] + dp[i - 1][j] 遇见障碍 continue
    (4) 返回值:dp[-1][-1]
    时间复杂度:O(n*m)
    空间复杂度:O(m*n)
    
  • 代码

    class Solution:
        def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
    
            # 定义dp
            m, n = len(obstacleGrid), len(obstacleGrid[0])
            dp = [[0] * n for _ in range(m)]
            # 定义初始转态
            # 有障碍区进行跳转
            for i in range(m):
                if obstacleGrid[i][0]: break
                dp[i][0] = 1
            for j in range(n):
                if obstacleGrid[0][j]: break
                dp[0][j] = 1
    
            # 转态转移
            for i in range(1, m):
                for j in range(1, n):
                    if obstacleGrid[i][j] == 1: continue
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
            # 返回值
            return dp[m - 1][n - 1]
    

搜索旋转排序数组(重点

题目类型:二分法

题目难度:🌟🌟🌟🌟

  • 问题描述

    问题描述:
        整数数组 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(logn)
    空间复杂度:O(1)
    
  • 代码

    class Solution:
        def search(self, nums: List[int], target: int) -> int:
    
            if not nums: return -1
    
            l, r = 0, len(nums) - 1
            while l <= r:
    
                mid = (l + r) // 2
                if nums[mid] == target:
                    return mid
                if nums[0] <= nums[mid]:
                    if nums[0] <= target < nums[mid]:
                        r = mid - 1
                    else:
                        l = mid + 1
                else:
                    if nums[mid] < target <= nums[-1]:
                        l = mid + 1
                    else:
                        r = mid - 1
            return -1
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值