1025 反轉鏈表 (25 分) PAT乙級 C++/Python版

1025 反轉鏈表 (25 分) PAT (Basic Level) Practice (中文)

給定一個常數 K 以及一個單鏈表 L,請編寫程序將 L 中每 K 個結點反轉。例如:給定 L 爲 1→2→3→4→5→6,K 爲 3,則輸出應該爲 3→2→1→6→5→4;如果 K 爲 4,則輸出應該爲 4→3→2→1→5→6,即最後不到 K 個元素不反轉。

輸入格式:

每個輸入包含 1 個測試用例。每個測試用例第 1 行給出第 1 個結點的地址、結點總個數正整數 N (≤10​5​​)、以及正整數 K (≤N),即要求反轉的子鏈結點的個數。結點的地址是 5 位非負整數,NULL 地址用 −1 表示。

接下來有 N 行,每行格式爲:

Address Data Next

其中 Address 是結點地址,Data 是該結點保存的整數數據,Next 是下一結點的地址。

輸出格式:

對每個測試用例,順序輸出反轉後的鏈表,其上每個結點佔一行,格式與輸入相同。

輸入樣例:

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

輸出樣例:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

作者: CHEN, Yue

單位: 浙江大學

時間限制: 400 ms

內存限制: 64 MB

代碼長度限制: 16 KB


分析:

  1. 輸入的節點信息,並不是按鏈表順序輸入的。這意味着必須將輸入信息存起來。
  2. 有可能存在“虛假節點”,即該節點並不在實際所求的鏈表上。
  3. 由於題目沒有交代若該鏈表是空鏈表時如何輸出,可以認爲鏈表至少有一個節點。
  4. 每湊夠K個節點來一輪逆置,但最後若湊不夠K個則不逆置!所以要預判數量。
  5. 注意輸出的地址要湊足5位數,除了-1外。

解題思路:

  1. 直接映射哈希法存儲節點:由分析1,且有效地址是不超過5位數的非負整數,用長度爲100000的數組A[]存儲節點。
  2. 用順序表模擬鏈表:用數組link[]按鏈表的順序存儲輸入所代表的鏈表,但只存儲<address,data>,因爲可以用下標遍歷而不需要next。(反正都用了哈希存儲,空間複雜度不可能<O(N)了)
  3. 在順序表(link[])中完成逆置:每湊夠K個節點來一輪逆置,逆置操作用雙指針迭代交換完成,最後不足K個節點跳出。
  4. 將link[]模擬的鏈表打印出來:注意鏈表長度不一定爲N,要以實際記錄的長度爲準,可以在link[]末端插入地址-1作爲哨兵。

Python3版本:(有超時)

因爲最近在學Python,所以一開始就上手Python代碼,如下:

#1025 反轉鏈表 (25 分)
link=[None]*100000  #add最大99999
head,N,K=map(int,input().split(' '))
for i in range(N):
    add,data,next=map(int,input().split(' '))
    link[add]=[data,next]
T,p=[],head
while -1!=p:
    if None==link[p]:break
    #print(p,*node)
    T.append(["%05d"%(p) ,link[p][0]])
    p=link[p][1]
for j in range(K-1,len(T),K):
    i=j-K+1
    while i<j:
        T[i],T[j]=T[j],T[i]
        i+=1
        j-=1
T.append(['-1'])
for i in range(len(T)-1):
    print("%s %d %s"%(T[i][0],T[i][1],T[i+1][0]))

Python的優點是代碼簡潔,但因爲其是解釋型程序,當代碼有大量循環語句和輸入輸出時,那就坑了。如果有大佬能用Python版本AC的,請賜教。


C++版本(AC)

和上面的Python解法完全一樣,只因爲輸入輸出快了,所以能AC。

//1025 反轉鏈表 (25 分)
#include <stdio.h>
#include<map>
using namespace std;
pair<int, int> A[100000];	//0~99999   A[]=<data,next>
int main(){
	int head, N, K;
	scanf("%d %d %d", &head, &N, &K);
	pair<int, int> *link = new pair<int, int>[N+1];	//用順序表模擬鏈表
	while (N-- > 0) {
		int p, data, next;
		scanf("%d %d %d", &p, &data, &next);
		A[p] = { data,next };	//直接映射哈希存儲:p爲關鍵詞
	}
	int len = 0;	//link數組(代表鏈表)的有效長度
	while (-1 != head) {
		link[len++] = { head,A[head].first };	//={add,data}
		head = A[head].second;					//=next
	}
	for (int step = K; step <= len; step+=K) {	//每湊足K個逆置
		for (int i = step - K, j = step - 1; i < j; i++, j--) {
			swap(link[i], link[j]);	//交換
		}
	}
	for (int i = 0; true; ) {
		printf("%05d %d ", link[i].first, link[i].second);
		if (++i<len) 
			printf("%05d\n", link[i].first);
		else{	//是最後一個
			printf("-1\n"); break;
		} 
	}
	return 0;
}

其實沒比Python版本長多少,所以此題不適合用Python。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章