PAT乙级 链表题-1025、1075、1105、1110
题目:
PAT乙级1025 反转链表
https://pintia.cn/problem-sets/994805260223102976/exam/problems/994805296180871168
PAT乙级1075 链表元素分类
https://pintia.cn/problem-sets/994805260223102976/exam/problems/994805262953594880
PAT乙级1105 链表合并
https://pintia.cn/problem-sets/994805260223102976/exam/problems/1478634321389170688
PAT乙级1110 区块反转
https://pintia.cn/problem-sets/994805260223102976/exam/problems/1478634682663895040
总体分析:
1、几道题思路基本一致,都是用较大的数组模拟链表行为。
list数组下标作为节点地址,数组元素记录数据和下一节点地址。
struct Node
{
int addr;
int data;
int next;
}list[100001];
2、可以转到提取有效节点到新数组处理链表(1025、1075),也可以在大数组中直接处理(1105、1110)。
//按顺序提取链表到新数组
while(ptr != -1)
{
list1[length] = list[ptr];
list1[length].id = length;
length++;
ptr = list[ptr].next;
}
//链表的反转--直接在大数组处理
ptr2 = -1; int ptr2_next = head2;
while(ptr2_next != -1)
{
int temp = list[ptr2_next].next;
list[ptr2_next].next = ptr2;
ptr2 = ptr2_next;
ptr2_next = temp;
}
代码及分析:
PAT乙级1025 反转链表:
完成部分节点的反转,直接对部分节点进行排序比较清晰,因此在获取节点正确顺序后可以加入节点排序数据id。
根据k使用sort函数反转部分链表,反转后首尾节点的地址需要更新。
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct Node
{
int addr;
int data;
int next;
int id = 0;
}list[100001];
bool cmp(Node n1, Node n2)
{
return n1.id > n2.id;
}
int main()
{
int head, n, k;
cin >> head >> n >> k;
for(int i = 0; i < n; i++) //数据输入
{
int addr;
cin >> addr;
list[addr].addr = addr;
cin >> list[addr].data >> list[addr].next;
}
Node list1[n];
int ptr = head, length = 0;
while(ptr != -1) //将链表转移至小数组(只有有效节点被记录)
{
list1[length] = list[ptr];
list1[length].id = length; //为方便反转,添加一个id数据
length++;
ptr = list[ptr].next;
}
for(int i = 0;i < length; i += k) //根据id降序排列,即完成链表部分反转
{
if(i + k <= length)
{
sort(list1 + i, list1 + i + k, cmp);
}
}
for(int i = 0; i < length; i++) //输出反转后新的下一节点地址
{
printf("%05d %d ", list1[i].addr, list1[i].data);
if(i == length - 1) printf("-1\n");
else printf("%05d\n", list1[i+1].addr);
}
return 0;
}
PAT乙级1075 链表元素分类:
最开始的思路是将有效节点集中到一个数组后,根据特定规则排序;
cmp中:一个节点的数据>=0、一个<0的时候,则升序排;如果一个在[0,k]内,一个不在,则升序排;其他情况全不排。
bool cmp(Node n1, Node n2)
{
if((n1.data < 0 && n2.data >= 0) || (n1.data >= 0 && n2.data < 0))
return n1.data < n2.data;
else if((n1.data >= 0 && n1.data <= k && n2.data > k) ||
(n1.data > k && n2.data >= 0 && n2.data <= k))
return n1.data < n2.data;
else return false;
}
但是测试点5一直答案错误,未发现原因,后更改为将不同类型的节点一次存入三个数组,再按顺序输出即可。
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct Node
{
int addr;
int data;
int next;
}list[100001];
int head, n, k;
int main()
{
cin >> head >> n >> k;
for(int i = 0; i < n; i++)
{
int addr;
cin >> addr;
list[addr].addr = addr;
cin >> list[addr].data >> list[addr].next;
}
int ptr = head;
Node list1[n], list2[n], list3[n];
int length1 = 0, length2 = 0, length3 = 0;
while(ptr != -1) //对不同的节点分类,存储到不同的数组去
{
if(list[ptr].data < 0)
{
list1[length1] = list[ptr];
length1++;
}
else if(list[ptr].data >= 0 && list[ptr].data <= k)
{
list2[length2] = list[ptr];
length2++;
}
else
{
list3[length3] = list[ptr];
length3++;
}
ptr = list[ptr].next;
}
//顺序输出三个数组
for(int i = 0; i < length1; i++)
{
printf("%05d %d ", list1[i].addr, list1[i].data);
if(i != length1 - 1) printf("%05d\n", list1[i + 1].addr);
else if(length2 == 0 && length3 == 0) printf("-1\n");
}
for(int i = 0; i < length2; i++)
{
if(i == 0 && length1 != 0) printf("%05d\n", list2[0].addr);
printf("%05d %d ", list2[i].addr, list2[i].data);
if(i != length2 - 1) printf("%05d\n", list2[i + 1].addr);
else if(length3 == 0) printf("-1\n");
}
for(int i = 0; i < length3; i++)
{
if(i == 0 && (length1 != 0 || length2 != 0)) printf("%05d\n", list3[0].addr);
printf("%05d %d ", list3[i].addr, list3[i].data);
if(i != length3 - 1) printf("%05d\n", list3[i + 1].addr);
else printf("-1\n");
}
return 0;
}
PAT乙级1105 链表合并:
思路:比较两个链表长度,反转短链表,长链表每两个节点间加入一个短链表节点。
直接在大数组中操作,行为和实际链表类似,新节点连接到长链表上一节点next,断掉新节点next指针,指向长链表下一节点。
#include<iostream>
#include<stdio.h>
using namespace std;
struct Node
{
int addr;
int data;
int next;
}list[100001];
int main()
{
int head1, head2, n;
cin >> head1 >> head2 >> n;
for(int i = 0; i < n; i++)
{
int addr;
cin >> addr;
list[addr].addr = addr;
cin >> list[addr].data >> list[addr].next;
}
int length1 = 0, length2 = 0;
int ptr1 = head1, ptr2 = head2;
while(ptr1 != -1 || ptr2 != -1) //记录比较两个链表长度
{
if(ptr1 != -1)
{
length1++;
ptr1 = list[ptr1].next;
}
if(ptr2 != -1)
{
length2++;
ptr2 = list[ptr2].next;
}
}
if(length1 < length2) //保证1长2短
{
int temp = head1; head1 = head2; head2 = temp;
temp = length1; length1 = length2; length2 = temp;
}
if(length2 > 1) //短链表反转
{
ptr2 = -1; int ptr2_next = head2;
for(int i = 0; i < length2; i++)
{
int temp = list[ptr2_next].next;
list[ptr2_next].next = ptr2;
ptr2 = ptr2_next;
ptr2_next = temp;
}
head2 = ptr2;
}
int cnt = 0; ptr1 = head1; ptr2 = head2;
while(ptr1 != -1) //长链表每两节点中间接入一个短链表节点,直接在大数组中操作
{
if(cnt == 1)
{
if(ptr2 != -1)
{
int temp = list[ptr1].next;
list[ptr1].next = list[ptr2].addr;
int temp2 = list[ptr2].next;
list[ptr2].next = temp;
ptr2 = temp2;
ptr1 = temp;
}
cnt = 0;
}
else
{
cnt++;
ptr1 = list[ptr1].next;
}
}
ptr1 = head1;
while(ptr1 != -1)
{
printf("%05d %d ", list[ptr1].addr, list[ptr1].data);
if(list[ptr1].next == -1) printf("-1\n");
else printf("%05d\n", list[ptr1].next);
ptr1 = list[ptr1].next;
}
return 0;
}
PAT乙级1110 区块反转:
每k个节点,断掉尾节点,并移位保存首节点和上一首节点地址,尾节点指向上一首节点。最后k(或者不到k)个节点的首节点,即为新链表的head。
#include<iostream>
#include<string>
using namespace std;
struct Node
{
int address;
int data;
int next_address;
}list[100001];
int main()
{
int head_address, n, k;
cin >> head_address >> n >> k;
for(int i = 0; i < n; i++)
{
int idx;
cin >> idx;
list[idx].address = idx;
cin >> list[idx].data >> list[idx].next_address;
}
int ptr_address = head_address;
int lastfirst = -1, first = -1;
int cnt = 0;
while(ptr_address != -1) //每k个节点,断掉尾节点next,指向上一部分k个节点的首节点
{
if(cnt == 0)
{
lastfirst = first;
first = ptr_address;
}
int temp_nextaddr;
if(cnt == k - 1 || list[ptr_address].next_address == -1)
{
temp_nextaddr = list[ptr_address].next_address;
list[ptr_address].next_address = lastfirst;
ptr_address = temp_nextaddr;
cnt = 0;
if(ptr_address == -1)
head_address = first;
}
else
{
cnt++;
ptr_address = list[ptr_address].next_address;
}
}
ptr_address = head_address;
while(ptr_address != -1)
{
printf("%05d %d ", list[ptr_address].address, list[ptr_address].data);
if(list[ptr_address].next_address != -1) printf("%05d\n", list[ptr_address].next_address);
else printf("-1\n");
ptr_address = list[ptr_address].next_address;
}
return 0;
}
#刷题记录#PAT乙级(Basic)刷题记录
