7-7 最長連續遞增子序列(20 分) 普通STL解出
這道題我看了一下 決定寫。 在寫之前網上看到很多高手的題解,深表敬意。
只是我想用STL來完成一下這道題。
7-7 最長連續遞增子序列(20 分)
給定一個順序儲存的線性表,請設計一個演算法查詢該線性表中最長的連續遞增子序列。例如,(1,9,2,5,7,3,4,6,8,0)中最長的遞增子序列為(3,4,6,8)。
輸入格式:
輸入第1行給出正整數n(≤105);第2行給出n個整數,其間以空格分隔。
輸出格式:
在一行中輸出第一次出現的最長連續遞增子序列,數字之間用空格分隔,序列結尾不能有多餘空格。
輸入樣例:
15 1 9 2 5 7 3 4 6 8 0 11 15 17 17 10
輸出樣例:
3 4 6 8
這次我要使用一個名叫 雙端佇列的東西 deque .
本次練習 共測試了幾個樣例
1 . 1 2 3 4 5
2. 5 4 3 2 1
3. 1 2 3 1 2 3 4
4. 5 4 3 2 1 2 3 4 5 6 6 7 8 9 10 9
5. 0
我的程式碼是怎樣想出來的??
1.看到題目之後 我想 既然是一個遞增子序列 我可以用 雙端佇列陣列儲存下這些數列 然後動用帶cmp函式的sort排序輸出雙端佇列陣列的首地址下的所有元素。 比如題目樣例 1 9 2 5 7 3 4 6 8 0 11 15 17 17 10 可想而知 1 9 存在 [0] ,2 5 7 存在 [1] , 3 4 6 8 存在 [2] , 0 11 15 17存在 [3] 17 存在 [4] 10 存在 [5] 這個時候題目有一個重要的 提示 “
什麼!!第一次。這可難辦了 因為數數的序列其實並不是有序的 那我在排序時候可想而知 我不知道誰才是第一子序列,自然會在這裡栽跟頭。這裡當然有兩種辦法,第一種建一個標記陣列 map<deque<int>,int>,第二個 直接在儲存上面搞。
我選擇了第二個 我把 deque 定義的時候修改為 deque<pair<int,int> >[10000+10] 第一個引數是存元素的 第二個引數是存這個元素的所在組的位置。但是 這是不可取的 !! 為什麼?因為題目中 1五個零就是 10W的資料量 ,雙端佇列陣列就相當於是一個 行已知 列未知的二維陣列, 這時候即便完成也一定會報 記憶體超限 【想想二維陣列 再想想10W資料量 , 然後往sh雙端裡插入了pair 然後還開了 100000+10 的空間】
顯然以上方法是不可取的 ,我們可以來欣賞一下shan上面完成的程式碼。 【記憶體超限 不可取】
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
deque<pair<int,int> > f[100000 + 10];
int cnt = 0;
int x;
bool cmp(deque<pair<int,int> >A, deque<pair<int, int> >B) {
if (A.size() < B.size()) return false;
else if (A.size() == B.size() && A.front().second > B.front().second) return false;
return true;
}
int main() {
scanf("%d", &x);
int tmp;
for (int i = 0; i < x; i++) {
int inp;
scanf("%d", &inp);
if (i == 0) {
tmp = inp;
f[cnt].push_back({inp,cnt});
}
else {
if (inp <= tmp) {
i = inp;
cnt++;
f[cnt].push_back({ inp,cnt });
}
else {
f[cnt].push_back({ inp,cnt });
}
}
tmp = inp;
}
sort(f, f + cnt, cmp);
for (int i = 0; i < f[0].size(); i++) {
i == 0 ? printf("%d", f[0][i]) : printf(" %d", f[0][i]);
}
system("pause");
return 0;
}
轉折-- 雙變數 爆破成功
難道 這就無解了嗎 看看鐘表 凌晨 2:45 分 算了 明天起來再說吧! 躺在床上睡不著,都說睡覺要在 24:00 -- 3:00 才有益。睡不著就會胡思亂想。想著想著 突然想到 不需要陣列 不需要sort 只需要 兩個 deque<int>的變數即可。········【睡著了】
·····早晨 8:00 :
拿出了題目想到了半夜的思路 就試了一下。
思路是這樣的 :
1 . 定義兩個 deque<int> 的變數 一個為答案變數 一個為臨時變數A 。
2 .定義 臨時變數B 儲存上一次 輸入的值。
2.1. 考慮到 臨時變數B第一次要單獨處理。
3.接著每次輸入[除去第一次] 都用現輸入的值和臨時變數B相比較 如果比臨時變數大則 更新臨時變數B 同時把 輸入的值放入臨時變數A之中(尾插)
3.1.如果臨時變數小於等於 輸入的值 那麼 判斷臨時變數A的 size()是不是 大於(沒有等於,為什麼見 3.2.)答案變數的size(),如果大了就更新,接著執行 臨時變數A.clear(); 再把剛剛輸入的值放入臨時變數接著下一次迴圈。如果小了就不更新,接著執行 臨時變數A.clear(); 再把剛剛輸入的值放入臨時變數接著下一次迴圈。
3.2. 沒有等於源於 題目中 “在一行中輸出第一次出現的最長連續遞增子序列” 我們知道我們是從頭往後去遍歷的,那麼
假定我們 前面已經得到一個長度為 5 的連續序列 那一定就是最先出現的長度為5的子序列 如果後面又出現 臨時bian變數的序列長度為 5 那麼 它就不可能代替答案序列 成為答案。因為以己有比它優先的長度為5的序列。
就是這樣核心思路核心的程式碼出來了:
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
class firstq {
public:
deque<int> f; // 答案變數
deque<int> ftmp; // 臨時變數A
int cnt = 0; // 第一次更新策略
int x; // 資料量
int F() {
scanf("%d", &x);
int tmp; // 臨時變數B
for (int i = 0; i < x; i++) {
int inp;
scanf("%d", &inp);
if (i == 0) {
tmp = inp;
ftmp.push_back(inp);
}
else {
if (inp <= tmp) {
if (cnt == 0) f = ftmp; // 第一次更新策略使用地方
else if (cnt&&f.size() < ftmp.size()) f = ftmp;
cnt++; // 第一次更新策略唯一修改地方
ftmp.clear();
ftmp.push_back(inp);
}
else {
ftmp.push_back(inp);
}
}
tmp = inp;
}
if (f.size() < ftmp.size()) f = ftmp;
for (int i = 0; i < f.size(); i++) {
i == 0 ? printf("%d", f[i]) : printf(" %d", f[i]);
}
system("pause");
return 0;
}
};
int main() {
firstq A;
A.F();
}
PS.寫CLASS主要是想和其他網上程式用對數器驗證。
----來自海南,在山東
2018年8月16日