本文非原创,为摘录网络内容
1 简介
1.1 单链表
单链表的典型定义:
public class ListNode{int val;ListNode next;ListNode(int x){val = x;}}
1.2 双链表
双链表的定义:
public class ListNode{int val;ListNode next,prev;ListNode(int x){val = x;}}
1.3 设计链表
707. 设计链表
单链表的写法:
class ListNode {int val;ListNode next;ListNode(){};ListNode(int x){this.val = x;}}class MyLinkedList {int size ; //存储数量ListNode head; //虚拟头节点/** Initialize your data structure here. */public MyLinkedList() {size = 0;head = new ListNode(0);}/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */public int get(int index) {if(index>=size || index < 0){return -1;}ListNode node = head;for(int i = 0 ; i <= index; i++){node = node.next;}return node.val;}/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */public void addAtHead(int val) {addAtIndex(0,val);}/** Append a node of value val to the last element of the linked list. */public void addAtTail(int val) {addAtIndex(size,val);}/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */public void addAtIndex(int index, int val) {if(index > size) return;ListNode addNode = new ListNode(val);if(index < 0){index = 0;}ListNode preNode = head;for(int i = 0 ; i < index; i++){preNode = preNode.next;}addNode.next = preNode.next;preNode.next = addNode;size++;}/** Delete the index-th node in the linked list, if the index is valid. */public void deleteAtIndex(int index) {if(index >= size || index < 0) return;ListNode preNode = head;for(int i = 0 ; i < index ; i++){preNode = preNode.next;}preNode.next = preNode.next.next;size--;}}/*** Your MyLinkedList object will be instantiated and called as such:* MyLinkedList obj = new MyLinkedList();* int param_1 = obj.get(index);* obj.addAtHead(val);* obj.addAtTail(val);* obj.addAtIndex(index,val);* obj.deleteAtIndex(index);*/
双链表的写法:
class MyLinkedList {class ListNode{int val;ListNode next,prev;ListNode(int x){val = x;}}int size;ListNode head, tail;/** Initialize your data structure here. */public MyLinkedList() {size = 0;head = new ListNode(0);tail = new ListNode(0);head.next = tail;tail.prev = head;}/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */public int get(int index) {if(index < 0 || index >= size) return -1;ListNode cur = head;//头节点遍历还是尾结点遍历if(index < (size-1)/2){for(int i = 0 ; i <=index ; i++){cur = cur.next;}}else{cur = tail;for(int i = 0 ; i <= size - index - 1;i++){cur = cur.prev;}}return cur.val;}/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */public void addAtHead(int val) {ListNode addNode = new ListNode(val);ListNode cur = head;cur.next.prev = addNode;addNode.next = cur.next;cur.next = addNode;addNode.prev = cur;size++;}/** Append a node of value val to the last element of the linked list. */public void addAtTail(int val) {ListNode addNode = new ListNode(val);ListNode cur = tail;cur.prev.next = addNode;addNode.prev = cur.prev;addNode.next = cur;cur.prev = addNode;size++;}/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */public void addAtIndex(int index, int val) {if(index > size) return;if(index < 0) index = 0;ListNode curNode = head;for(int i = 0 ; i < index; i++){curNode = curNode.next;}ListNode addNode = new ListNode(val);addNode.next = curNode.next;curNode.next.prev = addNode;curNode.next = addNode;addNode.prev = curNode;size++;}//找到前一个index前的第一个节点/** Delete the index-th node in the linked list, if the index is valid. */public void deleteAtIndex(int index) {if(index >= size || index < 0 ) return;ListNode pre = head;for(int i = 0 ; i < index; i++){pre = pre.next;}ListNode t = pre.next.next;pre.next = t;t.prev = pre;size--;}}
2. 链表中的双指针技巧
在链表中使用两个速度不同的指针会发生的情况:
- 如果不存在环,快指针会停在链表的末尾;
- 如果有环,快指针最终会与慢指针相遇
一个安全的选择是每次移动慢指针一步,而移动快指针两步。每一次迭代,快速指针将额外移动一步。如果环的长度为 M,经过 M 次迭代后,快指针肯定会多绕环一周,并赶上慢指针。
需要注意快指针和慢指针的起点是否一致(有些题目需要保持一致)
// Initialize slow & fast pointersListNode slow = head;ListNode fast = head;/*** Change this condition to fit specific problem.* Attention: remember to avoid null-pointer error**/while (slow != null && fast != null && fast.next != null) {slow = slow.next; // move slow pointer one step each timefast = fast.next.next; // move fast pointer two steps each timeif (slow == fast) { // change this condition to fit specific problemreturn true;}}return false; // change return value to fit specific problem
除此之外,需要注意:
- 在调用 next 字段之前,始终检查节点是否为空。
获取空节点的下一个节点将导致空指针错误。例如,在我们运行 fast = fast.next.next 之前,需要检查 fast 和 fast.next 不为空。
- 仔细定义循环的结束条件。
链表环问题【以下问题中,快慢指针同节点】
参考《漫画算法:小灰的算法之旅》
1、如果链表有环,怎么求出环的长度?
当两个指针首次相遇,证明链表有环的时候,让两个指针从相遇点继续循环前进,并统计前进的循环 次数,直到两个指针第2次相遇。此时,统计出来的前进次数就是环长。
2、如果链表有环,如何求出入环节点?
也就是说,从链表头结点到入环点的距离,等于从首次相遇点绕环n-1圈再回到入环点的距离。
这样一来,只要把其中一个指针放回到头节点位置,另一个指针保持在首次相遇点,两个指针都是每 次向前走1步。那么,它们最终相遇的节点,就是入环节点。
相关题目:
142. 环形链表 II
160. 相交链表
19. 删除链表的倒数第 N 个结点
3 链表经典问题
在解决链表问题时,我们常常可以使用守卫节点来简化操作,如
ListNode dummyNode = new ListNode();dummyNode.next = head;
234. 回文链表 使用递归去解决问题
430. 扁平化多级双向链表
138. 复制带随机指针的链表
