K - 循环数组最大子段和

本文介绍了一种解决循环序列中寻找最大子段和的方法,包括四种可能的情况,并通过编程实现了解决方案。

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

N个整数组成的循环序列a11,a22,a33,…,ann,求该序列如aii+ai+1i+1+…+ajj的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑an1n−1,ann,a11,a22这样的序列)。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
Input
第1行:整数序列的长度N(2 <= N <= 50000) 
第2 - N+1行:N个整数 (-10^9 <= Sii <= 10^9)
Output
输出循环数组的最大子段和。
Sample Input
6
-2
11
-4
13
-5
-2
Sample Output

20


**************************************************************************

思路,其实我就是觉得很烦。很烦。

**************************************************************************

你可以把这个一串数字,分为以下几类: 

(1)第一种,从开始最后都是递增的,也就是全加起来,就是最大值。

例:5 1 2 3 4 5

(2)第二种,中间的一部分大,两头加了,就变小了。循环也是中间的。

例:6 -1 0 5 -1 5 -1

(3)第三种,两头的大,中间一部分数值,阻隔了。循环去考虑。

例:5 5 -1 -2 5 -1

(4)第四种,就前面,或者后面的小,其余的是最大值的组成部分。

例:5 1 2 -1 0 -3 或者 5 -1 0 -3 1 2

**************************************************************************

现在我们来解决他们这些情况,就可以解决了。

(1)(4)我们用一个数值,求不循环的最大值,就可以解决掉。OK。

(2)(3)如果我们把所有的数取反,之后求最大值,得到的是不是小的部分加起来的最大值,之后再把原来的数据,加起来。他们求和,不就是最大值吗?假设原来全部数据和为ans1 ,取反求最大值为ans2,那么ans = ans1 + ans2吗?或者这样来理解,我们把原来的数据求最小值,我们用所有的数据和,减去他,ans = ans1 - (-ans2),公式不就是这个吗?只不过前者我取反求的ans2而已。

**************************************************************************

(1)(2)(3)(4)合并,二者之间不就是,去取最大值吗?

**************************************************************************

这种解释,应该能懂吧?或者还有什么情况没有考虑吗?欢迎下面留言,我将一一改正。

**************************************************************************

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

long long int a[50005];

int n;

long long int  cmp()
{
    long long int max1 = 0;
    long long int num = 0;
    for(int i=0;i<n;i++)
    {
       if(max1<0) {
            max1=a[i];
       }
       else {
          num = max(num,max1);
          max1+=a[i];
       }
    }
    return num;
}

void print_gaibian()
{
    for(int i=0; i<n; i++)
    {
        a[i] = -a[i];
    }
}
int main()
{
    scanf("%d",&n);
    long long int ans=0,ans1=0,ans2=0;
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
        ans+=a[i];
    }
    ans1 = cmp();
    print_gaibian();
    ans2 = cmp();
    ans = max(ans1,ans+ans2);
    printf("%lld\n",ans);
    return 0;
}

### 最大问题的算法实现及优化方法 最大问题是经典的算法问题,其目标是从一个整数数组中找到连续子数组最大。以下是基于引用内容专业知识对最大问题的实现与优化方法的详细说明。 #### 1. 蛮力算法 蛮力算法通过三重循环来枚举所有可能的,并计算它们的,从而找到最大。这种方法的时间复杂度为 \(O(n^3)\),在实际应用中效率较低。伪代码如下: ```python def brute_force_max_subarray(arr): n = len(arr) max_sum = float('-inf') for i in range(n): # 起点 for j in range(i, n): # 终点 this_sum = 0 for k in range(i, j + 1): # 计算 this_sum += arr[k] if this_sum > max_sum: max_sum = this_sum return max_sum ``` 该算法可以通过减少内层循环数进行优化,将时间复杂度降低到 \(O(n^2)\) [^2]。 #### 2. 分治策略 分治策略将数组分为左右两部分,递归地求解左右两部分的最大,并计算跨越中间点的最大。最终结果为这三者中的最大值。分治法的时间复杂度为 \(O(n \log n)\)。伪代码如下: ```python def divide_and_conquer_max_subarray(arr, left, right): if left == right: # 基本情况:只有一个元素 return arr[left] mid = (left + right) // 2 # 计算左半部分的最大 left_max_sum = divide_and_conquer_max_subarray(arr, left, mid) # 计算右半部分的最大 right_max_sum = divide_and_conquer_max_subarray(arr, mid + 1, right) # 计算跨越中间点的最大 cross_max_sum = find_cross_max_subarray(arr, left, mid, right) return max(left_max_sum, right_max_sum, cross_max_sum) def find_cross_max_subarray(arr, left, mid, right): left_sum = float('-inf') sum = 0 for i in range(mid, left - 1, -1): sum += arr[i] if sum > left_sum: left_sum = sum right_sum = float('-inf') sum = 0 for i in range(mid + 1, right + 1): sum += arr[i] if sum > right_sum: right_sum = sum return left_sum + right_sum ``` #### 3. 动态规划算法 动态规划是解决最大问题的最优方法之一,其核心思想是利用递推公式 \(C[i] = \max(C[i-1] + a[i], a[i])\) 来计算以每个位置结尾的最大。最终答案为所有 \(C[i]\) 中的最大值。动态规划的时间复杂度为 \(O(n)\) [^1]。伪代码如下: ```python def dynamic_programming_max_subarray(arr): n = len(arr) C = [0] * n C[0] = arr[0] max_sum = C[0] for i in range(1, n): C[i] = max(C[i - 1] + arr[i], arr[i]) if C[i] > max_sum: max_sum = C[i] return max_sum ``` #### 4. 前缀优化 前缀是一种高效的优化方法,尤其适用于多查询最大的场景。通过预处理数组的前缀,可以快速计算任意。结合前缀与动态规划,可以在某些情况下进一步提升性能 [^3]。 ```python def prefix_sum_optimized_max_subarray(arr): n = len(arr) prefix_sum = [0] * (n + 1) for i in range(1, n + 1): prefix_sum[i] = prefix_sum[i - 1] + arr[i - 1] min_prefix_sum = 0 max_sum = float('-inf') for i in range(1, n + 1): current_sum = prefix_sum[i] - min_prefix_sum if current_sum > max_sum: max_sum = current_sum if prefix_sum[i] < min_prefix_sum: min_prefix_sum = prefix_sum[i] return max_sum ``` #### 总结 以上方法分别对应了不同时间复杂度的解决方案。蛮力算法适合理解问题的本质,但效率低下;分治策略提供了较好的平衡;动态规划则是最优解法;前缀优化则在特定场景下表现出色。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值