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

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

给定

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. USING REFLECTION

    In this section, you take a closer look at the System.Type class, which enables you to access inform ...

  2. sphinx是支持结果聚类的

    Coreseek 4.1 参考手册 / Sphinx 2.0.1-beta Sphinx--强大的开源全文检索引擎,Coreseek--免费开源的中文全文检索引擎 版权 © 2001-2011 And ...

  3. bzoj 2744 朋友圈

    题目大意: 两个国家 各有A和B个人,每个人有一个数值. 若两个A国的人满足$val_i\space xor \space val_j \mod 2 =1$ 则他们为朋友 若两个B国的人满足$val_ ...

  4. 实现的是Linux和Windows之间的一种共享--samba

    samba 基本配置及自定义控制 https://www.cnblogs.com/l-hh/p/9473937.html Samba简介: Samba实现的是Linux和Windows之间的一种共享, ...

  5. bzoj4196 [Noi2015]软件包管理器——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4196 树链剖分. 代码如下: #include<iostream> #inclu ...

  6. bzoj 3270: 博物馆【dp+高斯消元】

    好像是高斯消元解互相推(?)的dp的例子 首先考虑dp,设f[i][j]为一人在i一人在j的概率,点i答案显然就是f[i][i]: 然后根据题意,得到转移是 \[ f[i][j]=f[i][j]*p_ ...

  7. bzoj 3624: [Apio2008]免费道路【生成树+贪心】

    先把水泥路建生成树,然后加鹅卵石路,这里加的鹅卵石路是一定要用的(连接各个联通块),然后初始化并查集,先把必需的鹅卵石路加进去,然后随便加鹅卵石路直到k条,然后加水泥路即可. 注意判断无解 #incl ...

  8. 洛谷P4364 [九省联考2018]IIIDX(线段树)

    传送门 题解看得……很……迷? 因为取完一个数后,它的子树中只能取权值小于等于它的数.我们先把权值从大到小排序,然后记$a_i$为他左边(包括自己)所有取完他还能取的数的个数.那么当取完一个点$x$的 ...

  9. JavaScript 数组相关基础方法

    文章来源于:https://www.cnblogs.com/dolphinX/p/3353590.html 创建数组 构造函数 1.无参构造函数,创建一空数组 var a1=new Array(); ...

  10. js 几秒之后就不断的执行

     function url()    { $.ajax({            url: "AA.ashx",            data: { ID: "gggg ...