戀上數據結構與算法:單向鏈表練習(四)

文章目錄

(一)練習01:刪除節點
(二)練習02:反轉鏈表(遞歸)
(三)練習03:反轉鏈表(迭代)(頭插法)
(四)練習04:環形鏈表
(五)作業題

(一)練習01:刪除節點

https://leetcode-cn.com/problems/delete-node-in-a-linked-list/

我們的目標是刪除指定的node,但是卻不提供查詢前一個node的方法
在這裏插入圖片描述
我們可以換一種思路,把後一個節點的,覆蓋掉要刪除的節點的(用next可以獲取下一個節點)
在這裏插入圖片描述
然後把值爲9的節點的next指向next的next,如下:
在這裏插入圖片描述
代碼如下:

    /**
     * 刪除指定的節點
     *
     * @param node
     */
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }

(二)練習02:反轉鏈表(遞歸)

https://leetcode-cn.com/problems/reverse-linked-list/

傳入head對應的鏈表如下:
在這裏插入圖片描述
期望的結果如下:
在這裏插入圖片描述

遞歸的過程如下:
如果傳入的是head.next(相當於從4開始翻轉),情況如下:
在這裏插入圖片描述
首先讓4號元素的next指向5號元素就可以了(此時的4號元素依然被head的next指着),然後讓5號元素的next指向null即可

代碼如下:

    /**
     * 傳入頭節點,反轉後傳回新的頭節點
     *
     * @param head
     * @return
     */
    public ListNode reverseList(ListNode head) {
//        if (head == null) return null;//到最後一步了,最後爲空節點
//        if (head.next == null) return head;//意味着這個鏈表只有一個節點了,翻轉了還是本身
        if (head == null || head.next == null) return head;

        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }

遞歸的解題思路:搞清楚方法的作用,比如本題中ListNode reverseList(ListNode head)的作用是返回翻轉後的鏈表的頭結點

(三)練習03:反轉鏈表(迭代)(頭插法)

https://leetcode-cn.com/problems/reverse-linked-list/

我們希望newHead指向1,1指向2,2指向3…
在這裏插入圖片描述
實現的步驟如下:
在這裏插入圖片描述
首先讓head的next指向newHead
在這裏插入圖片描述
然後讓newHead指向head
在這裏插入圖片描述
然後讓head指向下一個節點
在這裏插入圖片描述
效果如下:
在這裏插入圖片描述
再循環一遍,效果如下:
在這裏插入圖片描述
但是會有一個問題,一開始就讓head的next指向newHead,後面的節點就沒有被引用了,會被銷燬
在這裏插入圖片描述
所以我們需要搞一個臨時變量,讓它一開始就要指向head的next,如下:
在這裏插入圖片描述
此時再讓head的next指向newHead
在這裏插入圖片描述
再讓newHead指向head
在這裏插入圖片描述
head指向temp指向的節點
在這裏插入圖片描述
效果如下:
在這裏插入圖片描述
新一輪的循環開始之前,先讓temp指向head的next
在這裏插入圖片描述
代碼實現如下:

    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) return head;

        ListNode newHead = null;
        while (head != null) {
            ListNode tmp = head.next;
            head.next = newHead;
            newHead = head;
            head = tmp;
        }
        return newHead;
    }

(四)練習04:環形鏈表

https://leetcode-cn.com/problems/linked-list-cycle/

注意:java的引用相當於c語言的指針,這裏我們就用到快慢指針的思想

判斷一個鏈表是否有環的步驟如下:
假設有一個環形鏈表
在這裏插入圖片描述
首先用slow(慢指針)指向head
在這裏插入圖片描述
再用fast(快指針)指向head的next
在這裏插入圖片描述
注意:慢指針和快指針的初始位置不重要

慢指針一次走一步,快指針一次走兩步,最終它們都會進入環路,由於速度不一致,最終肯定會相遇

注意:如果fast(快指針)先指null(空指針),則代表該鏈表沒有環
在這裏插入圖片描述
代碼如下:

    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            //if (slow == fast) return true;
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) return true;//剛進來肯定是不相等的,先讓它們走一輪再判斷
        }
        return false;
    }

分析:複雜度需要看fast(快指針),大概是O(n/2),即O(n)

(五)作業題

203. 移除鏈表元素https://leetcode-cn.com/problems/remove-linked-list-elements/
83. 刪除排序鏈表中的重複元素https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
876. 鏈表的中間結點https://leetcode-cn.com/problems/middle-of-the-linked-list/

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