PAT(甲级)2019年秋季考试 7-2 Merging Linked Lists (25 分)
题目描述:
Given two singly linked lists L1=a1→a2→?→an?1→an and L2=b1→b2→?→bm?1→bm. If n≥2m, you are supposed to reverse and merge the shorter one into the longer one to obtain a list like a1→a2→bm→a3→a4→bm?1?. For example, given one list being 6→7 and the other one 1→2→3→4→5, you must output 1→2→7→3→4→6→5.
译:给定两个单链表 L1=a1→a2→?→an?1→an 和L2=b1→b2→?→bm?1→bm。如果 n≥2m 你应该反转并将较短的合并到较长的一个以获得类似的列表 a1→a2→bm→a3→a4→bm?1?。例如,给定一个链表6→7 和另外一个链表 1→2→3→4→5,你应该输出1→2→7→3→4→6→5。
Input Specification (输入说明):
Each input file contains one test case. For each case, the first line contains the two addresses of the first nodes of L1 and L2, plus a positive N (≤105) which is the total number of nodes given. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1
.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address
is the position of the node, Data
is a positive integer no more than 105, and Next
is the position of the next node. It is guaranteed that no list is empty, and the longer list is at least twice as long as the shorter one.
译:每个输入文件包含一个测试用例,对于每种情况,第一行包含表示L1 和 L2 的首节点的地址,再加上一个表示给出结点总数的正整数 N (≤105) 。一个结点的地址是一个 5 位的非负数,并且空节点用 -1 表示。
接下来 N 行,每行用如下格式描述一个结点:
Address Data Next
Address
表示节点地址, Data
是一个不超过 105 的正整数, Next
是下一结点的地址。题目保证链表不为空,并且长链表的长度至少是短链表的长度的两倍。
Output Specification (输出说明):
For each case, output in order the resulting linked list. Each node occupies a line, and is printed in the same format as in the input.
译:对于每种情况,将结果链表依次输出。每个结点占一行,格式和输入格式相同。
Sample Input (样例输入):
00100 01000 7
02233 2 34891
00100 6 00001
34891 3 10086
01000 1 02233
00033 5 -1
10086 4 00033
00001 7 -1
Sample Output (样例输出):
01000 1 02233
02233 2 00001
00001 7 34891
34891 3 10086
10086 4 00100
00100 6 00033
00033 5 -1
The Idea:
题目中明确说明了,两个链表是有长有短的,而且长的链表的长度 n 和短的链表的长度 m 一定满足 n >= 2m
需要注意的地方:
- 并没有指明哪个是长链表,哪个是短链表
- 并不是给出的所有结点,都是链表上的节点(存在无效节点,最后两个测试点)
我的思路是用结构体模拟链表,然后因为合并的时候,是隔两个加一个,而且加的是逆序,可以选择先将短链表翻转过来,但是这里我选择了使用 栈 , 这样很方便进行取出需要添加的节点。
The Codes:
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 100010 ;
struct node{
int data , next ;
}link[maxn] ;
int l1 , l2 , n , id , ans ;
void merge(int start , stack<int> st){
ans = start ; // 记录最后的合并后的起始地址
for(int i = 0 ; !st.empty() ; i ++){
if(i > 0 && (i + 1) % 2 == 0){
int top = st.top() ;
st.pop() ;
link[top].next = link[start].next ;
link[start].next = top ;
start = link[top].next ;
}else start = link[start].next ;
}
}
int main(){
scanf("%d%d%d" , &l1 , &l2 , &n) ;
for(int i = 0 ; i < n ; i ++){
scanf("%d" , &id) ;
scanf("%d%d" , &link[id].data , &link[id].next) ;
}
int p = l1 , q = l2 ;
stack<int> st1 , st2 ;
while(p != -1 && q != -1){ // 将短链表的所有结点全部 入栈
st1.push(p) ;
p = link[p].next ;
st2.push(q) ;
q = link[q].next ;
}
if(p == -1) merge(l2 , st1) ; // 如果 l1 是短链,则将 l1 合并到 l2 中
else merge(l1 , st2) ; // 如果 l2 是短链,则将 l2 合并到 l1 中
while(link[ans].next != -1){ // 不是 n 个,因为有无效节点
printf("%05d %d %05d\n" , ans , link[ans].data , link[ans].next) ;
ans = link[ans].next ;
}
printf("%05d %d -1\n" , ans , link[ans].data) ;
return 0 ;
}
用数组的前后关系模拟链表的前后结点,这种思路值得借鉴!!!
#include<bits/stdc++.h>
using namespace std;
struct node {
int data, addr;
};
node nodes[100005];
int main() {
int headA, headB, n;
cin >> headA >> headB >> n;
for (int i = 0; i < n; ++i) {
int address, data, next;
cin >> address >> data >> next;
nodes[address] = {data, next};
}
vector<node> a, b, c;
for (int p = headA; p != -1; p = nodes[p].addr)
a.push_back({nodes[p].data, p});
for (int p = headB; p != -1; p = nodes[p].addr)
b.push_back({nodes[p].data, p});
if (a.size() < b.size()) swap(a, b);
reverse(b.begin(), b.end());
for (int i = 0, j = 0, k = 0; i < a.size() || j < b.size(); ++k) {
if (k % 3 == 2 && j < b.size()) c.push_back(b[j++]);
else c.push_back(a[i++]);
}
for (int i = 0; i < c.size(); ++i) {
printf("%05d %d ", c[i].addr, c[i].data);
if (i == c.size() - 1) cout << "-1\n";
else printf("%05d\n", c[i + 1].addr);
}
}