2019-03-03 求最大連續(xù)子列和問(wèn)題

算法介紹

算法一:暴力法

不同的是并沒(méi)有使用三重循環(huán)來(lái)進(jìn)行遍歷棺聊,因?yàn)橛^察到每一次只需要在a[i]后加一個(gè)即可侯养,所以時(shí)間復(fù)雜度為O(n^2)拍鲤。

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int k = 0;
  scanf("%d", &k);
  int *a = (int*)malloc(sizeof(int) * k);
  for(int i = 0; i < k; i++){
    scanf("%d", &a[I]);
  }
  int maxsum = 0;
  for(int i = 0; i < k; i++){
    int thissum = 0;
    for(int j = i; j < k; j++){
        thissum += a[j];
        if(thissum > maxsum){
          maxsum = thissum;
        }
    }
  }
  free(a);

  if(maxsum > 0){
    printf("%d", maxsum);
  }
  else{
    printf("0");
  }
  return 0;
}

算法二:在線處理法

在線處理法就是在輸入的時(shí)候進(jìn)行條件的判斷,有點(diǎn)像對(duì)每一個(gè)數(shù)進(jìn)行實(shí)時(shí)處理憋沿,在輸入完成后結(jié)果也就得出旺芽,所以時(shí)間復(fù)雜度最低,為O(N)辐啄。具體的判斷條件是如果輸入的數(shù)加上目前的序列和之后導(dǎo)致了當(dāng)前序列和的減少甥绿,則不進(jìn)行錄入,當(dāng)相加后當(dāng)前序列和小于0時(shí)则披,則放棄該序列,因?yàn)橹粫?huì)對(duì)之后的序列和產(chǎn)生副作用洗出。缺點(diǎn)是不是很直觀地讓人理解士复。

#include <stdio.h>

int main()
{
  int k = 0, x = 0;
  scanf("%d", &k);
  int  thissum = 0, maxsum = 0;
  for(int i = 0; i < k; i++){
    scanf("%d", &x);
    thissum += x;
    if(thissum > maxsum){
      maxsum = thissum;
    }
    else if(thissum < 0){
      thissum = 0;
    }
  }
  if(maxsum > 0){
    printf("%d", maxsum);
  }
  else{
    printf("0");
  }
  return 0;
}

算法三:分治法

這個(gè)方法較為復(fù)雜,就我個(gè)人而言理解和實(shí)現(xiàn)起來(lái)都比在線處理法麻煩不少,具體實(shí)現(xiàn)思路就是將一個(gè)規(guī)模比較大的問(wèn)題通過(guò)不斷劃分劃分成一個(gè)個(gè)小規(guī)模的問(wèn)題阱洪,然后再將每個(gè)小問(wèn)題的解集中起來(lái)便贵,通過(guò)考慮到跨越邊界的情況最終得出答案。(真是又復(fù)雜又難敲)
貼一個(gè)圖幫助理解一下:


分治法
#include <stdio.h>

int Max3(int A, int B, int C){
    //返回3個(gè)整數(shù)中的最大值
    return A > B ? A > C ? A : C : B > C ? B : C;
    //return A > B ? (A > C ? A : (B > C ? B : C)) : B > C ? B : C;
}

