Leetcode之鏈表(一)

目錄

1.linked-list-cycle

2.linked-list-cycle-ii

3.partition-list

4.reverse-linked-list-ii

5.reverse-nodes-in-k-group

6.rotate-list

7.reorder-list

8.swap-nodes-in-pairs

9.convert-sorted-list-to-binary-search-tree

10.remove-nth-node-from-end-of-list


1.linked-list-cycle

題目:判斷給定的鏈表中是否有環,滿足不使用額外的空間

分析:利用快慢指針,如果快慢指針能相遇則說明有環

   public boolean hasCycle(ListNode head) {
        ListNode low = head;
        ListNode quick = head;
        while(quick != null && quick.next != null){
            quick = quick.next.next;
            low = low.next;
            if(low == quick)
                return true;
        }
        return false;
    }

2.linked-list-cycle-ii

題目:對於一個給定的鏈表,返回環的入口節點,如果沒有環,返回null

分析:見劍指offer面試題23 https://blog.csdn.net/Nibaby9/article/details/104050540

3.partition-list

題目:給出一個鏈表和一個值x,以x爲參照將鏈表劃分成兩部分,使所有小於x的節點都位於大於或等於x的節點之前。兩個部分之內的節點之間要保持的原始相對順序。例如:給出1->4->3->2->5->2和x = 3,返回1->2->2->4->3->5.

分析:新建立兩個結點,將小於x的結點與大於等於x的結點分別插到這兩個結點之後,形成兩條鏈表,最後將兩條鏈表連起來即可。

    public ListNode partition(ListNode head, int x) {
        ListNode head1 = new ListNode(0);
        ListNode head2 = new ListNode(0);
        ListNode cur = head,cur1 = head1,cur2 = head2;
        while(cur != null){
            if(cur.val < x){
                cur1.next = cur;
                cur1 = cur1.next;
            }
            else{
                cur2.next = cur;
                cur2 = cur2.next;
            }
            cur = cur.next;
        }
        cur1.next = head2.next;
        cur2.next = null;
        return head1.next;
    }

4.reverse-linked-list-ii

題目:將一個鏈表m位置到n位置之間的區間反轉,要求使用原地算法,並且在一次掃描之內完成反轉。例如:給出的鏈表爲1->2->3->4->5->NULL, m = 2 ,n = 4,返回1->4->3->2->5->NULL。注意:給出的m,n滿足以下條件:1 ≤ m ≤ n ≤ 鏈表長度

分析:定義兩個指針,指針pre指向鏈表開始反轉的前一個位置,指針start指向鏈表反轉的第一個位置。每次刪除start的後一個節點,再該結點插入pre後面,需刪除n-m次即可。注意:鏈表的頭結點可能會發生變化,需要創建一個新節點來指向鏈表的頭結點。

翻轉鏈表類似題見劍指offer面試題24 https://blog.csdn.net/Nibaby9/article/details/104050540

    public ListNode reverseBetween(ListNode head, int m, int n){
        ListNode preHead = new ListNode(0);//方便返回鏈表頭結點,修改後的頭結點有可能不是head
        preHead.next = head;//勿漏
        ListNode pre = preHead;
        ListNode start = head;
        for(int i = 1;i < m;i++){
            pre = start;
            start = start.next;
        }
        for(int i = 1;i <= n - m;i++) {//需要刪n-m次
            ListNode temp = start.next;
            start.next = temp.next;
            temp.next = pre.next;
            pre.next = temp;
        }
        return preHead.next;
    }

5.reverse-nodes-in-k-group

題目:將給出的鏈表中的節點每k個一組翻轉,返回翻轉後的鏈表。如果鏈表中的節點數不是k的倍數,將最後剩下的節點保持原樣。你不能更改節點中的值,只能更改節點本身。只允許使用常數級的空間。例如:給定的鏈表是1->2->3->4->5,對於 k = 2, 你應該返回 2->1->4->3->5;對於 k = 3, y你應該返回 3->2->1->4->5

分析:遞歸。將前k個節點與剩下節點斷開,翻轉前k個節點,遞歸求解剩下節點,再將兩條鏈表合併即可。

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode end = head;
        int index = 1;
        while(index < k && end != null){
            end = end.next;
            index++;
        }
        if(end == null || index < k)
            return head;
        ListNode head2 = end.next;
        end.next = null;
        head2 = reverseKGroup(head2,k);
        ListNode head1 = reverse(head);
        head.next = head2;
        return head1;
    }

    private ListNode reverse(ListNode head) {
        ListNode cur = head,pre = null;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }

6.rotate-list

題目:將給定的鏈表向右轉動k個位置,k是非負數。例如:給定1->2->3->4->5->null , k=2,返回4->5->1->2->3->null。

