最大子数组和-动态规划、分治

21 篇文章 0 订阅
13 篇文章 0 订阅
本文探讨了如何使用动态规划和分治算法解决经典问题——寻找具有最大和的整数数组连续子数组。动态规划通过状态转移方程求解,而分治法则通过递归拆分数组来寻找跨区间最大和。通过实例和代码展示,深入理解这两种方法在解决此类问题中的应用。
摘要由CSDN通过智能技术生成
  • 题目

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

  • 示例

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6

  • 动态规划算法
  1. dp[i]表示以nums[i]为结尾的连续子数组的最大和
  2. 以nums[i]为结尾的连续子数组的最大和有两种情况
    情况1.nums[i]孤身一人,即dp[i] = nums[i]
    情况2.nums[i]前面有人,即dp[i] = dp[i-1] + nums[i]
  • 代码
public int maxSubArray(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];
        int ret = dp[0];
        for (int i = 1; i < n; i++) {
            dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
            ret = Math.max(ret, dp[i]);
        }
        return ret;
    }
  • 分治算法

将数组分为左数组和右数组后,拥有最大和的连续子数组的出现位置有3中情况
情况1.子数组在左数组中
清理2.子数组在右数组中
情况3.子数组跨越左右两个数组

  • 代码
public int getMax(int[] nums, int low, int high) {
		// 如果数组只有一个元素
        if (low == high) {
            return nums[low];
        }
        // 将数组分为左数组和右数组
        int mid = low + (high - low) / 2;
        // 求左数组的连续子数组的最大和
        int leftMax = getMax(nums, low, mid);
        // 求右数组的连续子数组的最大和
        int rightMax = getMax(nums, mid + 1, high);
        // 求跨越跨越左右两个数组的连续子数组的最大和
        int crossMax = getCrossMax(nums, low, mid, high);
        // 三者取最大
        return Math.max(Math.max(leftMax, rightMax), crossMax);
    }
    // 子数组跨越左右两个数组的情况下的最大和
    public int getCrossMax(int[] nums, int low, int mid, int high) {		
    // 既然是跨越两个数组,则左数组的最右元素
    // 和右数组的最左元素必然在拥有最大和连续子数组中
    	// 左数组从最右向左的累加和
        int leftSum = nums[mid];
        // 左数组从最右向左的子数组的最大和
        int leftMax = nums[mid];
        // 左数组从最右向左的累加和
        for (int i = mid - 1; i >= low; i--) {
        	// 累加
            leftSum += nums[i];
            // 记录最大
            leftMax = Math.max(leftMax, leftSum);
        }
        // 右数组同理
        int rightSum = nums[mid+1];
        int rightMax = nums[mid+1];
        for (int i = mid + 2; i <= high; i++) {
            rightSum += nums[i];
            rightMax = Math.max(rightMax, rightSum);
        }
        return leftMax + rightMax;
    }

    public int maxSubArray(int[] nums) {
        return getMax(nums, 0 , nums.length - 1);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值