填坑Ⅰ | 簡單的數據結構

19. 填坑Ⅰ

成績 10 開啓時間 2020年09月17日 星期四 12:00
折扣 0.8 折扣時間 2020年09月24日 星期四 12:00
容許遲交 關閉時間 2020年10月10日 星期六 23:00

Descriptionc++

又是北湖深坑,驚不驚喜,意不意外?!程序員

Rack以爲用水填湖太沒意思了,用石頭填坑多有意思。假設北湖的地面仍是一維的,每一塊寬度都爲1,高度是非負整數,用一個數組來表示。現提供不限量的1x2規格的石頭,問是否能夠將北湖填平。(全部地面到達同一高度即爲填平)算法

注:石頭只能水平或垂直填放。編程

Input數組

樣例有多組輸入至文件末尾;每組用例佔兩行;數據結構

第一行輸入1個整數n表示北湖地面總寬度;函數

第二行輸入n個整數用空格間隔,表示地面高度。測試

Outputspa

若能填平則輸出「YES」,不然輸出「NO」。.net

  測試輸入 期待的輸出 時間限制 內存限制 額外進程
測試用例 1
  1. 5↵
  2. 2 1 1 2 5↵
  3. 3↵
  4. 4 5 3↵
  5. 3↵
  6. 1 2 3↵
  1. YES↵
  2. YES↵
  3. NO↵
1秒 64M 0

 1、預熱知識

        在說具體的算法以前,首先咱們要知道這個數據結構,以前在 「括號匹配」 裏我已經簡單提到過棧。關於棧,你如今只須要知道兩點

一、它的特色:單口出入,先進後出。


二、它的使用
      注意,小學期你直接學會c++封裝的STL的使用便可,至於它是怎麼實現的,下學期數據結構這門課有你學的。

#include <stack>  //導入庫
using namespace std;  //肯定命名空間

stack<int>  s;  //定義一個元素是整型的棧,命名爲s

int a;
s.push(a);   //將整型變量壓入棧頂

s.size();   //返回棧內元素個數

s.empty();  //返回棧是否爲空

/* 注意,如下的操做必須先保證棧不爲空,不然會re */

int b = s.top();  //查看棧頂元素,存入變量b中

s.pop();  //出棧:棧頂元素彈出(注意,這個函數返回值爲空)


      若是你學有餘力,也能夠看看雞翅總結的棧的數據結構筆記,貼心傳送門:

      Stack | 棧的數組實現

      Stack | 棧實現 —— 後綴表達式

      Stack | 棧實現 —— 符號配對

2、算法分析

下面來分析一下這道題:
       用1x2的石頭填坑,應該這樣理解:能夠每次將單位長度升高2米,或者能夠將連續兩個單位長度同時增加1米

       因爲咱們最後的目的就填平至任意整數高度。那麼對於兩個同高的相鄰地方,他們絕對是不會影響咱們的結果的。由於咱們能夠一米一米地對他倆增高,到任意咱們想要的高度。故兩兩相同高度的地方咱們能夠直接忽略!好比高度1 2 2 3,咱們能夠直接視爲1 3相鄰,忽略其中兩個。因此相鄰的定義就放大了。(這裏必定要弄明白,這是整個思路的核心,若是不明白就看看後面的再仔細想一想)


       那麼咱們的思路就出來了,下面是最清楚的思路,其餘方法均可以等價地替換成這個方法的處理。因此如下的方式能夠正確地解決判斷問題:

Ⅰ、 首先找到最高點

Ⅱ、 將石頭以1爲底2爲高來使用,咱們儘可能將每一處升高到最高點處:

  • 與最高點相差奇數個高度,能夠填至與最高處只相差一米。記爲1
  • 與最高點相差偶數個高度,能夠剛好填至與最高處齊平。記爲0

Ⅲ、而後依次遍歷記錄下來的整個01串,有相同的在一塊兒能夠兩兩相消,若是最後01串內元素大於1,那麼說明北湖永遠填不平嘍!


       你不能理解的就是爲啥能夠兩兩相消吧,看看以下例子(測試用例1:2 1 1 2 5)。咱們先讓每一列貼近最高點,最後的01串爲10010。接着能夠消成110,接着能夠消成0,因此最後輸出YES

       認真理解一下二、3列爲何不影響最後的結果,咱們能夠直接將二、3列抵消掉?你想一想咱們怎麼再在以下基礎上填平,想好了你估計能明白,由於二、3它們能夠以1爲單位配合到任何高度,不影響咱們的結果,能夠直接忽略!!!這裏有點只可意會的感受,你若是想不通就多想幾個用例....

