• Leetcode: Reverse Nodes in k-Group


    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
    
    If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
    
    You may not alter the values in the nodes, only nodes itself may be changed.
    
    Only constant memory is allowed.
    
    For example,
    Given this linked list: 1->2->3->4->5
    
    For k = 2, you should return: 2->1->4->3->5
    
    For k = 3, you should return: 3->2->1->4->5

    Analysis: Linked List节点倒序,Naive的方法就是用Stack,这样的话只需要K层Stack,不满足constant memory的条件;

    第二遍方法(采用解法)两个指针:walker指向需改序序列的上一个节点,runner指向需改序序列最后节点,每次把walker下一个节点移到runner下一点处,直到walker.next = runner

     1 /**
     2  * Definition for singly-linked list.
     3  * public class ListNode {
     4  *     int val;
     5  *     ListNode next;
     6  *     ListNode(int x) {
     7  *         val = x;
     8  *         next = null;
     9  *     }
    10  * }
    11  */
    12 public class Solution {
    13     public ListNode reverseKGroup(ListNode head, int k) {
    14         ListNode dummy = new ListNode(-1);
    15         dummy.next = head;
    16         ListNode walker = dummy;
    17         ListNode runner = dummy;
    18         while (runner.next != null) {
    19             int count = k;
    20             while (count > 0 && runner.next != null) {
    21                 runner = runner.next;
    22                 count--;
    23             }
    24             if (count == 0) walker = reverse(walker, runner);
    25             else break;
    26             runner = walker;
    27         }
    28         return dummy.next;
    29     }
    30     
    31     public ListNode reverse(ListNode walker, ListNode runner) {
    32         ListNode store = walker.next;
    33         while (walker.next != runner) {
    34             ListNode cur = walker.next;
    35             ListNode next = cur.next;
    36             cur.next = runner.next;
    37             runner.next = cur;
    38             walker.next = next;
    39         }
    40         return store;
    41     }
    42 }

    第二遍方法(另一种方法,可以但是不如第一种方法好写):精髓在于reverse子函数,输入的两个参数分别是prev: 需改续序列的上一个节点,end: 需改续序列的下一个节点

    reverse函数中设计比较精巧的地方在于,需要一开始保存一个start.next节点,最后作为start的新位置返回去更新start,这就是新的需改续序列的上一个节点位置(我一开始也就是卡在这里,不知如何更新start)

     1 public class Solution {
     2     public ListNode reverseKGroup(ListNode head, int k) {
     3         ListNode dummy = new ListNode(0);
     4         dummy.next = head;
     5  
     6         ListNode start = dummy;
     7         ListNode end = head;
     8         while (end != null) {
     9             int count = k;
    10             for (; count>0 && end!=null; count--) {
    11                 end = end.next;
    12             }
    13             if (count == 0) {
    14                 start = reverse(start, end);
    15             }
    16         }
    17         return dummy.next;
    18     }
    19     
    20     public ListNode reverse(ListNode start, ListNode end) {
    21         ListNode pre = end;
    22         ListNode store = start.next;
    23         ListNode cur = store;
    24         while (cur != end) {
    25             ListNode next = cur.next;
    26             cur.next = pre;
    27             pre = cur;
    28             cur = next;
    29         }
    30         start.next = pre;
    31         return store;
    32     }
    33 }

    Naive方法:使用Stack, 但不满足constant memeory的条件

     1 /**
     2  * Definition for singly-linked list.
     3  * public class ListNode {
     4  *     int val;
     5  *     ListNode next;
     6  *     ListNode(int x) {
     7  *         val = x;
     8  *         next = null;
     9  *     }
    10  * }
    11  */
    12 public class Solution {
    13     public ListNode reverseKGroup(ListNode head, int k) {
    14         if (head == null) return null;
    15         ListNode prev = new ListNode(-1);
    16         prev.next = head;
    17         ListNode current = prev;
    18         while (head != null) {
    19             Stack<Integer> store = new Stack<Integer>();
    20             ListNode temp = head;
    21             int i = 0;
    22             for (; i < k; i++) {
    23                 if (head == null) break;
    24                 store.push(head.val);
    25                 head = head.next;
    26             }
    27             if (i == k) {
    28                 while (!store.empty()) {
    29                     current.next = new ListNode(store.pop());
    30                     current = current.next;
    31                 }
    32             }
    33             else current.next = temp;
    34         }
    35         return prev.next;
    36     }
    37 }

    Gode Ganker的改指针做法(与我的第二遍方法2相仿),输入给reverse函数的参数分别是:prev: 需改续序列的前一个节点,end: 需改续序列的后一个节点

    基本思路是这样的,我们统计目前节点数量,如果到达k,就把当前k个结点reverse,这里需要reverse linked list的subroutine。这里我们需要先往前走,到达k的时候才做reverse,所以总体来说每个结点会被访问两次。总时间复杂度是O(2*n)=O(n),空间复杂度是O(1)。

     1 public ListNode reverseKGroup(ListNode head, int k) {
     2     if(head == null)
     3     {
     4         return null;
     5     }
     6     ListNode dummy = new ListNode(0);
     7     dummy.next = head;
     8     int count = 0;
     9     ListNode pre = dummy;
    10     ListNode cur = head;
    11     while(cur != null)
    12     {
    13         count ++;
    14         ListNode next = cur.next;
    15         if(count == k)
    16         {
    17             pre = reverse(pre, next);
    18             count = 0;   
    19         }
    20         cur = next;
    21     }
    22     return dummy.next;
    23 }
    24 private ListNode reverse(ListNode pre, ListNode end)
    25 {
    26     if(pre==null || pre.next==null)
    27         return pre;
    28     ListNode head = pre.next;
    29     ListNode cur = pre.next.next;
    30     while(cur!=end)
    31     {
    32         ListNode next = cur.next;
    33         cur.next = pre.next;
    34         pre.next = cur;
    35         cur = next;
    36     }
    37     head.next = end;
    38     return head;
    39 }
  • 相关阅读:
    deleteCustomer
    python入门day07——可变不可变类型、数字类型、字符串类型.md
    python入门day06——流程控制之if判断、while循环、for循环
    python入门day05——基本运算符、逻辑运算符
    python入门day04——基本数据类型、输入输出、基本运算符
    python入门day03——变量、内存管理:垃圾回收机制(GC)、常量
    python入门day03——python介绍、运行程序步骤
    python入门day02——计算机硬件、操作系统、编程语言
    python入门day01——01 计算机硬件组成与工作原理
    python入门作业day04 基本数据类型应用
  • 原文地址:https://www.cnblogs.com/EdwardLiu/p/3792086.html
Copyright © 2020-2023  润新知