PAT-BASIC1025——反转链表/PAT-ADVANCED1074/Data Structures and Algorithms7-2——Reversing Linked List

我的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++解题报告:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值