AcWing1560-反转链表

题目

扣我传送

给定一个常数 K 和一个单链表 L,请你在单链表上每 K 个元素做一次反转,并输出反转完成后的链表。如果链表最后一部分不足 K 个元素,则最后一部分不翻转。

例如,假设 L为 1→2→3→4→5→6,如果 K=3,则你应该输出 3→2→1→6→5→4;如果 K=4,则你应该输出 4→3→2→1→5→6

补充

1、本题中可能包含不在链表中的节点,这些节点无需考虑。

输入格式

第一行包含头节点地址,总节点数量 N以及常数 K

节点地址用一个 5 位非负整数表示(可能有前导 0),NULL 用 −1表示。

接下来 N 行,每行描述一个节点的信息,格式如下:

Address Data Next

其中 Address 是节点地址,Data 是一个整数,Next 是下一个节点的地址。

输出格式

将重新排好序的链表,从头节点点开始,依次输出每个节点的信息,格式与输入相同。

数据范围

1≤N≤105,

1≤KN

输入样例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

代码以及思路

就爱做水题~

思路

数组模拟链表

题目明示了用数组来模拟链表了,那我们就这么干吧。

创建一个如下的结构体,同时创建一个长度为100001(或更大)的数组。名字随你便起:

struct Link
{
    int data, next;
} L[100001];

为什么要多一个呢?注意到这题大概率要对第一个节点进行操作,所以我们再多分配一个首节点来方便后续的操作。题目有说明节点的地址要在0~99999之间,因此这里我把head节点分配在100000,这将在接下来的代码体现。


继续反转的条件判断

如题的:

如果链表最后一部分不足 K 个元素,则最后一部分不翻转。

,我们就要判断链表剩下的元素是否有 K 个。考虑到后续在实现对一组 K 个元素反转后我们要获得接下去的节点地址,因此我们写一个函数,用来读取距离当前节点 K 个位置后的节点吗,我将它命名为k_after

函数如下:

int k_after(int address, int k) {
    for (int i = 0; i < k; i++) {
        // 当在向后探索的过程中如果到达的链尾,那么我们直接结束循环就行
        // 这样在外部处理时,如果返回的值为-1,那么就可以直接停止处理了
        if (address == -1) break;
        address = L[address].next;
    }
    return address;
}

处理反转

我们先想这么在单组 K 个节点之间处理,之后用一个循环就能直接结束这道题了,在这里我用一个handle函数来处理这个问题,那么handle要怎么写呢?

要对这 K 个节点反转,我们需要修改的指针就应该是 K+1 个,其中,位于内部的 K-2 个节点的指针特别容易修改,只需要我们记录节点的顺序再依次反转即可,如:

order[0] = L[previous_node].next;
for (int i = 1; i < k; i++)
	order[i] = L[order[i - 1]].next;

for (int i = k - 1; i >= 1; i--) {
	L[order[i]].next = order[i - 1];
}

这里的previous_node是这 K 个节点头的前一个节点,因为我们需要修改这个节点的next指针的值。

剩下的两个 指向这 K 个序列头的指针 以及 这 K 个序列尾指向的指针 需要我们进行单独的操作。

指向这 K 个序列头的指针

处理完的序列头一定是原先的最后一个节点,所以我们直接把previous_node的next赋值为order数组的最后一个元素就行

这 K 个序列尾指向的指针

这个指针指向原本是由最后一个元素记录的,但是我们发现再反转内部节点时把这个指向丢失了,于是我们要对上面的代码添加一个变量用来存储原本指向的地址,并在最后把新的结尾的指针指向它。综上,函数长这样:

void handle(int previous_node, int k) {
    int order[k], out;
    order[0] = L[previous_node].next;
    for (int i = 1; i < k; i++)
        order[i] = L[order[i - 1]].next;
    out = L[order[k - 1]].next;  // 记录

    for (int i = k - 1; i >= 1; i--) {
        L[order[i]].next = order[i - 1];
    }
    L[order[0]].next = out;  // 新的尾
    L[previous_node].next = order[k - 1];  	// 新的头
}

到这里就差不多写完了。


代码

// https://www.acwing.com/problem/content/1562/
#include<bits/stdc++.h>
using namespace std;

struct Link
{
    int data, next;
} L[100001];

int k_after(int address, int k) {
    for (int i = 0; i < k; i++) {
        if (address == -1) break;
        address = L[address].next;
    }
    return address;
}

// 输入要交换的前一个节点, 以及反转长度.
void handle(int previous_node, int k) {
    int order[k], out;
    order[0] = L[previous_node].next;
    for (int i = 1; i < k; i++)
        order[i] = L[order[i - 1]].next;
    out = L[order[k - 1]].next;

    for (int i = k - 1; i >= 1; i--) {
        L[order[i]].next = order[i - 1];
    }
    L[order[0]].next = out;
    L[previous_node].next = order[k - 1];
}

void print(int node) {
    int next_node = L[node].next;
    if (next_node == -1) return;
    if ( L[next_node].next == -1) printf("%05d %d -1\n", next_node, L[next_node].data);
    else printf("%05d %d %05d\n", next_node, L[next_node].data, L[next_node].next);
    print(next_node);
}


int main(){
    int num, k, temp = 100000;
    cin >> L[100000].next >> num >> k;

    for (int i = 0;i < num; i++) {
        int address;
        cin >> address;
        cin >> L[address].data >> L[address].next;
    }

    while (k_after(temp, k) != -1) {
        handle(temp, k);
        temp = k_after(temp, k);
    }

    print(100000);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值