给定一个数组,求它的一个子数组,使其求和最大。

这个问题的应用:给定一只股票很多天的价格,计算从哪天买进哪天卖出能获得最大利润。

给定

prices:100   113   98   87   65   78   120   110   115

计算delta

delta:           13    -15  -11  -22   13    42    -10    5

求delta数组的最大连续子数组就能得到最大利润。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1231

解法1:Devide and Conquer

1)将delta按中点分为两个数组left[l...mid]、right[mid+1...r],最大子数组要么在left中,要么在right中,要么跨越left和right。

2)将其递归划分至原子问题,left中一个元素,right中一个元素。最大子数组要么是left[l],要么是right[r],要么是left[l]+right[r]。

3)先不考虑跨越left和right的情况,那么求left和right中的最大子数组,就是原问题的子问题,原问题时间复杂度T(n),该子问题复杂度为T(n/2)。

4)将求跨越left和right的最大子数组的问题额外处理。其最大值一定是  left中以mid为右端点的最大子数组  加上  right中以mid+1为左端点的最大子数组。求这个问题的时间复杂度可以做到O(n)。最终T(n)=2T(n/2)+O(n),整个问题的复杂度为O(nlogn)。

#include<iostream>
#include<cstdio>
using namespace std; #define N 10005 struct Pair {
int sum, left,right;
Pair() {}
explicit Pair(int s, int l, int r)
{
sum = s;
left = l;
right = r;
}
bool operator < (const Pair& p)const
{
return sum < p.sum;
}
bool operator <= (const Pair& p)const
{
return sum <= p.sum;
}
}; int n, num[N],preSum[N],sufSum[N]; Pair findMaxCrossSubarr(int l, int r)
{
int mid = (l + r) / ,lmax_l=mid,rmax_r=mid+,lmax=num[mid],rmax=num[mid+];
for (int i = l; i < mid; i++)
{
int tmp = preSum[mid] - preSum[i - ];
if (tmp > lmax)
{
lmax = tmp;
lmax_l = i;
}
}
for (int i = mid + ; i <= r; i++)
{
int tmp = sufSum[mid + ] - sufSum[i+];
if (tmp > rmax)
{
rmax = tmp;
rmax_r = i;
}
}
//cout << rmax + lmax << " " << lmax_l << " " << rmax_r << endl;
/*if(rmax+lmax<0)
return Pair(0, l, r);
else */
return Pair(rmax + lmax, lmax_l, rmax_r); } Pair findMaxSubarr(int l, int r)
{
if (l == r)
return Pair(num[l], l, r);
int mid = (l + r) / ;
Pair lpair = findMaxSubarr(l, mid);
Pair rpair = findMaxSubarr(mid + , r);
Pair xpair = findMaxCrossSubarr(l, r);
//cout << "*" << lpair.sum << " " << rpair.sum << " " << xpair.sum << endl;
if (rpair <= lpair&&xpair <= lpair)
return lpair;
else if (lpair < rpair&&xpair < rpair)
return rpair;
else
return xpair;
} int main()
{
while (scanf_s("%d", &n) != EOF && n)
{
for (int i = ; i <= n; i++)
{
scanf_s("%d", &num[i]);
preSum[i] = preSum[i - ] + num[i];
}
for (int i = n; i > ; i--)
sufSum[i] = sufSum[i + ] + num[i];
Pair res = findMaxSubarr(, n);
//printf("%d %d %d\n", res.sum, res.left, res.right);
if (res.sum < )
printf("0 %d %d\n", num[], num[n]);
else
printf("%d %d %d\n", res.sum, num[res.left], num[res.right]);
//cout << endl;
}
return ;
}

解法2:Dynamic Programming 线性时间复杂度

假如知道以r为右端点的最大子数组,将其扩展到以r+1为右端点的最大子数组,若dp[r]>=0,则dp[r+1]=dp[r]+num[r+1];若dp[r]<0,则dp[r+1]=num[r+1];

