快慢指针
public class LinkedList01 {
public static Node find01(Node head) {
if (head == null || head.next == null) {
return head;
}
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public static Node find02(Node head) {
if (head == null || head.next == null) {
return head;
}
Node slow = head.next;
Node fast = head.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public static Node find03(Node head) {
if (head == null || head.next == null) {
return head;
}
Node slow = head;
Node fast = head.next.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public static Node find04(Node head) {
if (head == null || head.next == null) {
return head;
}
Node slow = head;
Node fast = head.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private static class Node {
private Node next;
private int value;
}
}
四个类似的问题: 1、输入链表头部,奇数长度返回中点,偶数长度返回上中点 2、输入链表头部,奇数长度返回中点,偶数长度返回下中点 3、输入链表头部,奇数长度返回中点前一个,偶数长度返回上中点前一个 4、输入链表头部,奇数长度返回中点前一个,偶数长度返回下中点前一个
处理逻辑都一样,都是设置一个快指针和一个慢指针,快指针每次遍历两个结点,慢指针每次遍历一个结点,当快指针无法往后遍历时,返回慢指针指向的节点。 唯一不同的就是慢指针和快指针的初始指向。
输入一个链表头结点,判断链表是否是回文结构
public class LinkedList02 {
public static boolean isReverse01(Node head) {
if (head == null && head.next == null) return true;
Stack<Node> stack = new Stack<>();
Node help = head;
while (help != null) stack.push(help);
boolean res = true;
help = head;
while (!stack.isEmpty()) {
res &= stack.pop().value == help.value;
help = help.next;
}
return res;
}
public static boolean isReverse02(Node head) {
if (head == null && head.next == null) return true;
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
Stack<Node> stack = new Stack<>();
Node n2 = slow.next;
boolean res = true;
while (n2 != null) {
stack.push(n2);
n2 = n2.next;
}
n2 = head;
while (!stack.isEmpty()) {
res &= stack.pop().value == n2.value;
n2 = n2.next;
}
return res;
}
public static boolean isReverse03(Node head) {
if (head == null && head.next == null) return true;
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
Node n1 = slow;
Node n2 = n1.next;
n1.next = null;
Node n3 = null;
while (n2 != null) {
n3 = n2.next;
n2.next = n1;
n1 = n2;
n2 = n3;
}
n3 = n1;
n2 = head;
boolean res = true;
while (n1 != null && n2 != null) {
res &= n1.value == n2.value;
n1 = n1.next;
n2 = n2.next;
}
n1 = n3.next;
n3.next = null;
while (n1 != null) {
n2 = n1.next;
n1.next = n3;
n3 = n1;
n1 = n2;
}
return res;
}
private static class Node {
private Node next;
private int value;
}
}
三种方法: 1、把链表结点压入栈中,此时栈中结点的顺序与链表相反,一个个弹出与链表结点比较即可 2、通过快慢指针,然慢指针指向链表中间节点,然后只把后半部分节点压入栈中,与列表节点进行比较,节省一半空间 3、通过快慢指针,然慢指针指向链表中间节点,然后把后把部分的节点的next指针反转,再用两个指针,一头一尾,遍历进行比较,比较完毕后还原后半部分节点的next指针
将单向链表按某值划分为左边小,中间等于,右边大于的形式
public class LinkedList03 {
public static Node partition01(Node head, int pivot) {
if (head == null || head.next == null) return head;
Node help = head;
int size = 0;
while (help != null) {
size++;
head = help.next;
}
Node[] arr = new Node[size];
help = help;
int index = 0;
while (help != null) {
arr[index++] = help;
help = help.next;
}
int i1 = -1;
int i2 = 0;
int i3 = arr.length;
while (i2 != i3) {
Node curr = arr[i2];
if (curr.value < pivot) {
swap(arr, ++i1, i2++);
} else if (curr.value > pivot) {
swap(arr, i2, --i3);
} else {
i2++;
}
}
Node prev = arr[0];
for (int i = 1; i < arr.length; i++) {
prev.next = arr[i];
prev = arr[i];
}
return arr[0];
}
public static Node partition02(Node head, int pivot) {
if (head == null || head.next == null) return head;
Node smallHead = null;
Node smallTail = null;
Node equalsHead = null;
Node equalsTail = null;
Node bigHead = null;
Node bigTail = null;
Node next;
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (smallHead == null) {
smallHead = head;
smallTail = head;
} else {
smallTail.next = head;
smallTail = head;
}
} else if (head.value == pivot) {
if (equalsHead == null) {
equalsHead = head;
equalsTail = head;
} else {
equalsTail.next = head;
equalsTail = head;
}
} else {
if (bigHead == null) {
bigHead = head;
bigTail = head;
} else {
bigTail.next = head;
bigTail = head;
}
}
head = next;
}
if (smallHead != null) {
smallTail.next = equalsHead;
equalsTail = equalsHead == null ? smallTail : equalsTail;
}
if (equalsHead != null) {
equalsTail = bigHead;
}
return smallHead != null ? smallHead : (equalsHead != null ? equalsHead : bigHead);
}
private static class Node {
private int value;
private Node next;
}
private static void swap(Node[] arr, int i, int j) {
Node temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
链表结点带rand指针克隆问题
public class LinkedList04 {
public static Node clone01(Node head) {
if (head == null) return null;
Map<Node, Node> map = new HashMap<>();
Node help = head;
while (help != null) {
Node copy = new Node();
copy.value = help.value;
map.put(help, copy);
help = help.next;
}
help = head;
while (help != null) {
Node copy = map.get(help);
if (help.next != null) copy.next = map.get(help.next);
if (help.rand != null) copy.rand = map.get(help.rand);
help = help.next;
}
return map.get(head);
}
public static Node clone02(Node head) {
Node help = head;
while (help != null) {
Node next = help.next;
Node copy = new Node();
copy.value = help.value;
help.next = copy;
copy.next = next;
help = next;
}
help = head;
while (help != null) {
Node next = help.next.next;
Node copy = help.next;
if (help.rand != null) copy.rand = help.rand.next;
help = next;
}
Node res = help.next;
help = head;
while (help != null) {
Node next = help.next.next;
Node copy = help.next;
help.next = next;
if (next != null) copy.next = next.next;
help = next;
}
return res;
}
private static class Node{
private int value;
private Node next;
private Node rand;
}
}
给定一个链表,如果有环则返回环中的第一个节点,没有则返回null
public class LinkedList05 {
public static Node find(Node head) {
if (head == null || head.next == null || head.next.next == null) return null;
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast == null || fast.next == null) return null;
slow = slow.next;
fast = fast.next.next;
}
fast = head;
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
private static class Node {
private int value;
private Node next;
}
}
给定两个无环链表,返回两个链表相交的第一个节点,没有则返回null
public class LinkedList06 {
public static Node findIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) return null;
int len = 0;
Node curr1 = head1;
while (curr1.next != null) {
len++;
curr1 = curr1.next;
}
Node curr2 = head2;
while (curr2.next != null) {
len--;
curr2 = curr2.next;
}
if (curr1 != curr2) return null;
curr1 = len < 0 ? head2 : head1;
curr2 = curr1 == head1 ? head2 : head1;
len = Math.abs(len);
while (len != 0) {
len--;
curr1 = curr1.next;
}
while (curr1 != curr2) {
curr1 = curr1.next;
curr2 = curr2.next;
}
return curr1;
}
private static class Node {
private int value;
private Node next;
}
}
两个有环链表,给定链表头结点和环中第一个节点,找出两个链表相交的结点,没有相交则返回null
public class LinkedList07 {
public static Node findLoopIntersect(Node head1, Node loop1, Node head2, Node loop2) {
Node curr1 = null;
Node curr2 = null;
if (loop1 == loop2) {
curr1 = head1;
curr2 = head2;
int len = 0;
while (curr1 != loop1) {
len++;
curr1 = curr1.next;
}
while (curr2 != loop2) {
len--;
curr2 = curr2.next;
}
curr1 = len < 0 ? head2 : head1;
curr2 = curr1 == head1 ? head2 : head1;
len = Math.abs(len);
while (len > 0) {
len--;
curr1 = curr1.next;
}
while (curr1 != curr2) {
curr1 = curr1.next;
curr2 = curr2.next;
}
return curr1;
} else {
curr1 = loop1.next;
while (curr1 != loop1) {
if (curr1 == loop2) return loop1;
curr1 = curr1.next;
}
return null;
}
}
private static class Node {
private int value;
private Node next;
}
}
给定两个链表,有可能有环,也有可能无环,返回两个链表的相交结点,没有相交则返回null
public class LinkedList08 {
public static Node find(Node head1, Node head2) {
if (head1 == null || head2 == null) return null;
Node loop1 = findLoopNode(head1);
Node loop2 = findLoopNode(head2);
if (loop1 == null && loop2 == null) {
return findIntersectNodeNoLoop(head1, head2);
}
if (loop1 != null && loop2 != null) {
return findLoopIntersect(head1, loop1, head2, loop2);
}
return null;
}
public static Node findLoopIntersect(Node head1, Node loop1, Node head2, Node loop2) {
Node curr1 = null;
Node curr2 = null;
if (loop1 == loop2) {
curr1 = head1;
curr2 = head2;
int len = 0;
while (curr1 != loop1) {
len++;
curr1 = curr1.next;
}
while (curr2 != loop2) {
len--;
curr2 = curr2.next;
}
curr1 = len < 0 ? head2 : head1;
curr2 = curr1 == head1 ? head2 : head1;
len = Math.abs(len);
while (len > 0) {
len--;
curr1 = curr1.next;
}
while (curr1 != curr2) {
curr1 = curr1.next;
curr2 = curr2.next;
}
return curr1;
} else {
curr1 = loop1.next;
while (curr1 != loop1) {
if (curr1 == loop2) return loop1;
curr1 = curr1.next;
}
return null;
}
}
public static Node findIntersectNodeNoLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) return null;
int len = 0;
Node curr1 = head1;
while (curr1.next != null) {
len++;
curr1 = curr1.next;
}
Node curr2 = head2;
while (curr2.next != null) {
len--;
curr2 = curr2.next;
}
if (curr1 != curr2) return null;
curr1 = len < 0 ? head2 : head1;
curr2 = curr1 == head1 ? head2 : head1;
len = Math.abs(len);
while (len != 0) {
len--;
curr1 = curr1.next;
}
while (curr1 != curr2) {
curr1 = curr1.next;
curr2 = curr2.next;
}
return curr1;
}
public static Node findLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) return null;
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast == null || fast.next == null) return null;
slow = slow.next;
fast = fast.next.next;
}
fast = head;
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
private static class Node {
private int value;
private Node next;
}
}
|