25. 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

链接:

题解:

题目要求constant memory,所以一般要用iterative解法或者尾递归。

先来看递归。思路很简单,先找到第 k 和 k + 1节点,对k + 1节点进行递归,之后再用reverse list的方法对前k个节点进行reverse即可

Time Complexity - O(n), Space Complexity - O(n),  虽然能ac但是Space Complexity不满足题意。代码比较sloppy,以后要继续refactor。

public class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null || head.next == null || k <= 1)
            return head;        
        ListNode kthNode = head;
        int count = 1;
        
        while(count < k) {
            if(kthNode == null)
                return head;
            kthNode = kthNode.next;
            count++;
        }
           
        if(kthNode == null)
            return head;
        ListNode kplusoneNode = kthNode.next;        
        kthNode.next = null;        
        ListNode newHead = reverse(head);
        head.next = reverseKGroup(kplusoneNode, k);
        return newHead;
    }
    
    private ListNode reverse(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode dummy = new ListNode(-1);
        
        while(head != null) {
            ListNode tmp = head.next;
            head.next = dummy.next;
            dummy.next = head;
            head = tmp;
        }
        
        return dummy.next;
    }
}

接下来看迭代。思路和reverse linked list II 很像, 我们需要dummy,preHead,head, tail,postTail几个节点。有了这些节点以后,就可以做一个local的reverse K-group node运算,reverse之后的结果再和之前的preHead以及postTail连接起来,最后更新preHead = head; head = postTail; 就可以继续下面操作了。节点之间的转换还可以再继续简化,有时间的话还要继续refactor,也可以把reverse这一部分直接写到主要的方法体里,用 count来判定reverse到哪一个节点。

Time Complexity - O(n), Space Complexity - O(1)。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null || head.next == null || k == 1)
            return head;
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode preHead = dummy, tail, postTail;       //we need preHead, head, tail and postTail
        
        while(head != null) {
            tail = head;
            int count = 1; 
            
            while(count < k) {            //find tail 
               if(tail == null)
                  return dummy.next;
               tail = tail.next;
               count++;
            }
            
            if(tail == null)
                return dummy.next;
                
            postTail = tail.next;
            tail.next = null;
            preHead.next = reverse(head);
            head.next = postTail;
            preHead = head;
            head = head.next;
        }
        
        return dummy.next;
    }
    
     private ListNode reverse(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode dummy = new ListNode(-1);
        
        while(head != null) {
            ListNode tmp = head.next;
            head.next = dummy.next;
            dummy.next = head;
            head = tmp;
        }
        
        return dummy.next;
    }
}

这道题最好和前面的节点翻转题目结合起来做,顺序如下:

1) Reverse Linked List

2) Reverse Linked List II

3) Swap Node in Pairs

4) Reverse Linked List in K-Group

二刷:

分成几步思考,感觉难度不是那么大。另外Space Complexity其实等于O(k),假如k是比较小的常数那么也可以理解为Constant Space,否则还要把reverse函数写回去到函数体力。

Java:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null || head.next == null || k <= 1) {
            return head;
        }
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode preHead = dummy, tail = dummy, postTail = dummy;
        int count = 0;
        while (tail != null) {
            if (count == k) {
                count = 0;
                postTail = tail.next;
                tail.next = null;
                preHead.next = reverse(head);
                head.next = postTail;
                preHead = head;
                tail = head;
                head = head.next;
            }
            tail = tail.next;
            count++;
        }
        return dummy.next;
    }
    
    private ListNode reverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode dummy = new ListNode(-1);
        while (head != null) {
            ListNode tmp = head.next;
            head.next = dummy.next;
            dummy.next = head;
            head = tmp;
        }
        return dummy.next;
    }
}

纯的constant space Complexity:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null || head.next == null || k <= 1) {
            return head;
        }
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode preHead = dummy, tail = dummy, postTail, tmp;
        int count = 0;
        while (tail != null) {
            if (count == k) {
                count = 0;
                postTail = tail.next;
                tail.next = null;
                preHead.next = null;
                tail = head;               //reuse "tail"
                while (tail != null) {     //reverse head to original tail
                    tmp = tail.next;
                    tail.next = preHead.next;
                    preHead.next = tail;
                    tail = tmp;
                }
                head.next = postTail;
                preHead = head;
                tail = preHead;
                head = head.next;
            }
            tail = tail.next;
            count++;
        }
        return dummy.next;
    }
}

三刷:

Java:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null || head.next == null || k <= 1) return head;
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode curr = dummy, preHead = dummy, postTail = null, tmp = null;
        int count = 0;
        while (curr.next != null) {
            curr = curr.next;
            count++;
            if (count == k) {
                postTail = curr.next;
                curr.next = null;
                preHead.next = null;
                curr = head;
                while (curr != null) {
                    tmp = curr.next;
                    curr.next = preHead.next;
                    preHead.next = curr;
                    curr = tmp;
                }
                head.next = postTail;
                preHead = head;
                curr = head;
                head = postTail;
                count = 0;
            }
        }
        return dummy.next;
    }
}

Reference:

https://leetcode.com/discuss/21301/short-but-recursive-java-code-with-comments

原文地址:https://www.cnblogs.com/yrbbest/p/4434866.html