序列操作-美團點評2018秋
1.題目描述
有一天你得到了一個長度爲 n 的序列,序列中的元素分別爲 1,2,3,…,n。接下來你想對這個 序列進行一些操作。每一操作你會選擇一個數然後將它從序列中原來的位置取出並放在序列的最前面。你 想知道經過一系列操作後這個序列長什麼樣。
- 輸入描述:
第一行包含兩個個整數 n、m,分別標書序列的長度和操作的個數。1≤n,m≤105,接下來 m 行每行包含一個整數 ki,表示你要把 ki放到序列的最前面。1≤ki≤n - 輸出描述:
從前往後輸出序列中的每個元素,每個元素佔一行。 - 輸入樣例:
5 3
4
2
5
- 輸出樣例:
5
2
4
1
3
2.題目解析
從題目本身看,容易得出數組移動的處理方式,但是效率比較低
#include <bits/stdc++.h>
using namespace std;
void move(int *arr, int n, int num) {
// 查找位置
int pos = 0;
for(int i=0;i!=n;++i){
if(arr[i] == num){
pos = i;
break;
}
}
// 位置前的向後移動
for(int i=pos;i!=0;--i){
arr[i] = arr[i-1];
}
arr[0] = num;
}
int main() {
int n = 0;
int m = 0;
scanf("%d%d",&n,&m);
// 初始化數列
int arr[n];
for(int i=0;i!=n;++i){
arr[i] = i+1;
}
// 獲取移動數據
while(m--){
int num = 0;
scanf("%d", &num);
move(arr, n, num);
}
// 打印移動結果
for (int i = 0; i != n; ++i) {
printf("%d\n",arr[i]);
}
return 0;
}
數組易查不易動,鏈表易動不易查。
- 優化效率
線性雙向鏈表:連續內存的雙向鏈表,以下標作爲連接。
3.參考答案
#include <bits/stdc++.h>
using namespace std;
struct Node{
int prev; // 前一個數據
int post; // 後一個數據
};
void Print(Node* nodes,int n,int head){
int now = head;
while(now != n+1){
printf("%d\n",now);
now = nodes[now].post; // 向後遍歷
}
}
int main() {
int n = 0;
scanf("%d",&n);
Node nodes[n+1];
// prev爲0表示開始
// post爲n+1表示結束
for(int i=1;i<=n;++i){
nodes[i].prev = i-1;
nodes[i].post = i+1;
}
// 遍歷鏈表
int head = 1;
int m = 0;
scanf("%d",&m);
for(int i=0;i<m;++i){
int move = 0;
scanf("%d",&move);
if(move == head) continue; // 如果要移動的數據已經在頭節點,不處理
int prev = nodes[move].prev;
int post = nodes[move].post;
nodes[prev].post = post;
nodes[post].prev = prev;
nodes[move].prev = 0;
nodes[move].post = head;
nodes[head].prev = move;
head = move; // 更換頭節點下標
}
Print(nodes,n,head);
}
#include <bits/stdc++.h>
using namespace std;
int main() {
int n = 0;
int m = 0;
scanf("%d%d",&n,&m);
// 位置記錄(數字與下標保持一致,下標0不使用)
// 設定第一個數的prev爲0,最後一個數的next爲n+1
int prev[n+1];
int next[n+1];
for(int i=1;i!=n+1;++i){
prev[i] = i-1;
next[i] = i+1;
}
int top = 1;// 頂部數字
// 移動
while(m--){
int num;// 移動的數字
scanf("%d",&num);
if(num == top){// 數字在頂不處理
continue;
}
// 把前面的與後面連在一起
next[prev[num]] = next[num];
// 把後面的與前面連在一起
prev[next[num]] = prev[num];
// 修改當前數字的連接
prev[num] = 0;
next[num] = top;
// 修改頂部的連接
prev[top] = num;
// 當前數字作爲新的頂部
top = num;
}
// 打印結果
for(int i = 0;i!=n;++i){
printf("%d\n",top);
top = next[top]; // 依次移動top
}
return 0;
}