Leetcode——初级部分——动态规划部分——Python实现

本文详细介绍了四个LeetCode上的动态规划问题:爬楼梯、买卖股票的最佳时机、最大子序和及打家劫舍。通过Python代码展示了如何解决这些问题,包括递归和循环等不同实现方式,并探讨了动态规划的思路和优化技巧。

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

爬楼梯

假设你正在爬楼梯。需要 n 步你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 步 + 1 步
2.  2 步

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 步 + 1 步 + 1 步
2.  1 步 + 2 步
3.  2 步 + 1 步

我的解答:

这个实际上就是斐波那契数列的求解。可以逆向来分析问题,如果有n个台阶,那么走完n个台阶的方式有f(n)种。而走完n个台阶有两种方法,先走完n-2个台阶,然后跨2个台阶;先走完n-1个台阶,然后跨1个台阶。所以f(n) = f(n-1) + f(n-2)。

方法1——递归实现(超时):

class Solution:
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return self.climbStairs(n-1) + self.climbStairs(n-2)

方法2——循环实现:

class Solution:
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            p = 1
            q = 1
            temp =0
            for i in range(n-1):
                temp = p + q
                p = q
                q = temp
            return q

买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

我的解答:

Python最大整数:

(1)32位系统上是 2**31 - 1,64位系统上是2**63 - 1

不过,超过这个范围后python会自动转用高精度计算,这样用户看起来就好像支持更大的整数计算。

(2)也可以用sys模块得到

import sys
i = sys.maxsize
print(i)   

下面是本题的解答:

class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """ 
        # 一次循环搞定查找最小值和最大差值。
        minprice = pow(2,31)-1
        profit = 0
        for i in range(len(prices)):
            minprice = min(prices[i],minprice)
            profit = max(prices[i]-minprice,profit)
        return profit

最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。


我的解答:

class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        numsum = 0
        for i in range(1,len(nums)):
            # 当前值的大小与前面的值之和比较,若当前值更大,则取当前值,舍弃前面的值之和
            numsum = max(nums[i] + nums[i-1],nums[i])
            # 现在nums里面存储的是一个和
            nums[i] = numsum
        return max(nums)

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

我的解答:

当前房屋i抢不抢的问题。抢了,第i+1就不能抢,不抢,第i+1就能抢。那么是不是每步最优之后,最后的结果也是最优的呢?

假设从最后一个房屋开始抢,最后一个房屋为index。将原问题分割成子问题,子问题的最优决策可以导出原问题的最优决策。

方法1——递归实现:

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 递归实现
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        if len(nums) == 2:
            return max(nums[0],nums[1])
        max1 = self.rob(nums[:-1])
        max2 = self.rob(nums[:-2])
        return max(max1,max2+nums[-1])

方法2——构建临时数组,存储子问题最优,避免递归重复计算

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 构建临时数组,存储子问题最优,避免递归重复计算
        res = {}
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        if len(nums) == 2:
            return max(nums[0],nums[1])
        else:
            res[0] = nums[0]
            res[1] = max(nums[0],nums[1])
            for i in range(2,len(nums)):
                res[i] = max(res[i-2]+nums[i],res[i-1])
            return res[len(nums)-1]




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值