#include<iostream>
#include<cstdio>
using namespace std; #define N 10005 int main()
{
int n;
while (scanf_s("%d", &n) != EOF && n)
{
int num[N];
for (int i = ; i <= n; i++)
scanf_s("%d", &num[i]);
int dp = -, dp1 = , l = , r = , maxn = -, tl = , tr = ;
for (int i = ; i <= n; i++)
{
if (dp < )
{
dp = num[i];
tl = tr = i;
}
else
{
dp += num[i];
tr = i;
}
if (dp > maxn)
{
maxn = dp;
l = tl;
r = tr;
}
}
if(maxn<)
printf("0 %d %d\n", num[], num[n]);
else
printf("%d %d %d\n", maxn, num[l], num[r]);
}
return ;
}

Divide and Conquer_1.最大连续子数组的更多相关文章

  1. LeetCode 581. Shortest Unsorted Continuous Subarray (最短无序连续子数组)

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  2. [LeetCode] Shortest Unsorted Continuous Subarray 最短无序连续子数组

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  3. Java课程课后作业190315之从文档中读取随机数并得到最大连续子数组

    从我上一篇随笔中,我们可以得到最大连续子数组. 按照要求,我们需要从TXT文档中读取随机数,那在此之前,我们需要在程序中写入随机数 import java.io.File; import java.i ...

  4. Leetcode 581.最短无序连续子数组

    最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, ...

  5. LeetCode 581. 最短无序连续子数组(Shortest Unsorted Continuous Subarray)

    581. 最短无序连续子数组 581. Shortest Unsorted Continuous Subarray 题目描述 给定一个整型数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序 ...

  6. 【LeetCode】1438. 绝对差不超过限制的最长连续子数组 Longest Continuous Subarray With Absolute Diff Less Than or Equal t

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 日期 题目地址:https://leetco ...

  7. The Day Two 找到一个具有最大和的连续子数组,返回其最大和

    """ 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5, ...

  8. Leetcode581.Shortest Unsorted Continuous Subarray最短无序连续子数组

    给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, 6, 4, 8, 1 ...

  9. 力扣1438. 绝对差不超过限制的最长连续子数组-C语言实现-中等难度

    题目 传送门 文本 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条 ...

随机推荐

  1. Day1 BFS算法的学习和训练

    ​ 因为自己的原因,之前没有坚持做算法的相应学习,总是觉得太难就半途而废,真的算是一个遗憾了,所以现在开始,定一个30天入门学习算法计划. ​ 我是根据<算法图解>的顺序进行安排的,自己对 ...

  2. UESTC149 解救小Q

    小Q被邪恶的大魔王困在了迷宫里,love8909决定去解救她.迷宫里面有一些陷阱,一旦走到陷阱里,就会被困身亡:(,迷宫里还有一些古老的传送阵,一旦走到传送阵上,会强制被传送到传送阵的另一头.现在请你 ...

  3. ubuntu切换中英文通用方法,ubuntu中文语言

    1:点击桌面右上角的齿轮,选择“system settings”进入系统设置界面

  4. wirte function in powershell

    https://github.com/dahlbyk/posh-git/blob/master/src/Utils.ps1#L102 https://docs.microsoft.com/en-us/ ...

  5. YTU 2928: 取不重复的子串。

    2928: 取不重复的子串. 时间限制: 1 Sec  内存限制: 128 MB 提交: 5  解决: 5 题目描述 输入字母构成的字符串(不大于30字符)从中读取3个不重复的字符,求所有取法,取出的 ...

  6. mac中的本地项目和登陆的钥匙串怎么解锁

    前提条件:电脑语言换成英语,然后按下面的操作就可以了. 1.打开launchapd中的钥匙串访问 2 选中第一栏登录, 点击左上角的锁锁上, 再点一次解锁. 3. 这回会弹出个东西 点击如上图中的重密 ...

  7. BZOJ3282:Tree(TCL基础题)

    给定N个点以及每个点的权值,要你处理接下来的M个操作. 操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和. 保证x到y是联通的. ...

  8. [Usaco2009 Dec] 过路费

    [题目链接] https://www.luogu.org/problemnew/show/P2966 [算法] SPFA最短路 时间复杂度 : O(N ^ 2) [代码] #include<bi ...

  9. [Usaco2018 Feb] New Barns

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=5192 [算法] 维护树的直径,在树上离一个点最远的点一定是一条直径的端点.     ...

  10. Cortex-M3 / M4 Hard Fault Handler (转载)

    转自大伟的,感谢大伟的帮助调试:http://www.cnblogs.com/shangdawei/archive/2013/04/30/3052491.html http://blog.frankv ...