[連結串列]leetcode1019-連結串列中的下一個更大節點

Deep-Cola發表於2020-12-13

[連結串列]–連結串列中的下一個更大節點


題目連結

leetcode 1019.連結串列中的下一個更大節點

題目

給出一個以頭節點 head 作為第一個節點的連結串列。連結串列中的節點分別編號為:node_1, node_2, node_3, … 。

每個節點都可能有下一個更大值(next larger value):對於 node_i,如果其 next_larger(node_i) 是 node_j.val,那就有 j > i 且 node_j.val > node_i.val,而 j 是可能的選項中最小的那個。如果不存在這樣的 j,那麼下一個更大值為 0 。

返回整數答案陣列 answer,其中 answer[i] = next_larger(node_{i+1}) 。

注意:在下面的示例中,諸如 [2,1,5] 這樣的輸入(不是輸出)是連結串列的序列化表示,其頭節點的值為 2,第二個節點值為 1,第三個節點值為 5 。

示例

輸入:[2,1,5]
輸出:[5,5,0]

輸入:[2,7,4,3,5]
輸出:[7,0,5,5,0]

輸入:[1,7,5,1,9,2,5,1]
輸出:[7,9,9,9,0,5,0,0]

解析

見過!但是做的不是連結串列形式,陣列!不如…

  1. 將節點值全部取出來裝入 list,裝作是一個動態陣列;
  2. 使用一個雙重迴圈遍歷 list,找出後面第一個大於自身的數裝入陣列即可,沒找到?那就是 0了。
    這時間就…說不出口

程式碼實現

public class Solution1019 {

    /**
     * Definition for singly-linked list
     */
    class ListNode {
        int val;
        ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }

    /**
     * 1.將連結串列的節點值裝入 list
     * 2.遍歷連結串列找出第一個大於自身的數裝入 result , 沒有裝入值的預設是 0
     * 時間複雜度 O(N^2)
     */
    public int[] nextLargerNodes(ListNode head) {
        if (head == null) return null;
        List<Integer> list = new ArrayList<>();
        ListNode cur = head;
        // 取出節點值
        while (cur != null) {
            list.add(cur.val);
            cur = cur.next;
        }
        // 找出第一個大於自身的數即可
        int[] result = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            for (int j = i+1; j < list.size(); j++) {
                if (list.get(j) > list.get(i)) {
                    result[i] = list.get(j);
                    break;
                }
            }
        }
        return result;
    }
}

單調棧!也就是這個棧內元素是單調遞增或者是單調遞減的。

  1. 還是取出所有的節點值裝入 list;
  2. 從後向前遍歷 list,對於當前元素的處理就是維護一個單調遞增棧:在棧不為空的前提下將所有不大於當前元素的都彈出棧;
  3. 對於當前元素來說:
    (1)棧為空:說明後面所有元素都小於他,所以對應陣列位置是0;
    (2)棧不為空:那棧頂元素就是後面所有元素中第一個大於他的,對應陣列位置就是棧頂元素了。
  4. 當前元素壓棧即可。

程式碼實現

public class Solution1019 {

    /**
     * Definition for singly-linked list
     */
    class ListNode {
        int val;
        ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }

    /**
     * 單調棧
     * 1.遍歷所有節點將值放入 list
     * 2.單調棧: 棧頂元素最小
     *      1.棧中存放的是後面大於當前遍歷到的 list 元素的最大值
     *      2.從後向前遍歷 list, 將棧中所有小於當前元素的都彈出去, 維護單調棧
     *      3.第二步之後棧頂元素(如果存在)必然是後面第一個大於當前元素的值,即下一個更大節點: 棧空說明遍歷過的元素自己最大
     *      4.每次迴圈進行完將當前元素壓棧, 進行下一次判斷
     */
    public int[] nextLargerNodes(ListNode head) {
        if (head == null) return null;
        List<Integer> list = new ArrayList<>();
        // 取出節點值
        while (head != null) {
            list.add(head.val);
            head = head.next;
        }
        // 使用棧存放對應位置的 list 元素以及其之後元素中最大的值
        int[] result = new int[list.size()];
        Stack<Integer> stack = new Stack<>();
        for (int i = list.size()-1; i >= 0; i--) {
            // 所有小於等於 list.get(i) 的都彈出去
            // 棧裡面存放的都大於 list,get(i), 那麼第一個大於 list 元素的就是棧頂元素
            while (!stack.isEmpty() && stack.peek() <= list.get(i)) {
                stack.pop();
            }
            // 棧不為空時說明棧頂元素就是當前大於 list 元素的第一個元素
            // 棧為空說明當前元素大於遍歷過的所有元素, 也就是說後面沒有比它更大的了, 所以此時下一個更大節點是 0
            result[i] = stack.isEmpty() ? 0 : stack.peek();
            stack.push(list.get(i));
        }
        return result;
    }
    
}

-----------------------------------------------------------------------------有始有終分割線----------------------------------------------------------------------------------

相關文章