1.移除元素
1.1. 手写递归的
public static ListNode removeElements(ListNode head, int val) {
if (head == null) {
return null;
}
if (head.val == val) {
return removeElements(head.next, val);
}else {
head.next = removeElements(head.next, val);
}
return head;
}
2.手写链表的一些功能
class MyLinkedList {
private ListNode root;
private int size;
public MyLinkedList() {
root = null;
size = 0;
}
public int get(int index) {
if(index < 0 || index >= size) {
return -1;
}
ListNode temp = root;
int idx = 0;
while (idx++ < index && temp != null) {
temp = temp.next;
}
return temp == null ? -1 : temp.val;
}
public void addAtHead(int val) {
ListNode listNode = new ListNode(val);
listNode.next = root;
root = listNode;
size ++;
}
public void addAtTail(int val) {
ListNode temp = root;
while (temp.next != null) {
temp = temp.next;
}
temp.next = new ListNode(val);
size++;
}
public void addAtIndex(int index, int val) {
ListNode temp = root;
if (root == null) {
return;
}
int idx = 0;
while (idx++ < index && temp.next != null) {
temp = temp.next;
}
ListNode MyLinkedList = new ListNode(val);
MyLinkedList.next = temp.next;
temp.next = MyLinkedList;
size++;
}
public void deleteAtIndex(int index) {
ListNode temp = root;
if (root == null) {
return;
}
int idx = 0;
while (idx++ < index && temp.next != null) {
temp = temp.next;
}
if (temp.next == null) {
return;
}
temp.next = temp.next.next;
size--;
}
}
3.链表倒排
3.1 手写
public static ListNode reverseList(ListNode head) {
ListNode reverse = null;
while (head != null) {
ListNode temp = head.next;
head.next = reverse;
reverse = head;
head = temp;
}
return reverse;
}
3.2 递归
public ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
return reverseListRecursionTerm(null, head);
}
private ListNode reverseListRecursionTerm(ListNode node, ListNode head) {
if (head == null) {
return node;
}
ListNode temp = head.next;
head.next = node;
return reverseListRecursionTerm(head, temp);
}
4. 链表值两两交换
4.1 递归手写,好理解一些
public static ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode nextNext = head.next.next;
ListNode next = head.next;
head.next = swapPairs(nextNext);
next.next = head;
return next;
}
4.2 非递归
public ListNode swapPairs(ListNode head) {
ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点
dumyhead.next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode cur = dumyhead;
ListNode temp; // 临时节点,保存两个节点后面的节点
ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点
ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点
while (cur.next != null && cur.next.next != null) {
temp = cur.next.next.next;
firstnode = cur.next;
secondnode = cur.next.next;
cur.next = secondnode; // 步骤一
secondnode.next = firstnode; // 步骤二
firstnode.next = temp; // 步骤三
cur = firstnode; // cur移动,准备下一轮交换
}
return dumyhead.next;
}
5.删除倒数第n个节点
5.1 手写,边界复杂
public ListNode removeNthFromEnd(ListNode head, int n) {
// 快慢指针
ListNode fast = head;
ListNode slow = head;
int i =0;
// 关键找到倒数第k个
while (i++ < n) {
fast = fast.next;
}
if (fast == null) {
return slow.next;
}
while (fast.next != null) {
fast =fast.next;
slow = slow.next;
}
// 首
slow.next = slow.next.next;
return head;
}
6.链表是否为环,并且环的交点
public ListNode detectCycle(ListNode head) {
// 快慢指针
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null && slow != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return null;
}
while (head != fast) {
head = head.next;
fast = fast.next;
}
return head;
}
快指针一定在第一圈能够追上慢指针
公式最终推导出来 x = n(y+z) + z
由此公式看出,从fast和slow相遇点,同头节点共同出发,最终会在环形入口相遇。
只不过从相遇点出发的指针可能会绕环n圈罢了