int DivideAndConquer( int List[], int left, int right )
{ /* 分治法求List[left]到List[right]的最大子列和 */
    int MaxLeftSum, MaxRightSum; /* 存放左右子問(wèn)題的解 */
    int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界線的結(jié)果*/
 
    int LeftBorderSum, RightBorderSum;
    int center, i;
 
    if( left == right )  { /* 遞歸的終止條件冗荸,子列只有1個(gè)數(shù)字 */
        if( List[left] > 0 )  return List[left];
        else return 0;
    }
 
    /* 下面是"分"的過(guò)程 */
    center = ( left + right ) / 2; /* 找到中分點(diǎn) */
    /* 遞歸求得兩邊子列的最大和 */
    MaxLeftSum = DivideAndConquer( List, left, center );
    MaxRightSum = DivideAndConquer( List, center+1, right );
 
    /* 下面求跨分界線的最大子列和 */
    MaxLeftBorderSum = 0; LeftBorderSum = 0;
    for( i=center; i>=left; i-- ) { /* 從中線向左掃描 */
        LeftBorderSum += List[i];
        if( LeftBorderSum > MaxLeftBorderSum )
            MaxLeftBorderSum = LeftBorderSum;
    } /* 左邊掃描結(jié)束 */
 
    MaxRightBorderSum = 0; RightBorderSum = 0;
    for( i=center+1; i<=right; i++ ) { /* 從中線向右掃描 */
        RightBorderSum += List[i];
        if( RightBorderSum > MaxRightBorderSum )
            MaxRightBorderSum = RightBorderSum;
    } /* 右邊掃描結(jié)束 */
 
    /* 下面返回"治"的結(jié)果 */
    return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
}
 
int MaxSubseqSum3( int List[], int N )
{ /* 保持與前2種算法相同的函數(shù)接口 */
    return DivideAndConquer( List, 0, N-1 );
}

int main()
{
    int k = 0;
    scanf("%d", &k);
    int a[k];
    for(int i = 0; i < k; i++){
        scanf("%d", &a[i]);
    }

    int res = MaxSubseqSum3(a, k);
    printf("%d", res);
    return 0;

}

不過(guò)這代碼看著工整舒服承璃,遞歸還是沒(méi)有明白。

練習(xí):

題目網(wǎng)站:https://pintia.cn/problem-sets/994805342720868352/problems/994805514284679168

題目描述:

1007 Maximum Subsequence Sum (25 point(s))
Given a sequence of K integers { N?1?? , N?2, ..., N?K}. A continuous subsequence is defined to be { N?I, N?I+1, ..., Nj} where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:

10 1 4

易錯(cuò)點(diǎn)分析

本題唯一的會(huì)影響AC的就是對(duì)于輸出格式的要求蚌本, 一開(kāi)始以為是輸出對(duì)應(yīng)的起止數(shù)據(jù)的下標(biāo)盔粹,后來(lái)發(fā)現(xiàn)是輸出對(duì)應(yīng)的數(shù),所以說(shuō)樣例還是很有誤導(dǎo)性的程癌,如果沒(méi)有完全看清楚題目要求很容易在這卡住舷嗡,只會(huì)得個(gè)辛苦分3分,出題的果然都想好了情況嵌莉。對(duì)于輸出的要求分為以下幾種:
1.存在最大子序列进萄,則輸出max_sum以及對(duì)應(yīng)的起止數(shù)據(jù)(如果最后一位是0的話,也要將0算進(jìn)最大子序列中)锐峭;
2.不存在最大子序列中鼠,輸出0和輸入的首尾數(shù)據(jù);
3.輸入全為負(fù)數(shù)沿癞,輸出0和輸入的首位數(shù)據(jù)援雇;
4.輸入全為負(fù)數(shù)和0,負(fù)數(shù)全部算作0抛寝,輸出三個(gè)0.
這里面最后一個(gè)條件比較難以發(fā)現(xiàn)熊杨,同時(shí)也要注意與第三中情況區(qū)分開(kāi)。

思路分析

下午剛學(xué)的方法就可以用盗舰,所以這道題最起碼有三種解法晶府,也就是上面的三種算法。
首先是在線處理法钻趋,我實(shí)現(xiàn)輸出的思路是對(duì)最后符合要求的那個(gè)i記為z川陆,說(shuō)明到這結(jié)束,如果this_sum > max_sum蛮位, 則较沪,z更新,同時(shí)子序列長(zhǎng)度count++失仁,最終只要將z減去長(zhǎng)度再加一即可得到子序列首位的數(shù)據(jù)尸曼。如果是使用暴力法的話,就直接將q = i, z = j萄焦,不斷更新即可控轿,不再詳細(xì)說(shuō)明冤竹。實(shí)現(xiàn)思路上肯定是前者較為復(fù)雜,但是算法效率毋庸置疑是前者茬射。

在線處理法:
#include <stdio.h>

