我的PAT-BASIC代码仓:https://github.com/617076674/PAT-BASIC
我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
我的Data Structures and Algorithms代码仓:https://github.com/617076674/Data-Structures-and-Algorithms
原题链接:
PAT-BASIC1025:https://pintia.cn/problem-sets/994805260223102976/problems/994805296180871168
PAT-ADVANCED1074:https://pintia.cn/problem-sets/994805342720868352/problems/994805394512134144
Data Structures and Algorithms7-2:https://pintia.cn/problem-sets/16/problems/664
题目描述:
PAT-BASIC1025:
PAT-ADVANCED1074、Data Structures and Algorithms7-2:
知识点:链表
思路一:用vector来保存输入的数据(在PAT中提交测试点5会超时)
这个思路的大致情况如下:
为便于描述,我们将待翻转的每一段链表称作分链表。
(1)定义一个结构体point,里面有3个int型变量,address、data和next。
(2)用一个vector<point>型变量points接收输入的各节点信息。由于题目所给的节点信息并不是按照链表的顺序给的。所以我们需要根据题目给的首节点地址firstPointAddress在points中寻找出链表应该有的正确顺序。
(3)对于每一个节点地址tempAddress,我们都需要在points中寻找address值为tempAddress的point,并根据其next来寻找下一个point,直至tempAddress为-1,我们可以跳出循环,停止寻找。由于每次寻找address值为tempAddress的point时,我们都需要遍历整个points,这未免有点太浪费时间。因此,我用了一个vector<bool>型的变量flag来记录points中相应索引的节点是否已经被访问过。如果被访问过了,我们就可以不去判断其address值是否为tempAddress。
(4)在求得按链表顺序存储的vector<point>型变量beforeChangePoints之后,我们需要寻找每个分链表的首节点,将除了第一个分链表之外的首节点值存储在vector<point>型变量tempFirstPointAddresses中。
(5)做好了上述准备之后,我们可以来翻转链表。只要当前链表需要翻转,则进行以下循环。
a:如果当前分链表的下一个分链表需要翻转,那么当前分链表的首节点的next应该从tempFirstPointAddresses中读取。
b:如果当前分链表的下一个分链表不需要翻转
b-1:如果当前分链表的末端刚好是整个链表的末端,那么当前分链表的首节点的next值应该设为-1。
b-2:如果当前分链表的末端未到达整个链表的末端,那么当前分链表的首节点的next值应该是beforeChangePoints索引+k位置元素的address值。
(6)翻转完链表之后,beforeChangePoints中的链表顺序已被打乱,我们需要用一个新的vector<point>型变量afterChangePoints来记录新的链表顺序值。这个过程和(3)中的过程一模一样。
(7)最后,我们顺序输出afterChangePoints中的结果即可。
时间复杂度是O(n ^ 2),其中n为输入链表中的节点个数。空间复杂度是O(n)。
由于在(3)、(7)步中排序链表节点之时花费的大量时间导致这个思路在测试点5超时了。
C++代码:
#include<iostream>
#include<vector>
using namespace std;
struct point {
int address;
int data;
int next;
};
int main() {
int firstPointAddress;
int n;
int k;
cin >> firstPointAddress >> n >> k;
vector<point> points;
point tempPoint;
int address;
int data;
int next;
for (int i = 0; i < n; i++) {
cin >> address >> data >> next;
tempPoint.address = address;
tempPoint.data = data;
tempPoint.next = next;
points.push_back(tempPoint);
}
vector<point> beforeChangePoints;
int tempAddress = firstPointAddress;
vector<bool> flag;
for (int i = 0; i < points.size(); i++) {
flag.push_back(false);
}
while (true) {
for (int i = 0; i < points.size(); i++) {
if (flag[i]) {
continue;
}
if (points[i].address == tempAddress) {
beforeChangePoints.push_back(points[i]);
flag[i] = true;
tempAddress = points[i].next;
break;
}
}
if (tempAddress == -1) {
break;
}
}
int index = 0;
firstPointAddress = beforeChangePoints[k - 1].address;
vector<point> tempFirstPointAddresses;
for (int i = 2 * k; i <= beforeChangePoints.size(); i += k) {
tempFirstPointAddresses.push_back(beforeChangePoints[i - 1]);
}
int count = 0;
while (index + k <= beforeChangePoints.size()) {
if (index + 2 * k <= beforeChangePoints.size()) {
beforeChangePoints[index].next = tempFirstPointAddresses[count].address;
} else {
if (index + k == beforeChangePoints.size()) {
beforeChangePoints[index].next = -1;
} else {
beforeChangePoints[index].next = beforeChangePoints[index + k].address;
}
}
for (int i = index + 1; i < index + k; i++) {
beforeChangePoints[i].next = beforeChangePoints[i - 1].address;
}
count++;
index = index + k;
}
vector<point> afterChangePoints;
tempAddress = firstPointAddress;
vector<bool> flag2;
for (int i = 0; i < beforeChangePoints.size(); i++) {
flag2.push_back(false);
}
while (true) {
for (int i = 0; i < beforeChangePoints.size(); i++) {
if (flag2[i]) {
continue;
}
if (beforeChangePoints[i].address == tempAddress) {
afterChangePoints.push_back(beforeChangePoints[i]);
flag2[i] = true;
tempAddress = beforeChangePoints[i].next;
break;
}
}
if (tempAddress == -1) {
break;
}
}
for (int i = 0; i < afterChangePoints.size(); i++) {
if (i != afterChangePoints.size() - 1) {
printf("%05d %d %05d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
} else {
printf("%05d %d %d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
}
}
}
C++解题报告:
思路二:对思路一的改进,用一个大小为100000的数组来保存节点
address为i的值保存在数组中索引为i的位置,这样我们就可以用while循环来得到一个顺序的链表,节省大量时间。
时间复杂度是O(n),其中n为输入链表中的节点个数。空间复杂度是O(100000)。
C++代码:
#include<iostream>
#include<vector>
using namespace std;
struct point {
int address;
int data;
int next;
};
int main() {
int firstPointAddress;
int n;
int k;
cin >> firstPointAddress >> n >> k;
point points[100000];
point tempPoint;
int address;
int data;
int next;
for (int i = 0; i < n; i++) {
cin >> address >> data >> next;
tempPoint.address = address;
tempPoint.data = data;
tempPoint.next = next;
points[address] = tempPoint;
}
vector<point> beforeChangePoints;
int tempAddress = firstPointAddress;
while (true) {
beforeChangePoints.push_back(points[tempAddress]);
tempAddress = points[tempAddress].next;
if (tempAddress == -1) {
break;
}
}
int index = 0;
firstPointAddress = beforeChangePoints[k - 1].address;
vector<point> tempFirstPointAddresses;
for (int i = 2 * k; i <= beforeChangePoints.size(); i += k) {
tempFirstPointAddresses.push_back(beforeChangePoints[i - 1]);
}
int count = 0;
while (index + k <= beforeChangePoints.size()) {
if (index + 2 * k <= beforeChangePoints.size()) {
beforeChangePoints[index].next = tempFirstPointAddresses[count].address;
} else {
if (index + k == beforeChangePoints.size()) {
beforeChangePoints[index].next = -1;
} else {
beforeChangePoints[index].next = beforeChangePoints[index + k].address;
}
}
for (int i = index + 1; i < index + k; i++) {
beforeChangePoints[i].next = beforeChangePoints[i - 1].address;
}
count++;
index = index + k;
}
point points2[100000];
for (int i = 0; i < beforeChangePoints.size(); i++) {
points2[beforeChangePoints[i].address] = beforeChangePoints[i];
}
vector<point> afterChangePoints;
tempAddress = firstPointAddress;
while (true) {
afterChangePoints.push_back(points2[tempAddress]);
tempAddress = points2[tempAddress].next;
if (tempAddress == -1) {
break;
}
}
for (int i = 0; i < afterChangePoints.size(); i++) {
if (i != afterChangePoints.size() - 1) {
printf("%05d %d %05d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
} else {
printf("%05d %d %d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
}
}
}
C++解题报告:
思路三:在翻转过程中完全不考虑next指针的指向,最后统一处理
思路一和思路二的复杂之处在于,每次翻转分链表的时候就在考虑每一个节点next指向何处。其实完全没有必要,我们可以先把各个节点按要输出的顺序摆好,最后让其每个节点的next指向下一个节点,最后一个节点则指向-1即可。
时间复杂度是O(n),其中n为输入链表中的节点个数。空间复杂度是O(100000)。
C++代码:
#include<iostream>
#include<vector>
using namespace std;
struct point {
int address;
int data;
int next;
};
int main() {
int firstPointAddress;
int n;
int k;
cin >> firstPointAddress >> n >> k;
point points[100000];
point tempPoint;
int address;
int data;
int next;
for (int i = 0; i < n; i++) {
cin >> address >> data >> next;
tempPoint.address = address;
tempPoint.data = data;
tempPoint.next = next;
points[address] = tempPoint;
}
vector<point> beforeChangePoints;
int tempAddress = firstPointAddress;
while (true) {
beforeChangePoints.push_back(points[tempAddress]);
tempAddress = points[tempAddress].next;
if (tempAddress == -1) {
break;
}
}
vector<point> afterChangePoints;
int index = 0;
while (index + k <= beforeChangePoints.size()) {
for (int i = index + k - 1; i >= index; i--) {
afterChangePoints.push_back(beforeChangePoints[i]);
}
index = index + k;
}
for (int i = index; i < beforeChangePoints.size(); i++) {
afterChangePoints.push_back(beforeChangePoints[i]);
}
for (int i = 0; i < afterChangePoints.size() - 1; i++) {
afterChangePoints[i].next = afterChangePoints[i + 1].address;
}
afterChangePoints[afterChangePoints.size() - 1].next = -1;
for (int i = 0; i < afterChangePoints.size(); i++) {
if (i != afterChangePoints.size() - 1) {
printf("%05d %d %05d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
} else {
printf("%05d %d %d\n", afterChangePoints[i].address, afterChangePoints[i].data, afterChangePoints[i].next);
}
}
}
C++解题报告: