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

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

给定

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. SQL Server 多库操作 库名.dbo.表名 出错的问题!

    SQL Server 多库操作 库名.dbo.表名 出错的问题! 数据库名不要用数字开头. 例如:343934.dbo.user 这就会出错.md a343934.dbo.user 就没问题!! 记住 ...

  2. 2015年沈阳网赛 Jesus Is Here(DP中的计数问题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5459 题目描述:给定一个递推得来的字符串,问字符串中不同cff之间的距离之和, 递推规则: s1=c; ...

  3. Vue解决安卓4.4不兼容的问题

    1.npm安装 npm install babel-polyfillnpm install es6-promise package.json中会出现 "babel-polyfill" ...

  4. final的好处

    1.final关键字提高了性能.JVM和Java应用都会缓存final变量. 2.final变量可以安全的在多线程下进行共享,而不需要额外的同步开销. 3.使用final关键字,JVM会对方法,变量和 ...

  5. HDU 5944 Fxx and string (暴力)

    题意:给定一个字符串,问有多少个三元组满足 i, j, k组成一个等比数列,并且s[i] = 'y', s[j] = 'r', s[k] = 'x',且j/i ,j/k中至少一个是整数. 析:直接暴力 ...

  6. 【WIP】外汇与证券交易29个技术指标

    创建: 2017/05/16   更新: 2017/05/30 更新: 2017/10/14 标题加上[WIP],增加创建时间  指标名称  函数原型(prototype)  参考与分析 (refer ...

  7. bzoj 4720: [Noip2016]换教室【期望dp】

    状压dp,设f[i][j][0/1]为前i个时间段换了j间教室的期望体力消耗,转移很好想(但是写起来好长= =) #include<iostream> #include<cstdio ...

  8. nginx下配置虚拟主机

    linux 虚拟机下配置虚拟主机 nginx.conf 文件不动, 在 conf.d 或者 conf 目录下 新建项目.conf server { listen 80; server_name loc ...

  9. C# DateTime.Now 详解

    //2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString(& ...

  10. BZOJ2553 [BJWC2011]禁忌

    传送门 Description ​ 给你前alphabet个小写字母组成的字符集, 以及n个单词, 定义一个串s的禁忌值为 \(\sum_{i } [s[i] == Taboo[i]]\) , Tab ...