常用算法1:动态规划--Leetcode

动态规划类似于递归的正向求解,把结果存到变量中,再进行筛选,或者在求解的同时进行筛选,解决了递归的内存不够问题,下面是一些例题的动态规划解法

5. 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

  • 示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

  • 示例 2:

输入: “cbbd”
输出: “bb”

  • 思路:

动态规划的思想,比如CABAC,如果只有一个字符‘B’,那么一定是回文的,然后看B两边,如果“ABA”两边相同,那么是回文的;再看“ABA”的两边。一直到左右两边不相等,或者溢出。和之前存储的回文串长度比较。

  • 代码:
class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        palindrome = ""
        for i in range(len(s)):
            len1 = len(self.getPalindrome(s, i, i))
            if len1 > len(palindrome):
                palindrome = self.getPalindrome(s, i, i)
            len2 = len(self.getPalindrome(s, i, i+1))
            if len2 > len(palindrome):
                palindrome = self.getPalindrome(s, i, i+1)
        return palindrome
    def getPalindrome(self, s, l, r):
        while l >= 0 and r < len(s) and s[l] == s[r]:
            l -= 1
            r += 1
        return s[l+1 : r]

53. 最大子序和

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

  • 示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],

输出: 6

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

  • 思路
    设sum[i]为以第i个元素结尾的最大的连续子序列和。假设对于元素i,所有以它前面的元素结尾的子数组的和都已经求出,那么以第i个元素结尾且和最大的连续子序列和,要么是以第i-1个元素结尾且和最大的连续子和再加上这个元素,要么是只包含第i个元素,即sum[i]= max(sum[i-1] + a[i], a[i]

  • 代码:

 class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        length = len(nums)
        if length == 0:
            return 0
        preSum = maxSum = nums[0]
        for i in range(1, length):
            preSum = max(preSum + nums[i], nums[i])
            maxSum = max(maxSum, preSum)
            print(i, preSum, maxSum)
        return maxSum

62. 不同路径

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

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

问总共有多少条不同的路径?

例如,上图是一个7 x 3 的网格。有多少可能的路径?

说明:m 和 n 的值均不超过 100。

  • 示例 1:

输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1.向右 -> 向右 -> 向下
2.向右 -> 向下 -> 向右
3.向下 -> 向右 -> 向右

  • 示例 2:

输入: m = 7, n = 3
输出: 28

  • 思路

动态规划问题,首先一行一列的情况下,只有一种走法;其他情况=它上面的格子的走法数量+它左边格子的走法数量

  • 代码
class Solution(object):
    def uniquePaths(self, m, n):
        """
        :param m: int
        :param n: int
        :return: int
        """
        r = [[0] * m for _ in range(n)]
        # 一行一行构建从起点[0,0]到点[i,j]的路径数
        for i in range(0, n):
            for j in range(0, m):
                if i == 0:
                    r[i][j] = r[i][j - 1]
                elif j == 0:
                    r[i][j] = r[i - 1][j]
                else:
                    r[i][j] = r[i - 1][j] + r[i][j - 1]
        return r[n - 1][m - 1]

70. 爬楼梯

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

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

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

  • 示例 1:

输入: 2
输出: 2

解释: 有两种方法可以爬到楼顶。
1 阶 + 1 阶
2 阶

  • 示例 2:

输入: 3
输出: 3

解释: 有三种方法可以爬到楼顶。
1 阶 + 1 阶 + 1 阶
1 阶 + 2 阶
2 阶 + 1 阶

  • 思路

典型的动态规划问题,对于第n阶台阶来说,有两种办法,一种是爬一个台阶,到第n-1阶;第二种是爬两个台阶,到第n-2阶。

得出动态规划递推式:F(n) = F(n-1) + F(n-2)

  • 代码
class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1: return 1
        if n == 2: return 2
       
        result = [1, 2]
        for i in range(2,n):
            result.append(result[i-1] + result[i-2])
        return result[-1]

121. 买卖股票的最佳时机

给定一个数组,它的第 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。

  • 思路:

一次循环,在价格最低的时候买入,在价格最高的时候卖出,将最大的利润保存下来。

  • 代码:
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if not prices: return 0
        max_prices = 0
        min_prices = prices[0]
        for i in prices:
            min_prices = min(min_prices, i)
            max_prices = max(max_prices, i-min_prices)
        return max_prices

198. 打家劫舍

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

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

  • 示例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 。

  • 思路:

动态规划思想

当前最大的累计收益= max(前一家的收益,前前一家的收益加上当前的收益)

状态转移方程: dp[i] = max(dp[i-1], dp[i-2]+nums[i])

  • 代码:
class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        last = 0
        now = 0
        for i in nums:
            print(last,now)
            last, now = now, max(last + i, now)
        return now
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值