1. 程式人生 > 其它 >LeetCode 497. 非重疊矩形中的隨機點(字首和+二分查詢)

LeetCode 497. 非重疊矩形中的隨機點(字首和+二分查詢)

技術標籤:資料結構資料結構java連結串列

雙向連結串列

雙向連結串列我們可以從頭到尾查詢,也可以從尾到頭查詢。

雙向連結串列圖如下:
在這裡插入圖片描述

1、雙向連結串列結點類

class Node<E>{
    E data;
    Node<E> prev;
    Node<E> next;

    public Node(E data, Node<E> prev, Node<E> next) {
        this.data = data;
        this.prev = prev;
        this.next =
next; } }

2、新增到尾結點的方法

public void linkLast(Object e){
        // 用臨時變數 last 儲存 head 結點
        final Node<Object> last = tail;
        // 建立一個新的結點,讓他的 prev 指標指向 last,next 指標指向 null 結點
        final Node<Object> newNode = new Node<>(e, last, null);
        // 讓 tail 指向新的結點
        tail =
newNode; // 如果之前的 last 為空,說明之前連結串列是空的,讓 head 和 tail 同時指向新結點即可 if (last == null) head = newNode; else // 如果之前連結串列不為空,讓之前 last 結點的 next 指向新的結點 last.next = newNode; size++; }

3、新增到頭結點的方法

public void linkFirst(Object e) {
        // 用臨時變數 firt 儲存 head 結點
final Node<Object> first = head; // 建立一個新的結點,讓他的 prev 指標指向 null,next指標指向head結點 final Node<Object> newNode = new Node<>(e, null, first); // 讓 head 指向新的結點 head = newNode; // 如果之前的 first 為空,說明之前連結串列是空的,讓 head 和 tail 同時指向新結點即可 if (first == null) tail = newNode; else // 如果之前連結串列不為空,讓之前 first 結點的 prev 指向新的結點 first.prev = newNode; size++; }

4、新增到指定結點之前的方法

public void linkBefore(Object e, Node<Object> node) {
        // 用臨時變數 nodeprev 儲存 node 結點前一個結點
        final Node<Object> nodeprev = node.prev;
        // 建立一個新結點,讓他的 prev 指標指向 nodeprev,next 指標指向 node
        final Node<Object> newNode = new Node<>(e, nodeprev, node);
        // 讓 node 的 next 指標指向新結點
        node.prev = newNode;
        // 如果之前 node 結點前一個結點為空,說明之前 node 是頭結點,讓 head 指向新結點
        if (nodeprev == null)
            head = newNode;
        else // 如果之前 node 結點前一個結點不為空,讓 node 結點前一個結點指向新結點
            nodeprev.next = newNode;
        size++;
    }

5、刪除連結串列的尾結點的方法

public Object unlinkLast(Node<Object> last) {
        // 用臨時變數 element 儲存 last 結點的資料
        final Object element = last.data;
        // 建立一個新結點,指向 last 的前一個結點
        final Node<Object> prev = last.prev;
        // 將 last 結點的資料和前一個指標指向 null 
        last.data = null;
        last.prev = null;
        // 尾結點指向 prev
        tail = prev;
        // 如果只有一個結點,把尾結點刪除,相當於把連結串列清空了
        if (prev == null)
            head = null;
        else // 如果不止有一個結點,把 prev 的 next 指向 null
            prev.next = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

6、刪除連結串列的頭結點的方法

public Object unlinkFirst(Node<Object> first) {
        // 用臨時變數 element 儲存 first 結點的資料
        final Object element = first.data;
        // 建立一個新結點,指向 first 的下一個結點
        final Node<Object> nest = first.next;
        // 將 first 結點的資料和下一個指標指向 null
        first.data = null;
        first.next = null;
        // 頭結點指向 prev
        head = nest;
        // 如果只有一個結點,把頭結點刪除,相當於把連結串列清空了
        if (nest == null)
            tail = null;
        else // 如果不止有一個結點,把 next 的 prev 指向 null
            nest.prev = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

7、刪除連結串列的中間結點的方法

public Object unlink(Node<Object> x) {
        // 用臨時變數 element 儲存 x 結點的資料
        final Object element = x.data;
        // 建立一個新結點,指向 x 的前一個結點
        final Node<Object> prev = x.prev;
        // 建立一個新結點,指向 x 的下一個結點
        final Node<Object> next = x.next;
        // 前一個結點是空
        if (prev == null) {
            head = next;
        } else { // 前一個結點不為空時,prev 的 next 指標指向 next,將 x 的 prev 置空
            prev.next = next;
            x.prev = null;
        }
        // 後一個結點是空
        if (next == null) {
            tail = null;
        } else { // 後一個結點不為空時,next 的 prev 指標指向 prev,將 x 的 next 置空
            next.prev = prev;
            x.next = null;
        }
        // 將 x 的 data 置空
        x.data = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

完整程式碼

class Node<E>{
    E data;
    Node<E> prev;
    Node<E> next;

    public Node() {
    }

    public Node(E data, Node<E> prev, Node<E> next) {
        this.data = data;
        this.prev = prev;
        this.next = next;
    }
}
public class MyLinkedList {
    Node<Object> tail = null;
    Node<Object> head = null;
    static int size = 0;

    public MyLinkedList() {
    }

    public MyLinkedList(Node<Object> tail, Node<Object> head) {
        this.tail = tail;
        this.head = head;
    }

    // 新增到尾結點的方法
    public void linkLast(Object e){
        // 用臨時變數 last 儲存 head 結點
        final Node<Object> last = tail;
        // 建立一個新的結點,讓他的 prev 指標指向 last,next 指標指向 null 結點
        final Node<Object> newNode = new Node<>(e, last, null);
        // 讓 tail 指向新的結點
        tail = newNode;
        // 如果之前的 last 為空,說明之前連結串列是空的,讓 head 和 tail 同時指向新結點即可
        if (last == null)
            head = newNode;
        else // 如果之前連結串列不為空,讓之前 last 結點的 next 指向新的結點
            last.next = newNode;
        size++;
    }

    // 新增到頭結點的方法
    public void linkFirst(Object e) {
        // 用臨時變數 firt 儲存 head 結點
        final Node<Object> first = head;
        // 建立一個新的結點,讓他的 prev 指標指向 null,next 指標指向 head 結點
        final Node<Object> newNode = new Node<>(e, null, first);
        // 讓 head 指向新的結點
        head = newNode;
        // 如果之前的 first 為空,說明之前連結串列是空的,讓 head 和 tail 同時指向新結點即可
        if (first == null)
            tail = newNode;
        else // 如果之前連結串列不為空,讓之前 first 結點的 prev 指向新的結點
            first.prev = newNode;
        size++;
    }

    // 新增到指定結點之前的方法
    public void linkBefore(Object e, Node<Object> node) {
        // 用臨時變數 nodeprev 儲存 node 結點前一個結點
        final Node<Object> nodeprev = node.prev;
        // 建立一個新結點,讓他的 prev 指標指向 nodeprev,next 指標指向 node
        final Node<Object> newNode = new Node<>(e, nodeprev, node);
        // 讓 node 的 next 指標指向新結點
        node.prev = newNode;
        // 如果之前 node 結點前一個結點為空,說明之前 node 是頭結點,讓 head 指向新結點
        if (nodeprev == null)
            head = newNode;
        else // 如果之前 node 結點前一個結點不為空,讓 node 結點前一個結點指向新結點
            nodeprev.next = newNode;
        size++;
    }

    // 刪除連結串列的尾結點的方法
    public Object unlinkLast(Node<Object> last) {
        // 用臨時變數 element 儲存 last 結點的資料
        final Object element = last.data;
        // 建立一個新結點,指向 last 的前一個結點
        final Node<Object> prev = last.prev;
        // 將 last 結點的資料和前一個指標指向 null
        last.data = null;
        last.prev = null;
        // 尾結點指向 prev
        tail = prev;
        // 如果只有一個結點,把尾結點刪除,相當於把連結串列清空了
        if (prev == null)
            head = null;
        else // 如果不止有一個結點,把 prev 的 next 指向 null
            prev.next = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

    // 刪除連結串列的頭結點的方法
    public Object unlinkFirst(Node<Object> first) {
        // 用臨時變數 element 儲存 first 結點的資料
        final Object element = first.data;
        // 建立一個新結點,指向 first 的下一個結點
        final Node<Object> nest = first.next;
        // 將 first 結點的資料和下一個指標指向 null
        first.data = null;
        first.next = null;
        // 頭結點指向 prev
        head = nest;
        // 如果只有一個結點,把頭結點刪除,相當於把連結串列清空了
        if (nest == null)
            tail = null;
        else // 如果不止有一個結點,把 next 的 prev 指向 null
            nest.prev = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

    // 刪除連結串列的中間結點的方法
    public Object unlink(Node<Object> x) {
        // 用臨時變數 element 儲存 x 結點的資料
        final Object element = x.data;
        // 建立一個新結點,指向 x 的前一個結點
        final Node<Object> prev = x.prev;
        // 建立一個新結點,指向 x 的下一個結點
        final Node<Object> next = x.next;
        // 前一個結點是空
        if (prev == null) {
            head = next;
        } else { // 前一個結點不為空時,prev 的 next 指標指向 next,將 x 的 prev 置空
            prev.next = next;
            x.prev = null;
        }
        // 後一個結點是空
        if (next == null) {
            tail = null;
        } else { // 後一個結點不為空時,next 的 prev 指標指向 prev,將 x 的 next 置空
            next.prev = prev;
            x.next = null;
        }
        // 將 x 的 data 置空
        x.data = null;
        size--;
        // 返回刪除結點的資料
        return element;
    }

}

測試一下

public class Test {
    static MyLinkedList myLinkedList = new MyLinkedList();
    public static void main(String[] args) {
        myLinkedList.linkFirst(1);
        show();
        myLinkedList.linkLast(2);
        myLinkedList.linkLast(3);
        show();
        myLinkedList.linkBefore(4, myLinkedList.head);
        show();
        System.out.println("刪除連結串列的中間結點: " + myLinkedList.unlink(myLinkedList.head.next));
        show();
        System.out.println("刪除連結串列的尾結點: " + myLinkedList.unlinkLast(myLinkedList.tail));
        show();
        System.out.println("刪除連結串列的頭結點: " + myLinkedList.unlinkFirst(myLinkedList.head));
        show();
    }
    public static void show() {
        Node<Object> node = myLinkedList.head;
        while (node != null) {
            System.out.print(node.data + " ");
            node = node.next;
        }
        System.out.println();
    }
}

執行結果如下

1 
1 2 3 
4 1 2 3 
刪除連結串列的中間結點: 1
4 2 3 
刪除連結串列的尾結點: 3
4 2 
刪除連結串列的頭結點: 4
2