LintCode-最大子数组 III

给定整数数组和k,找到k个不重叠子数组使其和最大。数组元素必须连续,返回最大和。对于数组[-1,4,-2,3,-2,3]和k=2,答案是8。要求时间复杂度为O(n),可通过预处理求解最大子数组和。" 80754198,5783076,Linux硬件信息与服务查询Shell脚本,"['Linux', 'shell脚本', '系统管理', '服务器监控']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个整数数组和一个整数k,找出k不重叠子数组使得它们的和最大。

每个子数组的数字在数组中的位置应该是连续的。

返回最大的和。

您在真实的面试中是否遇到过这个题? 
Yes
样例

给出数组[-1,4,-2,3,-2,3]以及k=2,返回 8

注意

子数组最少包含一个数

挑战

要求时间复杂度为O(n)

标签 

相关题目 


分析:做不到题目要求的挑战,只能想到前i个数里面取了j段,这样dp[i][j] = max(dp[p][j-1]+f(p+1,i)),其中f(i,j)表示数组从i到j的最大子数组和,其中f可以通过预处理得到

代码:

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @param k: An integer denote to find k non-overlapping subarrays
     * @return: An integer denote the sum of max k non-overlapping subarrays
     */
    int maxSubArray(vector<int> nums, int k) {
        // write your code here
        vector<vector<int> > dp(nums.size()+1,vector<int>(k+1,INT_MIN));
        for(int i=0;i<nums.size();i++)
            dp[i][0] = 0;
        for(int i=1;i<=nums.size();i++)
        {
            for(int j=1;j<=min(i,k);j++)
            {
                int endMax = 0;
                int mx = INT_MIN;
                for(int p = i;p>=j;p--)
                {
                    endMax = max(nums[p-1],nums[p-1]+endMax);
                    mx = max(mx,endMax);
                    dp[i][j] = max(dp[i][j],dp[p-1][j-1]+mx);
                }
            }
        }
        return dp[nums.size()][k];
    }
};


### 最大子数组算法的实现 最大子数组问题的目标是找到一个数组最大的连续子数组。该问题在算法领域中具有重要意义,尤其在动态规划分治算法的应用中被广泛研究。 #### 方法1:蛮力法 蛮力法是最直观的解决方案,其基本思想是遍历所有可能的子数组,计算它们的,并从中找出最大值。这种方法的时间复杂度为 $O(n^2)$,对于较小的数组规模是可行的,但对于较大的数组则效率较低。 以下是C语言实现: ```c #include <stdio.h> int maxSubArray1(int a[], int n) { int maxSum = 0; int i, j; for (i = 0; i < n; i++) { int currentSum = 0; for (j = i; j < n; j++) { currentSum += a[j]; if (currentSum > maxSum) { maxSum = currentSum; } } } return maxSum; } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组为: %d\n", maxSubArray1(arr, n)); return 0; } ``` #### 方法2:动态规划法 动态规划法是解决最大子数组问题的经典方法,其时间复杂度为 $O(n)$,效率显著优于蛮力法。其核心思想是维护一个当前子数组,如果当前子数组小于0,则丢弃之前的子数组并重新开始计算。 以下是C语言实现: ```c #include <stdio.h> int maxSubArray2(int a[], int n) { int maxSum = a[0]; int currentSum = a[0]; for (int i = 1; i < n; i++) { currentSum = (currentSum + a[i] > a[i]) ? currentSum + a[i] : a[i]; maxSum = (currentSum > maxSum) ? currentSum : maxSum; } return maxSum; } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组为: %d\n", maxSubArray2(arr, n)); return 0; } ``` #### 方法3:分治法 分治法将数组分为左右两部分,分别求解左半部分右半部分的最大子数组,同时考虑跨越中间的最大子数组。这种方法的时间复杂度为 $O(n \log n)$,适合大规模据的处理。 以下是C语言实现: ```c #include <stdio.h> // 求三者中的最大值 int max(int a, int b, int c) { return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } // 求跨越中间的最大子数组 int maxCrossingSum(int a[], int left, int mid, int right) { int sum = 0; int leftSum = -999999; for (int i = mid; i >= left; i--) { sum += a[i]; if (sum > leftSum) { leftSum = sum; } } sum = 0; int rightSum = -999999; for (int i = mid + 1; i <= right; i++) { sum += a[i]; if (sum > rightSum) { rightSum = sum; } } return leftSum + rightSum; } // 分治法主函 int maxSubArray3(int a[], int left, int right) { if (left == right) { return a[left]; } int mid = (left + right) / 2; int leftMax = maxSubArray3(a, left, mid); int rightMax = maxSubArray3(a, mid + 1, right); int crossMax = maxCrossingSum(a, left, mid, right); return max(leftMax, rightMax, crossMax); } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组为: %d\n", maxSubArray3(arr, 0, n - 1)); return 0; } ``` ### 总结 - **蛮力法**:简单直观,但效率较低,时间复杂度为 $O(n^2)$。 - **动态规划法**:高效且简洁,时间复杂度为 $O(n)$。 - **分治法**:适用于大规模据,时间复杂度为 $O(n \log n)$,但实现较复杂。 根据具体需求据规模,可以选择合适的算法实现最大子数组的求解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值