PTA Reversing Linked List ----- 对序列实现每K个元素反转一次

这个题我看了好多人的实现,发现他们是用了两个MAXSIZE大小的数组:
第一个数组是保存输入
第二个数组是保存的这些输入的顺序(将输入按照题意排序保存于这个数组)

这样做很简单,但是看看这个想法的 空间复杂度O(2*MAXSIZE)
我也是个菜鸡,可能分析有误,希望大家指出
而我算法的空间复杂度是O(MAXSIZE+K),而时间复杂度只是稍稍高于以上思路

算法思路:

我以一个数组保存题中的输入,为了方便,数组大小就是MAXSIZE,这样任何一个题目中元素的地址就是就是在这个数组中的下标,然后我开始从题中规定的顺序开始从1记数,题中也要求每K个倒序输出一下,所以每当记得数为K的倍数,我就倒序输出这K个数

难点

倒序输出很简单,我代码里在Prin函数t中,但是有一个盲点(华点,我发现了盲生):假设(N=5)有5个数,(K=2)每2个倒序输出一下(我的代码里是用了个长度为K的数组保存这K个数,然后把他们倒序输出),所以要倒序输出两轮,

例如: 1 2 3 4 5 —》 2 1 4 3 5

很好,这就是我的思路,然鹅。。。。
这个结点保存的Next是3,但是在第一轮倒序后,使得1的Next保存的是3
到了第2次倒序,我们把3和4的位置颠倒了
那么问题来了:第一轮里1保存的Next是3的,但在第二轮里面4成了倒序后的第一位,即1的Next需要保存4,而不是3。。。

解决办法:我们知道每K个数就要倒置一个,所以(呵呵),如果我这一轮进行了倒置,那么我倒置后的最后一个元素的Next有两种结果:

  1. 当这一轮倒置后,下面的数不够K个数(也即之后的数不用倒序了),那么倒置后最后一个Next就是这一轮元素的下一个元素
例如: 1 2 3 —》 2 1 3

倒置后的元素1 2倒置成了2 1,然后1的Next是这一轮元素的下一个元素 3

  1. 当这一轮的倒置结束后,接下来的数比K个多,即一定会有下一轮的倒序,此时这一轮倒置后最后一个元素的Next要指向距离他K个元素的地址
例如: 1 2 3 4 5—》 2 1 4 3 5

第一轮倒序结束后 2 1,而此时1的Next需要保存的是距离他K个元素的4

这个解决办法在代码中的Print函数中的while循环里

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 100005

int TheFirst, N, K, printNUM = 0;//printNUM为已近输出的个数,为了找到最后一个输出的元素(其Next为-1)来特殊处理
struct Node {
	int address;//保存这个元素的地址,以便在反转的时候可以方便让别的元素指向它
	int data;
	int Next;
}Node[MAXSIZE];
void Init() {
	int address;
	scanf("%d %d %d", &TheFirst, &N, &K);
	int n = N;
	while (n--) {
		scanf("%d", &address);
		Node[address].address = address;
		scanf("%d", &Node[address].data);
		scanf("%d", &Node[address].Next);
	}
}
void Print(struct Node* Reserve) {//每K个反转一次  注意,此时的反转后最后一个要指向下一轮的第一个(可能下一轮也要反转,所以此轮最后一个要指向下一轮反转后的第一个)
	//此时在改变颠倒后的Next域
	int address = Reserve[K - 1].Next;	//保存最后一个要Next,以便倒置结束后赋给倒置后第一个值的Next
	for (int i = K - 1;i >= 1;i--) {
		Reserve[i].Next = Reserve[i - 1].address;
	}
	int k = 0, ad = address;
	while (ad != -1) {//注意这一步是最关键的: 第一轮倒置的结果后上面进行了赋值,但是 下一轮如果还要倒置的话,需要将这一轮倒置后的最后一个Next重新给下一轮倒置后的第一个值
		//找下一轮倒序后的的第一个值
		if (++k == K) {
			address = Node[ad].address;//下一轮如果倒置,那么他的第一个值就是与我们这一轮未倒置时最后一个元素相差K,找到他的值,将他的值给我们这一轮倒置后的最后一个值(即未倒置时第一个元素)的Next
			break;
		}
		ad = Node[ad].Next;
	}
	Reserve[0].Next = address;
	for (int i = K - 1;i >= 0;i--) {
		printNUM++;
		if (printNUM != N) {
			printf("%05d %d %05d\n", Reserve[i].address, Reserve[i].data, Reserve[i].Next);
		}
		else {
			printf("%05d %d %d\n", Reserve[i].address, Reserve[i].data, Reserve[i].Next);
		}
	}

}
int main() {
	Init();
	struct Node* Reserve = (struct Node*)malloc(sizeof(struct Node) * K);//存放要反转的K个数  其实反转是在Reserve中,对原来的数组Node没影响
	int address = TheFirst;
	int sum = 0;
	while (address != -1) {
		sum++;
		if (sum % K == 0) {
			Reserve[K - 1].address = Node[address].address;	Reserve[K - 1].data = Node[address].data;	Reserve[K - 1].Next = Node[address].Next;
			Print(Reserve);
		}
		else {
			Reserve[sum % K - 1].address = Node[address].address;	Reserve[sum % K - 1].data = Node[address].data;	Reserve[sum % K - 1].Next = Node[address].Next;
		}
		address = Node[address].Next;
	}
	if (sum % K != 0) {
		for (int i = 0;i < sum % K - 1;i++) {
			printf("%05d %d %05d\n", Reserve[i].address, Reserve[i].data, Reserve[i].Next);
		}
		printf("%05d %d %d\n", Reserve[sum % K - 1].address, Reserve[sum % K - 1].data, Reserve[sum % K - 1].Next);//对最后一个单独输出  因为最后一个地址为-1不用补0
	}
	return 0;
}


这个代码过了不到几天我又看了下,一下子感到了害怕,无助;简直不敢相信这是我写的代码,当时真的不知道是什么让我把这个写出来。。。
在这里插入图片描述

如果大家有更好的思路过程的话请在评论里留言,希望我们可以共同进步,不断提高自己的算法能力

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值