leetcode之动态规划系列1

1、输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
思路:
该题可以用动态规划的方法求解。
状态定义:设动态规划列表dp,dp[i]代表元素nums[i]为结尾的连续子数组的最大和;
转移方程:若dp[i-1]<=0,说明dp[i-1]对dp[i]产生负贡献,即dp[i-1]+nums[i]还不如nums[i]本身大。因此:
(1)当dp[i-1]>0时:执行dp[i]=dp[i-1]+nums[i];
(2)当dp[i-1]<=0时:执行dp[i]=nums[i]
初始状态:dp[0]=nums[0],即以nums[0]结尾的连续子数组最大和为nums[0]
python解法:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        for i in range(1,len(nums)):
            nums[i] +=max(nums[i-1],0)
        return max(nums)

java解法:

class Solution {
    
    
    public int maxSubArray(int[] nums) {
    
    
       if (nums.length==0)  return 0;
       int[] dp=new int[nums.length];
       dp[0]=nums[0];
       int max=dp[0];
       for (int i=1 ; i<dp.length;i++){
    
    
           if (dp[i-1]>0){
    
    
               dp[i]=dp[i-1]+nums[i];
           }else {
    
    
               dp[i]=nums[i];
           }
           max=Math.max(max,dp[i]);
       }
       return max;
    }
}

2、最小路径和:给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

思路:
状态定义:创建二维动态规划数组dp,dp[i][j]表示从左上角出发到(i,j)位置的最小路径和。
转移方程
(1)当i>0且j=0时,dp[i][0]=dp[i-1][0]+grid[i][0]
(2)当i=0且j>0时,dp[0][j]=dp[0][j-1]+grid[0][j]
(3)当i>0且j>0时,dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
最后得到dp[m-1][n-1]的值即为网格左上角到网格右下角的最小路径和;
初始状态:dp[0][0]=grid[0][0]
Python解法:

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        if not grid or not grid[0]:
            return 0
        rows, columns = len(grid), len(grid[0])
        dp = [[0] * columns for _ in range(rows)]
        dp[0][0] = grid[0][0]
        for i in range(1, rows):
            dp[i][0] = dp[i - 1][0] + grid[i][0]
        for j in range(1, columns):
            dp[0][j] = dp[0][j - 1] + grid[0][j]
        for i in range(1, rows):
            for j in range(1, columns):
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
        
        return dp[rows - 1][columns - 1]

java解法:

class Solution {
    
    
    public int minPathSum(int[][] grid) {
    
    
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
    
    
            return 0;
        }
        int rows = grid.length, columns = grid[0].length;
        int[][] dp = new int[rows][columns];
        dp[0][0] = grid[0][0];
        for (int i = 1; i < rows; i++) {
    
    
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int j = 1; j < columns; j++) {
    
    
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }
        for (int i = 1; i < rows; i++) {
    
    
            for (int j = 1; j < columns; j++) {
    
    
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[rows - 1][columns - 1];
    }
}

3、最佳买卖股票时机(含冷冻期)
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票)
:
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
思路:此题可以用DP思想求解。
状态定义:创建二维动态规划数组dp,dp[i][j]表示在下标i这一天状态为j时的最大收益,
这里j定义三个状态:
0表示不持股;
1表示持股;
2表示在冷冻期。
转移方程
1、当天不持股可以由三个状态转换而来:
昨天不持股,今天不交易;
昨天持股,今天卖出了;
昨天在冷冻期,今天不交易;
dp[i][0]=max(max(dp[i-1][0],dp[i-1][2]),dp[i-1][1]+price[i])

2、持股可以由两个状态转换而来:
昨天持股但不交易,今天仍然持股;
昨天处于冷冻期,今天买入;
dp[i][1] = max(dp[i-1][1],(dp[i-1][2]-prices[i]))

3、处于冷冻期,由题意知道,只能由不持股转换而来。
dp[i][2]=dp[i-1][0]
这里需要注意的一点是,从不持股状态不能直接到持股状态,需要经过一个冷冻期,才能得到持股状态。
初始状态:dp[0][0]=grid[0][0]
在第0天,不持股的初始化值为0,持股的初始化值为-price[0](表示购买了股票),冷冻期的初始化值可以为0

**输出:**最后一天的最优值,手里是没有股票的,这里取不持股和冷冻期的最大值。
Python解法:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:return 0
        n=len(prices)
        dp=[[0]*3 for _ in range(n)]
        dp[0][0],dp[0][1],dp[0][2]=0,-prices[0],0
        for i in range(1,n):
            dp[i][0]=max(max(dp[i-1][0],dp[i-1][2]),dp[i-1][1]+prices[i])
            dp[i][1] = max(dp[i-1][1],(dp[i-1][2]-prices[i]))
            dp[i][2]=dp[i-1][0]
        return max(dp[n-1][0],dp[n-1][2])

java解法:

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        if(len < 2) return 0;

        int[][] dp = new int[len][3];
        //初始化
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;

        for(int i = 1;i < len;i++){
    
    
            //当天不持股 前一天不持股 前一天卖出 前一天冷冻期
            dp[i][0] = Math.max(Math.max(dp[i-1][0],dp[i-1][2]), dp[i - 1][1] + prices[i]);
            //当天持股 前一天持股 前一天冷冻期+买入
            dp[i][1] = Math.max(dp[i-1][1],(dp[i-1][2]-prices[i]));
            //当天冷冻期 前一天卖出
            dp[i][2] = dp[i-1][0];
        }

        return Math.max(dp[len-1][0],dp[len-1][2]);
    }
}

猜你喜欢

转载自blog.csdn.net/Monica114/article/details/107712959
今日推荐