鏈表Code

劍指 Offer 22. 鏈表中倒數第k個節點

輸入一個鏈表,輸出該鏈表中倒數第k個節點。爲了符合大多數人的習慣,本題從1開始計數,即鏈表的尾節點是倒數第1個節點。例如,一個鏈表有6個節點,從頭節點開始,它們的值依次是一、二、三、四、五、6。這個鏈表的倒數第3個節點是值爲4的節點。java

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。node

示例:數組

給定一個鏈表: 1->2->3->4->5, 和 k = 2.

返回鏈表 4->5

題解

1、固定長度的鏈表

  • 由於返回末尾固定長度的鏈表,因此一開始想到用一個新的、固定長度的鏈表解決
  • 假設k=2,就建立一個新鏈表,先將head中頭兩個結點存入
  • 以後head中若是還有結點,則添加至新鏈表尾部,並將頭部節點刪除,head循環完畢返回新鏈表便可
public ListNode getKthFromEnd(ListNode head, int k) {
    if (k == 0) return null;
    ListNode node = new ListNode(0, null);
    ListNode curr = node;
    while (head != null) {
        ListNode temp = head.next;
        curr.next = head;
        curr = curr.next;
        curr.next = null;
        head = temp;
        k--;
        if (k < 0)
            node = node.next;
    }
    return node.next;
}

2、雙指針(最優)

設置快慢指針,兩個指針之間正好有k個元素,遍歷head的時候兩個指針分別加一,遍歷結束後,返回慢指針便可網絡

public ListNode getKthFromEnd(ListNode head, int k) {
    if (k == 0) return null;
    ListNode next = head;
    for (int i = 0; i < k - 1; i++) {
        next = next.next;
    }
    while (next.next != null) {
        head = head.next;
        next = next.next;
    }
    return head;
}

劍指 Offer 18. 刪除鏈表的節點

給定單向鏈表的頭指針和一個要刪除的節點的值,定義一個函數刪除該節點。函數

返回刪除後的鏈表的頭節點。指針

示例 1:code

輸入: head = [4,5,1,9], val = 5
輸出: [4,1,9]
解釋: 給定你鏈表中值爲 5 的第二個節點,那麼在調用了你的函數以後,該鏈表應變爲 4 -> 1 -> 9.
示例 2:對象

輸入: head = [4,5,1,9], val = 1
輸出: [4,5,9]
解釋: 給定你鏈表中值爲 1 的第三個節點,那麼在調用了你的函數以後,該鏈表應變爲 4 -> 5 -> 9.排序

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。遞歸

題解

1、刪除鏈表中結點

public ListNode deleteNode(ListNode head, int val) {
    if (head.val == val) {
        head = head.next;
        return head;
    }
    ListNode curr = head;
    while (curr != null && curr.next != null) {
        if (curr.next.val == val) {
            curr.next = curr.next.next;
        }
        curr = curr.next;
    }
    return head;
}

劍指 Offer 25. 合併兩個排序的鏈表

輸入兩個遞增排序的鏈表,合併這兩個鏈表並使新鏈表中的節點仍然是遞增排序的。

示例1:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
限制:

0 <= 鏈表長度 <= 1000

注意:本題與主站 21 題相同:https://leetcode-cn.com/problems/merge-two-sorted-lists/

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。

題解

1、合併到新鏈表中

  • 將兩個指針分別指向兩條鏈表
  • 比較指針上的值,將較小的那個存入到新鏈表中,並將指針日後移一位
  • 只要有一個鏈表循環完,判斷若是有剩下的鏈表,就直接合併到新鏈表上
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode node = new ListNode(0,null);
    ListNode curr = node;
    while (l1 != null && l2 != null) {
        if (l1.val <= l2.val) {
            ListNode temp = l1.next;
            curr.next = l1;
            curr = curr.next;
            curr.next = null;
            l1 = temp;
        } else {
            ListNode temp = l2.next;
            curr.next = l2;
            curr = curr.next;
            curr.next = null;
            l2 = temp;
        }
    }

    if (l1 != null) {
        curr.next = l1;
    } else {
        curr.next = l2;
    }
    return node.next;
}

2、遞歸(巧妙)

利用遞歸思想,遞歸終止條件就是其中一條鏈表爲空,而後返回另外一條便可

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    //遞歸終止條件
    if (l1 == null) {
        return l2;
    }
    if (l2 == null) {
        return l1;
    }
    //不停遞歸
    if (l1.val < l2.val ) {
        l1.next = mergeTwoLists(l1.next,l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l2.next,l1);
        return l2;
    }
}

876. 鏈表的中間結點

給定一個帶有頭結點 head 的非空單鏈表,返回鏈表的中間結點。

若是有兩個中間結點,則返回第二個中間結點。

示例 1:

輸入:[1,2,3,4,5]
輸出:此列表中的結點 3 (序列化形式:[3,4,5])
返回的結點值爲 3 。 (測評系統對該結點序列化表述是 [3,4,5])。
注意,咱們返回了一個 ListNode 類型的對象 ans,這樣:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:

輸入:[1,2,3,4,5,6]
輸出:此列表中的結點 4 (序列化形式:[4,5,6])
因爲該列表有兩個中間結點,值分別爲 3 和 4,咱們返回第二個結點。

提示:

給定鏈表的結點數介於 1 和 100 之間。

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/middle-of-the-linked-list
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。

題解

1、轉換爲數組

單鏈表不容易判斷中間節點的位置,因此將鏈表遍歷轉換爲數組

時間複雜度:O(n)

空間複雜度:O(n)

public ListNode middleNode(ListNode head) {
    ListNode[] nodes = new ListNode[100];
    int count = 0;
    while (head != null) {
        nodes[count++] = head;
        head = head.next;
    }
    return nodes[count / 2];
}

2、單指針

將鏈表循環遍歷一遍,記錄總共多少個節點,以後求出中間節點的位置,再次遍歷鏈表

時間複雜度:O(n)

空間複雜度:O(1)

public ListNode middleNode(ListNode head) {
    ListNode curr = head;
    int count = 0;
    while (curr != null) {
        count++;
        curr = curr.next;
    }
    int mid = count / 2;
    for (int i = 0; i < mid; i++) {
        head = head.next;
    }
    return head;
}

3、快慢雙指針

快指針每次走兩步,慢指針每次走一步,當快指針到達鏈表末尾時,慢指針就位於中間位置

時間複雜度:O(n)

空間複雜度:O(1)

public ListNode middleNode3(ListNode head) {
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}
相關文章
相關標籤/搜索