LeetCode 497. 非重疊矩形中的隨機點(字首和+二分查詢)
阿新 • • 發佈:2021-01-23
雙向連結串列
雙向連結串列我們可以從頭到尾查詢,也可以從尾到頭查詢。
雙向連結串列圖如下:
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