leetcode 21天动态规划入门——从0到0.5【Day05】最大数组和 与 转着圈的最大数组和 dp思想由浅入深

leetcode 21天动态规划入门——从0到0.5【Day05】最大数组和 与 转着圈的最大数组和 dp思想由浅入深

写在前面

今天是动态规划入门的第五天了,今早打开了leetcode发现发出的讨论引起了很多人的共鸣,这也不乏是对博主的鼓励,博主也会继续加油哒,那么话不多说,来,上菜~看看今天是什么题…

题目

  1. 最大子数组和 难度系数:**

题目一

给你一个整数数组 nums ,
请你找出一个具有最大和的连续子数组
(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例

示例1:

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

示例2:

输入:nums = [1]
输出:1

示例3:

输入:nums = [5,4,-1,7,8]
输出:23
提示

1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4

思路
老样子,自然是动态规划的题型 维护一个dp数组 
和一个滚动变量res来获取当前数组的最大子数组和
再来用小部分推导全过程,动态规划的思路基本都大体相同

那么该题的动态转化方程我们可以根据示例来进行设计:
dp[0] = nums[0];
dp[1] = Math.max(dp[0]+nums[1],nums[1]);

此时的子数组和为:

  • 当前一个子数组和与当前数值相加

  • 当前数值

二者进行取最大值,获取得到当前的子数组和
dp[i] = Math.max(dp[i-1]+nums[i],nums[i])
然后我们利用一个滚动变量res 来记录最大的子数组和即:
res = Math.max(res,dp[i])

代码实现
class Solution {
    public int maxSubArray(int[] nums) {
    	//特殊情况特殊处理
        if (nums.length < 2 )return nums[0];
        //维护一个dp数组用来记录此时的数组和
        int[] dp = new int [nums.length+1];
        int res = nums[0];
        dp[0] = nums[0];
        for (int i = 1;i< nums.length;i++){
        	//动态转化方程 因为如果前面的数是一个负数那肯定相加没有当前数值大
            dp[i] = Math.max(nums[i],nums[i]+dp[i-1]);
            res = Math.max(res,dp[i]);
        }
        return res;
    }
}
执行结果

在这里插入图片描述

代码优化

用空间换时间的方法
同样是动态规划 动态转化方程也没有改
一看就懂~

class Solution {
    public int maxSubArray(int[] nums) { 
    	//维护当前的子数组和
        int pre = 0;
        int maxAns = nums[0];
        for (int x : nums){
        	//如果当前加了一个负数 肯定 就保留当前的值
            pre = Math.max(pre+x,x);
            //滚动变量来求最大子数组和
            maxAns = Math.max(maxAns,pre);
        }
        return maxAns;
    }
}

题目二

  1. 环形子数组的最大和 难度系数:****
给定一个由整数数组 A 表示的环形数组 C,
求 C 的非空子数组的最大可能和。
在此处,环形数组意味着数组的末端将会与开头相连呈环状。
(形式上,当0 <= i < A.length 时 C[i] = A[i],
且当 i >= 0 时 C[i+A.length] = C[i])
此外,子数组最多只能包含固定缓冲区 A 中的每个元素一次。
(形式上,对于子数组 C[i], C[i+1], ..., C[j],
不存在 i <= k1, k2 <= j 其中 k1 % A.length = k2 % A.length)
示例

示例1:

输入:[1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3

示例2:

输入:[5,-3,5]
输出:10
解释:从子数组 [5,5] 
得到最大和 5 + 5 = 10

示例3:

输入:[3,-1,2,-1]
输出:4
解释:从子数组 [2,-1,3] 
得到最大和 2 + (-1) + 3 = 4

示例4:

输入:[3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3

示例5:

输入:[-2,-3,-1]
输出:-1
解释:从子数组 [-1] 得到最大和 -1
提示

-30000 <= A[i] <= 30000
1 <= A.length <= 30000

思路
本题有两种情况
1)当不需要循环访问时,此时题就跟上面那道题一样一样的,
求到最大值就是最长子数组和的值。
2)当需要循环访问时,且如题可知,每个数最多访问一次,
也就是说当再次到达起始位置之前,一定可以找到最大子数组和,
那就需要考虑,你会明白一个道理,
因为每个数最多只能访问一次,我们就假如全部进行访问,
那获取总值之后,找到了最小的子数组之和,
与之相减,那么获得的就是可循环访问的最大子数组之和
上述两种情况中找到最大值,就是此题的解。
代码实现
class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        if(nums.length == 1)return nums[0];
        //sum是用来记录总的数组和剩下的变量和第一题意义相同
        int sum = 0,maxAns=nums[0],minAns=nums[0],pre=0;
        //进行遍历找到无需循环时的最大子数组和
        for (int i:nums){
            sum += i;
            pre = Math.max(i+pre,i);
            maxAns = Math.max(pre,maxAns);
        }
		//置0
        pre = 0 ;
        //此次寻找最小的子数组之和
        for (int i = 0; i<nums.length-1;i++){
            pre = Math.min(nums[i]+pre,0);
            minAns = Math.min(pre,minAns);
        }
 		//比较获取最大子数组和
        return Math.max(sum-minAns,maxAns);
    
    }
}
执行结果

在这里插入图片描述

写在最后

Day05打卡成功!
今天的动态规划问题较昨日有所改变
不仅需要求出此时的动态转化方程还需要设置滚动变量来进行答案求解
而第二道题更能考察做题者的分类讨论思想,以及基本的数学功底
今天又是有所收获的一天呢~

最后

每天进步点 每天收获点

愿诸君 事业有成 学有所获

如果觉得不错 别忘啦一键三连哦~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值