1. 程式人生 > >7-7 最長連續遞增子序列(20 分) 普通STL解出

7-7 最長連續遞增子序列(20 分) 普通STL解出

這道題我看了一下  決定寫。 在寫之前網上看到很多高手的題解,深表敬意。

只是我想用STL來完成一下這道題。

7-7 最長連續遞增子序列(20 分)

給定一個順序儲存的線性表,請設計一個演算法查詢該線性表中最長的連續遞增子序列。例如,(1,9,2,5,7,3,4,6,8,0)中最長的遞增子序列為(3,4,6,8)。

輸入格式:

輸入第1行給出正整數n(≤10​5​​);第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日