分析:特別注意k可能大於鏈表長度!!!因此k = k%len。將尾結點next指針指向首節點,形成一個環,接着往後跑len-k步,就是所需鏈表的尾結點,從這斷開鏈表即可。

    public ListNode rotateRight(ListNode head, int n) {
        if (head == null || head.next == null || n == 0)
            return head;
        int len = 1;
        ListNode tail = head;
        while(tail.next != null){
            len++;
            tail = tail.next;
        }
        tail.next = head;//首尾相連形成環
        for(int i = 0;i < len - n % len;i++){//注意n有可能大於鏈表長度
            tail = tail.next;
        }
        head = tail.next;
        tail.next = null;
        return head;
    }

7.reorder-list

題目:將給定的單鏈表L: L 0→L 1→…→L n-1→L n,重新排序爲: L 0→L n →L 1→L n-1→L 2→L n-2→…要求使用原地算法,並且不改變節點的值。例如:對於給定的單鏈表{1,2,3,4},將其重新排序爲{1,4,2,3}.

分析:將鏈表分成兩半,然後將後半部分翻轉,最後拼接兩個鏈表即可。

  public void reorderList(ListNode head) {
        if(head == null)
            return;
        //將鏈表從中間斷開
        ListNode mid = findMid(head);
        ListNode head2 = mid.next;
        mid.next = null;
        //將鏈表的前半部分和反轉後的後半部分合並
        ListNode cur1 = head,cur2 = reverse(head2);
        while(cur1 != null && cur2 != null){
            ListNode temp1 = cur1.next;
            ListNode temp2 = cur2.next;
            cur1.next = cur2;
            cur2.next = temp1;
            cur1 = temp1;
            cur2 = temp2;
        }
    }

    private ListNode reverse(ListNode head) {
        ListNode pre = null,cur = head;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }

    private ListNode findMid(ListNode head) {
        ListNode low = head,fast = head;
        while(fast != null && fast.next != null){
            low = low.next;
            fast = fast.next.next;
        }
        return low;
    }

8.swap-nodes-in-pairs

題目:將給定的鏈表中每兩個相鄰的節點交換一次,返回鏈表的頭指針。例如,給出1->2->3->4,你應該返回鏈表2->1->4->3。你給出的算法只能使用常量級的空間。你不能修改列表中的值,只能修改節點本身。

分析:遞歸求解即可。

    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode temp = head.next;
        head.next = swapPairs(temp.next);
        temp.next = head;
        return temp;
    }

9.convert-sorted-list-to-binary-search-tree

題目:給定一個單鏈表,其中的元素按升序排序,請將它轉化成平衡二叉搜索樹(BST)

分析:先利用快慢指針找到單鏈表的中間節點,然後以該節點爲根結點,再把原鏈表斷開,分爲前後兩個鏈表,遞歸調用原函數,分別爲根結點的左右子樹。注意參數的設計,傳遞的是鏈表的第一個結點和最後一個節點的next。

    public TreeNode sortedListToBST(ListNode head) {
         return toBST(head,null);
    }

    private TreeNode toBST(ListNode head, ListNode tail) {
        if(head == tail)
            return null;
        ListNode quick = head;
        ListNode low = head;
        while(quick != tail && quick.next != tail){
            low = low.next;
            quick = quick.next.next;
        }
        TreeNode root = new TreeNode(low.val);
        root.left = toBST(head,low);
        root.right = toBST(low.next,tail);
        return root;
    }

10.remove-nth-node-from-end-of-list

題目:給定一個鏈表,刪除鏈表的倒數第n個節點並返回鏈表的頭指針。例如, 給出的鏈表爲:1->2->3->4->5, n= 2.↵↵ 刪除了鏈表的倒數第n個節點之後,鏈表變爲1->2->3->5.備註:題目保證n一定是合法的;請嘗試只用一步操作完成該功能

分析:刪除倒數第n個節點需先找出倒數第n+1個節點。倒數數第n+1個節點也就是第len-n個節點,採用快慢指針,快指針先走出n步,隨後兩個指針同時前進,當快指針到達鏈表尾部時,慢指針剛好到達倒數第n+1個節點的位置。注意刪除節點爲鏈表頭結點的情況。類似題見劍指offer面試題22 https://blog.csdn.net/Nibaby9/article/details/104050540

   public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode preHead = new ListNode(0);
        preHead.next = head;
        ListNode quick = preHead;
        ListNode slow = preHead;
        for(int i = 0;i < n;i++)
            quick = quick.next;
        while(quick.next != null){
            slow = slow.next;
            quick = quick.next;
        }
        slow.next = slow.next.next;
        return preHead.next;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章