1. 程式人生 > 實用技巧 >最長 上升/下降/不上升/不下降 子序列長度

最長 上升/下降/不上升/不下降 子序列長度

1.lower_bound & upper_bound

Ⅰ 作用

兩者均屬STL函式,在標頭檔案 algorithm

假設我們查詢x,那麼:

lower_bound會找出序列中第一個大於等於x的數

upper_bound會找出序列中第一個大於x的數

沒錯這倆就差個等於號╮(╯▽╰)╭

Ⅱ 用法

以下都以lower_bound做栗子 (因為upper_bound做出的栗子不好吃)

(兩者使用方法同理)

它們倆使用的前提是一樣的:序列是有序的

對於一個數組a,在[1,n]的區間內查詢大於等於x的數(假設那個數是y),函式就寫成:

lower_bound(a + 1, a + 1 + n, x);

函式返回一個指向y的指標

看著是不是很熟悉?回想sort使用的時候:

sort(a, a + 1 + n, cmp);

這裡a+1,a+1+n的寫法是不是很像?

STL裡面的函式寫區間一般都這個尿性

同樣的,lower_bound和upper_bound也是可以加比較函式cmp的:

lower_bound(a + 1, a + 1 + n, x, cmp);

到這裡不得不說說前面的"有序序列",這裡的"有序"是對什麼有序?

你可能已經猜到了,它是對於比較器有序,並且必須是升序!

(為什麼不是降序?這個你可能要去問問寫STL的人)

一旦對降序序列使用lower_bound,就會出現神奇的錯誤,具體原因可以看這篇:

https://blog.csdn.net/qq1337715208/article/details/81072709

當然比較器預設也是"<"

如果要在一個下降序列裡尋找一個小於x的數呢?

根據我們之前說的,lower_bound只能對上升序列使用,那我假裝下降序列是個上升序列就行了嘛~

(lower_bound:你當我傻嗎)(w1049:沒錯我就當你傻)

只需要把比較器改成">":

同時需要寫一個函式cmp:

bool cmp(const int& a,const int& b){return a > b;}

當然,你也可以這樣:

lower_bound(a + 1, a + 1 + n, x, greater <int> () );

這裡的greater()就是c++友情提供的方便的大於函式,這樣就不用自己動手寫一個cmp函數了(其實就是懶)

它們的實現方式是二分查詢 ,存在的意義就是讓我們寫程式碼更方便地偷懶(一行lower_bound比寫二分查詢方便多了)

Ⅲ返回值

對於返回值我們有兩種處理方式:

第一種:

許多人討厭指標,那麼我們用這個指標減去陣列開頭的指標(即陣列名),得到兩個指標的差,就是陣列下標,即:

int p = lower_bound(懶得寫) - a;

那麼a[p]就是要找的y

(如果不知道為什麼就記著好了)

第二種:

指標好!指標妙!

改革春風吹滿地,用指標的oier真爭氣!

(以上兩行你可以當做什麼都沒看見)

int *p = lower_bound(還是懶得寫);

那麼*p就是要找的y

可以看出指標多麼直接,不像陣列下標還要倒騰一遍

總結一下:

好像沒什麼可總結的QwQ

對一個下降序列a

int p = lower_bound(a + 1, a + 1 + n, x, greater <int> () ) - a;

a[p]即a[1]到a[n]中第一個小於等於x的數

(被遺忘的upper_bound表示不服)

2.nlog(n)演算法實現

Ⅰ實現方法

首先我們需要一個數組a,儲存從第1個到第n個導彈的高度

然後一個數組d(其實是個棧),儲存不上升序列

把a中的每個元素挨個加到d裡面:

(a中第i個元素為a[i],d長度為len,d中最後一個(也是最小的一個)為d[len])

如果a[i] <= d[len],說明a[i]可以接在d後面(而整個d還是有序的),那就簡單粗暴地把a[i]丟進d:

d[++len] = a[i]

如果a[i] > d[len],說明a[i]接不上
但是我們發揚瞎搞精神:接的上要接,接不上創造條件也要接!

強行把a[i]塞進去:
在d中找到第一個小於a[i]的數,把它踹了,用a[i]代替它!(為什麼正確在下面)

假設這個數是y,怎樣踹掉它呢?

很明顯,我們需要使用lower_bound和upper_bound來查詢

第一步,找一個聽起來無比正確的理由,比如它佔著位置不幹活啦,幹起活來還不如a[i]啦,naive啦,它too young啦,too simple啦......反正能騙過lower_bound和upper_bound就行

(lower_bound&&upper_bound:你當我們傻)(w1049:真聰明)

接下來,特別有正義感的lower_bound和upper_bound就會去把y給拎出來

第二步,考慮使用什麼

我們知道,要求的是最大不上升子序列長度,也就是如果兩個元素相等也是可以的

所以我們踹人就不用踹等於a[i]的了

結合上面,應該使用upper_bound(終於想起來它了)並且使用>作為比較器(這是個下降序列)

第三步,直接開搞

int p = upper_bound(d + 1, d + 1 + len, a[i], greater<int>()) - d;
  
d[p] = a[i];

成功把a[i]塞了進去

Ⅱ 為什麼正確

若被替代掉的即為最大不上升子序列中的某一元素
那麼替代者與剩下的元素的關係依然滿足與被替代者的關係,顯然成立(也就是說替代者可以完全替代被替代者,並且擁有更廣泛的天空)
為什麼說是更廣泛的天空?
因為被替代者可以取到的範圍更大,它不僅可以做到代替作用,同時可以更新自己的序列,做到一箭雙鵰
這也就是為什麼這個演算法只能求長度而不能求具體的陣列

實際上,d[i] 的含義是:最大不上升子序列長度為 i 時,最優的結尾元素。