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

這個題目花了蠻長時間,主要是沒搞清楚逆轉一個鏈表的關系。弄了半天。其實是蠻簡單和經典的題目。

解法一:比較挫的解法。要判斷很多分支,所以容易出錯。先放在這里當反面教材。

 1 public static ListNode reverseKGroup(ListNode head, int k) {
 2         // Start typing your Java solution below
 3         // DO NOT write main() function
 4         ListNode firstGHead = head;
 5         int idx = 0;
 6         ListNode pp = null;
 7         while(head != null) {
 8             ListNode c = head;
 9             if(k <= 1 || c == null)return firstGHead;
10             for(int i = 0; i < k - 1&& c != null;i++) {
11                 c = c.next;
12             }
13             if(c == null) break; 
14             c = head;//save original head
15             int i = k - 1;
16             ListNode p = head;
17             ListNode pn = p.next;
18             ListNode lastEnd = pp;
19             while(i > 0){
20                 p = head;
21                 head = head.next;
22                 pn = p.next;
23                 pp = lastEnd;
24                 int swap = 0;
25                 while(swap < i){
26                     p.next = pn.next;
27                     pn.next = p;
28                     if(pp != null)
29                         pp.next = pn;
30                     pp = pn;
31                     pn= p.next;
32                     swap++;
33                 }
34                 i--;
35             }
36             if(idx++ == 0) firstGHead = head;
37             head = c.next;
38             pp = c;
39         }
40         return firstGHead;
View Code

逆轉那部分慘不忍睹啊。。。雖然過了leetcode,但是很不simple。還有,如果寫成遞歸leetcode是不讓你過的。

解法二:比較好的解法,又是leetcode討論組的人做的。首先,搞清楚怎么逆轉一個單鏈表。其實O(n)就可以了。第一個肯定是last one。然后我們每遍歷到一個node,就把它放到最鏈表的首位,最后一個么,最后就成為第一個了。下面是一個簡單逆轉鏈表的程序。

 1 ListNode dummy = new ListNode(0);
 2         dummy.next = head;
 3         ListNode pre = dummy;
 4         ListNode cur = head.next;
 5         ListNode last = head;
 6         while(cur != null){
 7             last.next = cur.next;
 8             cur.next = pre.next;
 9             pre.next = cur;
10             cur = last.next;
11         }
12         head = dummy.next;
reverse a linked list with a head node

因為有“放到鏈表首位”的操作,我們需要一個dummy的頭節點,遇到的新節點我們simply state: pre.next = cur; 保持一個invariant就是last節點始終在最后(cur的前面一個)

然后我們有如下方法:

/**
     * Reverse a link list between pre and next exclusively
     * an example:
     * a linked list:
     * 0->1->2->3->4->5->6
     * |           |   
     * pre        next
     * after call pre = reverse(pre, next)
     * 
     * 0->3->2->1->4->5->6
     *          |  |
     *          pre next
     * @param pre 
     * @param next
     * @return the reversed list's last node, which is the precedence of parameter next
     */
    private static ListNode reverse(ListNode pre, ListNode next){
        ListNode last = pre.next;//where first will be doomed "last"
        ListNode cur = last.next;
        while(cur != next){
            last.next = cur.next;
            cur.next = pre.next;
            pre.next = cur;
            cur = last.next;
        }
        return last;
    }
reverse range

就是區間的reverse。因為題目要求的是k group逆轉嘛。注意人返回的是最后一個(last)節點,這樣下一個k-group就可以用上了。牛人的想法真是周到體貼~~。主方法里面,遍歷的過程中每次都計數,每次到達k個節點,就可以使用pre和head.next調用上面的方法逆轉了。給跪了。

 1 public static ListNode reverseKGroup2(ListNode head, int k) {
 2         if(head == null || k == 1) return head;
 3         ListNode dummy = new ListNode(0);
 4         dummy.next = head;
 5         ListNode pre = dummy;
 6         int i = 0;
 7         while(head != null){
 8             i++;
 9             if(i % k ==0){
10                 pre = reverse(pre, head.next);
11                 head = pre.next;
12             }else {
13                 head = head.next;
14             }
15         }
16         return dummy.next;
17     }
reverseKGroup

通過這道題,我們學會了:

有效的算法是簡潔的!簡潔的!!簡潔的!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM