链表理论基础
链表的类型: 单向链表、双向链表、循环链表
链表的操作: 增加、删除、修改
[LeetCode] 203. 移除链表元素
要删除一个节点, 必须知道它的上一个节点是谁, 删除的是头节点, 还需要更新头节点.
这时候如果添加一个虚拟节点指向头节点, 就不需要关心头节点是否被删除, 所有节点都一视同仁, 最后返回的是 virtualNode.next 即可.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode virtualNode = new ListNode(0, head);
head = virtualNode;
while (head.next != null) {
if (head.next.val == val) {
head.next = head.next.next;
} else {
head = head.next;
}
}
return virtualNode.next;
}
}
[LeetCode] 707. 设计链表
整体没有遇到什么困难, 但是对于链表遍历的代码掌控能力还是不够, 什么时候用 while(current.next != null)、什么时候用 while (current != null) 还是需要思考一下才想明白. 对于基础题这是不太应该的.
class MyLinkedList {
private Node virtualHead = new Node(0, null);
// 添加了尾节点, 但是维护起来还是比较麻烦的.
// 所有添加删除的时候都需要维护一下尾节点
private Node tail = null;
private int size = 0;
public MyLinkedList() {
}
public int get(int index) {
if (index >= size) {
return -1;
}
Node current = virtualHead.next;
int currentIndex = 0;
while (current != null) {
if (currentIndex++ == index) {
return current.val;
} else {
current = current.next;
}
}
return -1;
}
public void addAtHead(int val) {
Node newHead = new Node(val, virtualHead.next);
virtualHead.next = newHead;
if (tail == null) {
tail = newHead;
}
size++;
}
public void addAtTail(int val) {
Node current = virtualHead;
while (current.next != null ) {
current = current.next;
}
current.next = new Node(val, null);
tail = current.next;
// if (tail == null) {
// virtualHead.next = new Node(val, null);
// tail = virtualHead.next;
// } else {
// tail.next = new Node(val, null);
// tail = tail.next;
// }
size++;
}
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
Node current = virtualHead;
int currentIndex = 0;
while (current != null) {
if (currentIndex++ == index) {
Node newNode = new Node(val, current.next);
current.next = newNode;
if (newNode.next == null) {
tail = newNode;
}
size++;
return;
} else {
current = current.next;
}
}
return;
}
public void deleteAtIndex(int index) {
Node current = virtualHead;
int currentIndex = 0;
while (current.next != null) {
if (currentIndex++ == index) {
current.next = current.next.next;
if (current.next == null) {
tail = current;
}
size--;
return;
} else {
current = current.next;
}
}
return;
}
private class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
public Node(int val, Node next) {
this.val = val;
this.next = next;
}
}
}
/**
* 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);
*/
[LeetCode] 206. 反转链表
核心思想是, 记录住三个节点: 前一个节点, 当前节点, 下一个节点. 对于头节点, 前一个节点是空节点. 因此 Node pre = null; Node current = head; while (current != null) { Node next = current.next; current.next = pre; pre = current; current = next;}
这里我一开是犯了个错, 初始化的时候把 pre 指向了 head, 这样如果不单独处理一下 head.next = null, 就会造成死循环.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode pre = null;
ListNode current = head;
ListNode next = null;
while (current != null) {
next = current.next;
current.next = pre;
pre = current;// pre 记录了每个非空的节点
current = next;
}
return pre;// pre 指向了最后一个非空节点, 该节点反转后为新链表的头节点.
}
}