int main()
{
    int k = 10, x = 0;
    scanf("%d", &k);
  //int a[] = {-10, 1, 2, 3, 4, 1, -23, 2, 7, -21};
  int a[k];
    int this_sum = 0, max_sum = 0, q = 0, z = 0, count  = 0, ret = 0, fu = 0, zero = 0;
  for(int i = 0; i < k; i++){
    scanf("%d", &a[i]);
    if(a[i] == 0){
      zero++;
    }
    if(a[i] < 0){
      fu++;
    }
  }
  if(fu+zero == k && zero != 0){
    printf("0 0 0");
  }
  else if(fu == k){
    printf("0 %d %d", a[0], a[k-1]);
  }
  else{
    for(int i = 0; i < k; i++){
      this_sum += a[i];
      count++;
      if(this_sum > max_sum){
        max_sum = this_sum;
        z = i;
        ret = 1;    
      }
      if(ret){
        q = z - count+1;
        }
      if(this_sum < 0){
        this_sum = 0; 
        count = 0;
      }
      ret = 0;
    }
    if(max_sum <= 0){
      printf("0 %d %d", a[0], a[k-1]);
    }
    else{
      printf("%d %d %d", max_sum, a[q], a[z]);
    }
  }
    return 0;
}
暴力法(直接搬運(yùn)https://blog.csdn.net/wwk0125/article/details/50444529)
#include<iostream>
#include<cstdio>
using namespace std;
#define maxN 10001
#define Inf 0x3f3f3f
 
int main()
{   
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int a[maxN];
    int k,sum,max=-Inf;
    int L, R;
    cin >> k;
    for (int i = 0; i < k; i++)
        cin >> a[i];
 
    
    for (int i = 0; i < k; i++)
    {
        sum = 0;
        for (int j = i; j < k; j++)
        {
            sum += a[j];
                if (sum>max)
                {
                    max = sum;
                    L = i;
                    R = j;
                }
        }
    }
    if (max<0)  //全為負(fù)數(shù)時(shí),按=0處理鹦蠕,輸出頭尾
        cout << "0" << " " << a[0] << " " << a[k-1] << endl;
    else
    cout << max << " " <<a[L] << " " << a[R] << endl;
    return 0;
}
/*
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
*/

原本以為暴力法會(huì)有一個(gè)點(diǎn)超時(shí),結(jié)果沒(méi)有在抛,早知道就直接暴力了钟病。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市刚梭,隨后出現(xiàn)的幾起案子肠阱,更是在濱河造成了極大的恐慌,老刑警劉巖望浩,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辖所,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡磨德,警方通過(guò)查閱死者的電腦和手機(jī)缘回,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)典挑,“玉大人酥宴,你說(shuō)我怎么就攤上這事∧酰” “怎么了拙寡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)琳水。 經(jīng)常有香客問(wèn)我肆糕,道長(zhǎng),這世上最難降的妖魔是什么在孝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任诚啃,我火速辦了婚禮,結(jié)果婚禮上私沮,老公的妹妹穿的比我還像新娘始赎。我一直安慰自己,他們只是感情好仔燕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布造垛。 她就那樣靜靜地躺著,像睡著了一般晰搀。 火紅的嫁衣襯著肌膚如雪五辽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天外恕,我揣著相機(jī)與錄音奔脐,去河邊找鬼俄周。 笑死,一個(gè)胖子當(dāng)著我的面吹牛髓迎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播建丧,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼排龄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了翎朱?” 一聲冷哼從身側(cè)響起橄维,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拴曲,沒(méi)想到半個(gè)月后争舞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澈灼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年竞川,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叁熔。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡委乌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荣回,到底是詐尸還是另有隱情遭贸,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布心软,位于F島的核電站壕吹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏删铃。R本人自食惡果不足惜耳贬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泳姐。 院中可真熱鬧效拭,春花似錦、人聲如沸胖秒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)阎肝。三九已至挤渔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間风题,已是汗流浹背判导。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工嫉父, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人眼刃。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓绕辖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親擂红。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仪际,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容