链表操作中的双指针技巧运用
该模块主要介绍链表操作中使用到的双指针技巧。其中包括虚拟头节点的运用,例如合并两个/多个有序链表,分割链表,删除链表的倒数第N个节点。也包含了快慢指针技巧的运用,例如获取链表的中间节点,判断链表是否有环。
合并两个有序单链表(LeetCode21)
public class MergeTwoList {
public static Node mergeTwoList(Node list1, Node list2) {
Node dummy = new Node(-1);
Node p1 = dummy;
while (list1 != null && list2 != null) {
if (list1.value < list2.value) {
p1.next = list1;
list1 = list1.next;
} else {
p1.next = list2;
list2 = list2.next;
}
p1 = p1.next;
}
if (list1 != null) {
p1.next = list1;
}
if (list2 != null) {
p1.next = list2;
}
return dummy.next;
}
}
分割链表(LeetCode86)
public class PartitionList {
public static Node partition(Node head, int x) {
Node dummy1 = new Node(-1);
Node dummy2 = new Node(-1);
Node p1 = dummy1;
Node p2 = dummy2;
Node p = head;
while (p != null) {
if (p.value < x) {
p1.next = p;
p1 = p1.next;
} else {
p2.next = p;
p2 = p2.next;
}
// 注意需要将原链表进行断链
Node temp = p.next;
p.next = null;
p = temp;
}
p1.next = dummy2.next;
return dummy1.next;
}
}
合并K个有序链表(LeetCode23)
public class MergeKList {
public static Node mergeKLists(Node[] lists) {
if (lists.length == 0) {
return null;
}
Node dummy = new Node(-1);
Node p = dummy;
PriorityQueue<Node> priorityQueue = new PriorityQueue<>(lists.length, (a, b) -> (a.value - b.value));
for (Node head : lists) {
if (head != null) {
priorityQueue.add(head);
}
}
while (!priorityQueue.isEmpty()) {
Node node = priorityQueue.poll();
p.next = node;
if (node.next != null) {
priorityQueue.add(node.next);
}
p = p.next;
}
return dummy.next;
}
}
删除链表的倒数第N个节点(LeetCode19)
public class RemoveNthFromEnd {
public static Node removeNthFromEnd(Node head, int n) {
Node dummy = new Node(-1);
dummy.next = head;
Node last = findNthFromEnd(head, n + 1);
last.next = last.next.next;
return dummy.next;
}
public static Node findNthFromEnd(Node head, int n) {
Node p1 = head;
for (int i = 0; i < n; i++) {
p1 = p1.next;
}
Node p2 = head;
while (p1 != null) {
p1 = p1.next;
p2 = p2.next;
}
return p2;
}
}
链表的中间节点(LeetCode876)
public class MiddleNode {
public static Node middleNode(Node head) {
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
判断链表是否有环并返回环的入口(LeetCode142)
public class CycleList {
public static Node findCycleStart(Node head) {
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next;
if (slow == fast) {
break;
}
}
// 无环条件下的退出
if (fast == null || fast.next == null) {
return null;
}
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
相交链表(LeetCode160)
public class IntersectionNode {
public static Node getIntersectionNode(Node head1, Node head2) {
Node p1 = head1;
Node p2 = head2;
while (p1 != p2) {
if (p1 == null) {
p1 = head2;
} else {
p1 = p1.next;
}
if (p2 == null) {
p2 = head1;
} else {
p2 = p2.next;
}
}
return p1;
}
}
判断链表是否为回文链表
public class PalindromeList {
public boolean isPalindrome(Node head) {
if (head == null || head.next == null) {
return false;
}
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
Node left = head;
Node right = reverse(slow);
boolean result = true;
while (right != null) {
if (left.value != right.value) {
result = false;
break;
}
left = left.next;
right = right.next;
}
return result;
}
public Node reverse(Node head) {
Node pre = null;
Node next = null;
Node cur = head;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
链表反转专题
使用迭代的方式反转链表
public class ReverseNode {
public static Node reverseNodeIterator(Node head) {
Node pre = null;
Node cur;
Node next;
cur = head;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
使用递归的方式反转链表
public class ReverseNode {
public static Node reverseNodeRecursion(Node head) {
if (head == null || head.next == null) {
return head;
}
Node last = reverseNodeRecursion(head);
head.next.next = head;
head.next = null;
return last;
}
}
使用递归的方式反转前N个节点
使用递归的方式反转前N个节点,需要注意反转后的原始头节点不再指向NULL了,而应该指向一个后驱节点。
public class ReverseNode {
private static Node successor = null;
public static Node reverseNodeRecursionN(Node head, int n) {
if (n == 1) {
successor = head.next;
return head;
}
Node last = reverseNodeRecursionN(head, n - 1);
head.next.next = head;
head.next = successor;
return last;
}
使用递归的方式反转m~n之间的节点
public class ReverseNode {
public static Node reverseNodeRecursionN(Node head, int n) {
Node successor = null;
if (n == 1) {
successor = head.next;
return head;
}
Node last = reverseNodeRecursionN(head, n - 1);
head.next.next = head;
head.next = successor;
return last;
}
public static Node reverseNodeRecursionBetween(Node head, int m, int n) {
if (m == 1) {
return reverseNodeRecursionN(head, n);
}
head.next = reverseNodeRecursionBetween(head, m - 1, n - 1);
return head;
}
}
K个一组对链表进行逆序
public class ReverseNodePerK {
public Node reverseNodeFromAToB(Node a, Node b) {
Node pre = null;
Node cur = a;
Node next = a;
while (cur != b) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = cur.next;
}
return pre;
}
public Node reverseNodePerK(Node head, int k) {
if (head == null) {
return head;
}
Node a = head;
Node b = head;
for (int i = 0; i < k; i++) {
if (b == null) {
return head;
}
b = b.next;
}
Node newHead = reverseNodeFromAToB(a, b);
a.next = reverseNodePerK(b, k);
return newHead;
}
}