3、算法實現


       你如今應該想到了算法應該怎麼實現吧!先找到最高點,而後依次記錄每一點與最高點相差高度的奇偶性,奇數記爲1,偶數記爲0。而後討論這個01數組...而後得出結果....前面的思路都是對的,而若是你用數組這個數據結構儲存,到最後去處理數組裏存儲的01串結果,就有點繁瑣了...可是!你有沒有想到你沒有用到棧誒!有更加簡單處理01串的辦法!用棧!


       你想一想棧的特色要怎麼應用到這個題裏呢!棧每次只能訪問和處理棧頂的元素,若是咱們依次討論並將相同的0/1消掉,是否是棧就特別合適呢!這麼說好抽象,棧這種微妙的做用,你仔細看看例子來理解:


好了,下面給出完整AC代碼:

不對,再另外提幾嘴。別嫌我囉嗦,說不定給你減小几小時debug的時間。

一、scanf返回值的問題

       不知道你有沒有注意過,樂學提交題目常常會給你返回這樣一個warning。(雖然咱們程序員常常忽略warning只在意error)

        這就是字面意思,你忽略了scanf函數的返回值!什麼?我用了這麼久的scanf函數還有返回值!?我歷來沒有用過啊,它不是輸入的嗎!但是你可能忘了c裏全部函數都有設定返回值(void爲空)。從這裏咱們能夠看到scanf返回值爲int類型。什麼意思呢?這個會返回一個是否成功輸入的標識,具體的我就不說了。當 c 在處理輸入時,一一讀取文件內容,當每有能夠讀取的時候,scanf的返回值就是EOF。 EOF是一個C標準庫定義的常量,不知道你是否還依稀記得 C 語言裏把常量用大寫字母來標識。(就好比下面代碼我就定義了一個常量MAXN,只不過是宏定義的形式哈...)

二、循環輸入必須注意

        這道題又是循環處理輸入的一個題,不少朋友會先寫出通常的處理代碼再套上循環。或許你也苦惱過爲啥我運行過沒有問題呀,再次運行就不對了呢?這種的多樣例測試必定要注意,若是你沒有在每次循環前將變量都初始化,你頗有可能後面一直在反覆在以前的基礎上使用變量!最好的檢測方式就是輸入兩次同樣的用例,看看結果是否相同,若是不一樣,那麼恭喜你中招了!

       因此每定義一個變量就對它初始化這是一個很棒的編程習慣基本數據類型好比int,double之類的我就不說了,數組咱們一般用string.h或cstring類中的memset函數進行初始化,棧咱們通常在使用前要初始化爲空!

       這裏的易錯點就是,你沒有每次把棧清空!!後面的運行就會以上一次棧內剩餘元素打底。


#include<cstdio>
#include<cstring>
#include<stack>

using namespace std;

#define MAXN 200010

long long int a[MAXN] = {0};
stack<int> stk;

int main() {
    long long int n;

    //當輸入沒有停止的時候,讀入 n
    while (EOF != scanf("%lld", &n)) {

        /* 初始化 */
        int maxElement_index = 0;  //記錄對高點的下標
        memset(a, 0, sizeof(a[0]));   //將數組a全都賦值爲 0
        while (!stk.empty())  //清空棧
            stk.pop();

        /* 處理輸入 */
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            //找出最高點下標
            if (a[i] > a[maxElement_index])
                maxElement_index = i;
        }

        /* 核心算法部分 */
        int temp;
        for (int i = 1; i <= n; i++) {
            if ((a[maxElement_index] - a[i]) % 2 == 1) //差的高爲奇數
                temp = 0;
            else  //差的高爲偶數
                temp = 1;

            if (!stk.empty() && temp == stk.top())  //棧非空的前提下:與前一個能夠對應相消時
                stk.pop();
            else
                stk.push(temp);
        }

        /* 處理結果 */
        int remainCount = stk.size();   //計算棧內剩餘元素
        if (remainCount <= 1)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

End

歡迎關注我的公衆號「雞翅編程」,這裏是認真且乖巧的碼農一枚,旨在用心寫好每一篇文章,日常會把筆記彙總成推送更新~

相關文章
相關標籤/搜索