龙空技术网

leetcode C++题解系列-024 K 个一组翻转链表

第一路痴索隆 174

前言:

此刻朋友们对“单链表逆序输出c语言”大概比较注意,小伙伴们都想要分析一些“单链表逆序输出c语言”的相关资讯。那么小编同时在网络上收集了一些有关“单链表逆序输出c语言””的相关文章,希望朋友们能喜欢,各位老铁们快快来学习一下吧!

题目

题解代码与测试

//// Created by tannzh on 2020/6/26.///* * 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。示例:给你这个链表:1->2->3->4->5当 k = 2 时,应当返回: 2->1->4->3->5当 k = 3 时,应当返回: 3->2->1->4->5说明:你的算法只能使用常数的额外空间。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。 */#include <iostream>/** * Definition for singly-linked list. */struct ListNode {    int val;    ListNode *next;    ListNode(int x) : val(x), next(nullptr) {}};class Solution {public:    ListNode* reverseKGroup(ListNode* head, int k) {        if (!head || !head->next || k<2) return head;        ListNode pre(0);        pre.next = head;        for (ListNode *front = &pre, *back = ⪯ true; front = head, back = head) {            for (int count = k; count > 0; --count)                if (!(back = back->next)) return pre.next;            for (head = front->next; front->next != back; ) {                ListNode *next = front->next;                front->next = next->next;                next->next = back->next;                back->next = next;            }        }        return pre.next;    }};ListNode *create_linkedlist(std::initializer_list<int> lst){    auto iter = lst.begin();    ListNode *head = lst.size() ? new ListNode(*iter++) : NULL;    for (ListNode *cur=head; iter != lst.end(); cur=cur->next)        cur->next = new ListNode(*iter++);    return head;}int main(int argc, char **argv){    Solution s;    ListNode *head = s.reverseKGroup(create_linkedlist({1,2,3,4,5}), 3);    for (ListNode *cur=head; cur; cur=cur->next)        std::cout << cur->val << "->";    std::cout << "\b\b  " << std::endl;    return 0;}
解题思路分析

首先,回顾一个基本的问题,单链表如何逆序?

 1->2->3->4->5 ^ root

想要逆序,最直接的想法,就是希望上图中的链表指向反过来。我们借用一个空指针 node 指向一个空节点:

 1->2->3->4->5 | ListNode* reverse(ListNode *root) { ^             |      ListNode *node = NULL;     root          | }               | NULL          | ^             | node          |

第一步,我们希望节点1从单链表中剥离,于是让其指向 node, 但我们不能因此而找不到链表索引,故需要一个额外的指针 next, 指向后续节点:

 2->3->4->5 | ListNode* reverse(ListNode *root) { ^          |      ListNode *node = NULL;    root       |      ListNode *next = root->next;     // next refer to 2            |      root->next = node;               // root point to node 1->NULL    |      node = root;                     // node refer to root(1) ^          |      root = next;                     // root refer to next(2) node       | }

几个简单的指针顶替,便将节点1反向的去指向了 node 节点。如法炮制的话,节点2, 节点3, 节点4, 节点5 都调转枪头,我们的目的便达到了。

ListNode* reverse(ListNode *root) {     ListNode *node = NULL;     while (root) {          ListNode *next = root->next;          root->next = node;          node = root;          root = next;     }     return node;}

回到这道题,我们分析题目给出的例子:

 1->2->3->4->5, k=3 => 3->2->1->4->5

对于这种连头指针都要被移动/替换的情况,果断创造一个 preHead(pre) 节点。另外,排除一些边界条件,如 k=0/k=1/head=NULL/head->next=NULL 这些情况。

 0->1->2->3->4->5 | if (head == NULL || head->next == NULL || k < 2) return head; ^                | ListNode pre(0); pre              | pre.next = head;

接下来我们起码要找到哪些节点要逆序,为了方便分析,使用 front 和 back 两个指针来指定逆序的范围。初始都指向 pre 节点,移动 back:

 0->1->2->3->4->5 | for (ListNode *front=&pre, *back=⪯ true; ) ^        ^       |      for (int count=k; count>0; --count) front    back    |           if ((back = back->next) == NULL) return pre.next;

然后就要开始逆序了吗?不,我们先分析一下下一次的逆序范围应该从哪里开始:

 0->3->2->1->4->5 | // next iteration should start at 1          ^       | // use head to refer it.          head    | head = front->next;

确定了下一次的开头后,我们就可以进行逆序过程了,不比基本问题中全部的逆序,这里只是部分,肯定是无法直接用指针顶替了,那样不把自己搞死才怪。我们要想办法用指针来交换位置,以达到咱们逆序的目的。我们还是需要一个临时指针 next, 来协助我们。

  _(1)_           | while (front->next != back) { |     |          |      // next |     v          |      ListNode *next = front->next; 0  1  2->3  4->5 |      // (1) front point to 2 ^  ^     ^       |      front->next = next->next; f  n^    b  ^    |      // (2) next point to 4    ||_(3)|  |    |      next->next = back->next;    |________|    |      // (3) back point to 1        (2)       |      back->next = next;                  | } 0->2->3->1->4->5 | ^  ^  ^          | f  n  b          |

如果我们死守着全逆序中指针顶替的方法,估计会吃不少苦头。局部范围内的处理,还是要以交换指针为主。

标签: #单链表逆序输出c语言