算法-动态规划(乘积最大子数组,和最大子数组)

文章目录

  • 连续子数组的最大和
  • 乘积最大子数组
  • 总结

连续子数组的最大和

面试题42. 连续子数组的最大和
算法-动态规划(乘积最大子数组,和最大子数组)_第1张图片
解题思路:
通过“子数组”、“最大和”等关键字,应该联想到动态规划,来看一下这道题是否有最优子结构:
定义一个max数组,max[i]用来记录以nums[i]结尾的连续子数组的最大和。来看一下,是否可以通过max[i-1]推出max[i]:

假设:max[i-1]=k,
当k<0时,nums[i]+k 当k>0时,nums[i]+k>nums[i],max[i]=nums[i]+k。

大功告成!

java代码:

    public int maxSubArray(int[] nums) {
        int max=nums[0];
        //这里直接在nums数组中进行修改,不用额外空间
        for(int i=1;i<nums.length;i++)
        {
            if(nums[i-1]>0)
                nums[i]=nums[i]+nums[i-1];
            //更新max
            max=Math.max(max,nums[i]);
        }
        return max;
    }

乘积最大子数组

乘积最大子数组
算法-动态规划(乘积最大子数组,和最大子数组)_第2张图片
解题思路:

一开始,想用滑动窗口来解决这道题,定义两个指针,left和right,right先走,当窗口内的乘积减小时,left+1,直到left走到头。
但写出来以后才发现不能解决,因为不能解决{-1,-2,-3,-4},这种情况。
right走到-3这个位置,乘积由2,变为-6,减小,left++,这样永远也到不了{-1,-2,-3,-4}这种情况(这种情况才是最大的)。所以滑动窗口不能解决该问题。

关键词:“子数组”,“乘积最大”,这不又是动态规划的苗头?
来尝试一下上面的方法,定义一个max数组,max[i]记录以nums[i]结尾的最大乘积。

当nums[i]*max[i-1]>nums[i],max[i]=nums[i]*max[i-1];
当nums[i]*max[i-1]

来试验一下能不能解决{-1,-2,-3,-4}这个数组;
max[0]=-1;
max[1]=-1×-2=2(nums[i]*max[i-1]>nums[i])
max[2]=-3;因为-3×2<-3。这里显然是不对的,max[2]应该是-2×-3=6。
问题在哪呢?
对于子数组存在多个负数(偶数个乘积为正,奇数个乘积为负)的情况,就不好确定乘积最大子数组了。
如何解决?
我们可以同时记录当前乘积最大max和乘积最小min(尤其是乘积为负的情况,因为再碰到一个负数就变为乘积为正)两个值,在**计算当前max[i]时比较nums[i]和Math.max(max[i-1]nums[i],min[i-1]nums[i])的大小,较大的为以nums[i]结尾的乘积最大子数组,同时也要更新乘积最小子数组min的值。

java代码:

    public int maxProduct(int[] nums) {
        int[] max = new int[nums.length];
        int[] min = new int[nums.length];
        int ans = nums[0];
        max[0] = ans;
        min[0] = ans;
        for(int i=1;i<nums.length;i++){
             int m = Math.max(nums[i]*max[i-1],nums[i]*min[i-1]);
             int n = Math.min(nums[i]*max[i-1],nums[i]*min[i-1]);
        	 max[i] = m>nums[i] ? m : nums[i];
       		 min[i] = n < nums[i] ? n : nums[i];
        	if(max[i] > ans){
            	ans = max[i];
        	}
    }
        return ans;
    }

总结

对于存在负数的数组求解连续子数组乘积最大,或者和最大的情况,利用滑动窗口无法解决连续负数的情况,但是动态规划可以解决,对于乘积最大连续子数组,不光要记录当前乘积最大值,还要记录乘积最小值,因为如果遇到下一个负数,这个乘积最小值就会变为乘积最大值了。

你可能感兴趣的:(算法,动态规划)