最大子序列和问题O(N)

问题描述:

给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大。

解决思想:

要想让时间复杂度为O(N),就只能用一个for(或while等的)循环。即遍历一遍数组。

1.我们可以从头遍历,把每一个元素相加,每加一次就与最大和进行比较,留下最大的;

2. 小于0的元素不可能成为最大子序列的第一或最后一个值(把它去掉的子序列和将更大);

3.当子序列和小于0的时候,代表这个序列不是我们想要的(空集子序列和为0,肯定比负数要大);

4.当子序列小于0时(最后一个元素让子序列为负,所以最后一个元素肯定是负数),让最后一个元素隔绝了前面的元素(前面的元素与最后一个元素相加不可能大于0),所以要从这个子序列的最后一个元素的下一个元素开始推进。

代码:

#include <iostream>
#include <vector>
using namespace std;
int maxsubsum(const vector<int>& a){//等同数组C中的传入首地址
        int maxsum=0;
        int thissum=0;
        for(int i=0;i<a.size();i++){//a.size为数组的元素个数
                thissum+=a[i];
                if(thissum>maxsum)
                        maxsum=thissum;
                if(thissum<0)
                        thissum=0;
        }
        return maxsum;
}

int main(){
        vector<int> a{-2,11,-4,13,-5,2,-5,-3,12,-9};
        cout<<maxsubsum(a)<<endl;
}

结果:


### 最大子序列问题的C语言实现 最大子序列问题是经典的算法问题,其目标是从给定维数组中找出具有最大一个连续子数组。以下是基于动态规划的思想来解决问题种高效解决方案。 #### 动态规划的核心思路 通过维护一个状态变量 `dp[i]` 表示以第 `i` 个元素为结尾的最大子数组,可以逐步更新并最终得到全局最优解。这种方法的时间复杂度为 O(n),空间复杂度可以通过优化降低至 O(1)[^2]。 下面是完整的 C 语言代码实现: ```c #include<stdio.h> long long num[200001]; long long dp[200001]; int max(int x, int y) { return (x > y) ? x : y; } int main() { int n, i, max_sum; while (scanf("%d", &n) != EOF) { for (i = 1; i <= n; i++) { scanf("%lld", &num[i]); } dp[1] = num[1]; max_sum = dp[1]; for (i = 2; i <= n; i++) { dp[i] = max(dp[i - 1] + num[i], num[i]); // 关键转移方程 if (max_sum < dp[i]) { max_sum = dp[i]; // 更新当前最大值 } } printf("%lld\n", max_sum); } return 0; } ``` 上述程序实现了动态规划最大子序列的方法。其中核心部分是对每个位置上的元素决定是否将其加入之前的子数组还是重新开始一个新的子数组,这步骤由表达式 `dp[i] = max(dp[i-1] + num[i], num[i])` 完成。 如果希望进步减少内存消耗,则可以直接省去存储整个 `dp[]` 数组的需,在迭代过程中仅保留上次的结果即可[^4]。 #### 另种暴力枚举方式 除了高效的动态规划方法外,还可以采用双重循环的方式逐尝试所有可能的子数组组合,并记录下最大的那个总。不过该策略效率较低,时间复杂度达到 O(n&sup2;)[^3]。 ```c #include <stdio.h> #define MAXN 1000 int maxsum(const int arr[], int N) { int this_sum, max_sum; max_sum = 0; for (int i = 0; i < N; i++) { // 子数组起始位置 this_sum = 0; for (int j = i; j < N; j++) { // 子数组结束位置 this_sum += arr[j]; if (this_sum > max_sum) { max_sum = this_sum; } } } return max_sum; } int main() { int arr[MAXN]; int N; scanf("%d", &N); for (int i = 0; i < N; i++) { scanf("%d", &arr[i]); } printf("%d\n", maxsum(arr, N)); return 0; } ``` 尽管此版本易于理解,但在处理大规模输入时性能表现不佳,因此推荐优先考虑更优的算法设计如前面提到过的动态规划技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值