• 25. k个一组翻转链表


    题目描述

    给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

    k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

    示例 :

    给定这个链表:1->2->3->4->5

    当 k = 2 时,应当返回: 2->1->4->3->5

    当 k = 3 时,应当返回: 3->2->1->4->5

    说明:

    • 你的算法只能使用常数的额外空间。
    • 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

    算法

    边界条件

    1. k值与链表长度。虽然题目说k 是一个正整数,它的值小于或等于链表的长度。但是实际提交的时候我发现。。。没错,k值大于链表长度也被作为一个测试点。
      k值大于链表长度

    2. 链表为空或者k值为1

    思路

    1. 找到两个距离为k的节点
    2. 反转两个节点之间的这段链表
    3. 重复1、2步直到遍历完整个链表

    代码

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* global_head;
        ListNode* reverseKGroup(ListNode* head, int k) {
        
            // 边界条件
            if(head == NULL || k == 1)
                return head;
            int size = 0;
            for(ListNode* t = head; t; t = t->next, size++);
            if(size < k)
                return head;
            
            /*** H靠近链表头部,tail靠近链表尾部;
            pre_node定义为前一段已经反转的局部链表的最后一个节点;
            比如链表1->2->3->4->5->6,k=2;第一段局部链表反转为2->1,那么pre_node指向1这个节点;
            pre_node初值设为NULL,可以在reverse_k中判断是不是第一段局部链表的反转,如果是第一段的话,需要设置反转后的链表头部节点global_head
            ***/
            ListNode *H, *tail, *pre_node = NULL;
            H = tail = head;
            
            // 遍历整个链表
            while(true)
            {
                // cnt用来记录H和tail节点之间的距离,
                int cnt = 0;
                while(cnt < k && tail != NULL)
                {
                    tail = tail->next;
                    cnt++;
                }
                
                // 1->2->3,k=3
                if(tail == NULL && cnt == k)
                {
                    reverse_k(pre_node, H, tail);
                    break;
                }
                // 最后剩余节点不足k个
                else if(cnt != k)
                {
                    pre_node->next = H;
                    break;
                }
                // 对k个节点反转
                else
                {
                    reverse_k(pre_node, H, tail);
                    H = tail;
                }
            }
            return global_head;
        }
    
        void reverse_k(ListNode *&pre_node, ListNode *&start, ListNode *&end) {
    
            /*** 这个函数将[start, end)之间的节点顺序逆置 ***/
    
            ListNode *pre, *p, *post;
            pre = start;
            p = pre->next;
            // 反转代码
            while(p != end)
            {
                post = p->next;
                p->next = pre;
                pre = p;
                p = post;
            }
            // 判断是不是第一段局部链表的反转以设置改动后的链表头节点global_head
            if(pre_node == NULL)
                global_head = pre;
            else
                // pre_node是前一段链表的最后一个节点,接上这段链表
                pre_node->next = pre;
            
            // 重新设置pre_node为这段链表的最后一个结点
            pre_node = start;
            pre_node->next = NULL;
        }
    };
    
  • 相关阅读:
    FastDFS介绍
    SwiftUI 中使用SDWebImageSwiftUI加载网络图片
    SwiftUI 中使用BBSwiftUIKit开源库实现上拉加载和下拉刷新
    SwiftUI 中使用ScrollView+LazyVStack代替List
    SwiftUI 动画
    SwiftUI 中实现省市区选择器
    SwiftUI 中Slider的使用
    SwiftUI 中Stepper的使用
    SwiftUI 中通过Toggle实现单选框和复选框效果
    SwiftUI 中加载bundle中的图片
  • 原文地址:https://www.cnblogs.com/shayue/p/10351412.html
Copyright © 2020-2023  润新知