一、单链表的相交问题
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
//得到入环节点
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
if (loop1 == null && loop2 == null) {
//1、无环链表的相交问题
return noLoop(head1, head2);
}
if (loop1 != null && loop2 != null) {
//2、有环链表的相交问题
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
/**
* 找到入环节点
* @param head
* @return
*/
public static Node getLoopNode(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.next == null || fast.next.next == null) {
return null;
}
fast = fast.next.next;
slow = slow.next;
}
//快慢指针到相同节点的时候,快指针回到开头
fast = head;
//快慢指针此时每次都走一步,走到同一节点跳出循环,该节点到入环节点
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
/**
* 无环链表相交问题
* @param head1
* @param head2
* @return
*/
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
//找到链表head1的结尾
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
// 找到链表head2的结尾
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
// 尾节点不等,没有交点
if (cur1 != cur2) {
return null;
}
// 如果n>0 head1长 cur1指向head1,n<0 则head2长 cur1指向head2(cur1始终指向较长链表的头)
cur1 = n > 0 ? head1 : head2;
// 如果cur1指向head1,则cur2指向head2
cur2 = cur1 == head1 ? head2 : head1;
// 取绝对值
n = Math.abs(n);
// 较长的链表先遍历n个节点
while (n != 0) {
n--;
cur1 = cur1.next;
}
//一起遍历,找到相交的节点
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
/**
* 有环链表相交问题
* @param head1
* @param loop1
* @param head2
* @param loop2
* @return
*/
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1;
Node cur2;
//和无环求交点类似(②)
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {
// 有环时的其他两种情况(① ③)
cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}
分析:
二、链表回文结构
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
// need n extra space
public static boolean isPalindrome1(Node head) {
Stack<Node> stack = new Stack<>();
Node cur = head;
// 原链表压入栈中
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
// 遍历链表,同时出栈进行比较
while (head != null) {
if (head.value != stack.pop().value) {
return false;
}
head = head.next;
}
return true;
}
// need n/2 extra space 后半段入栈
public static boolean isPalindrome2(Node head) {
if (head == null || head.next == null) {
return true;
}
Node right = head.next;
Node cur = head;
while (cur.next != null && cur.next.next != null) {
right = right.next;
cur = cur.next.next;
}
Stack<Node> stack = new Stack<>();
while (right != null) {
stack.push(right);
right = right.next;
}
while (!stack.isEmpty()) {
if (head.value != stack.pop().value) {
return false;
}
head = head.next;
}
return true;
}
// need O(1) extra space 快慢指针的使用
public static boolean isPalindrome3(Node head) {
if (head == null || head.next == null) {
return true;
}
Node slow = head;//慢指针
Node fast = head;//快指针
while (fast.next != null && fast.next.next != null) { // find mid node
slow = slow.next; // slow -> mid
fast = fast.next.next; // fast -> end
}
fast = slow.next; // fast -> right part first node
slow.next = null; // mid.next -> null
Node n3;
while (fast != null) { // right part convert
n3 = fast.next; // n3 -> save next node
fast.next = slow; // next of right node convert
slow = fast; // slow move
fast = n3; // fast move
}
n3 = slow; // n3 -> save last node
fast = head;// fast -> left first node
boolean res = true;
while (slow != null && fast != null) { // check palindrome
if (slow.value != fast.value) {
res = false;
break;
}
slow = slow.next; // left to mid
fast = fast.next; // right to mid
}
slow = n3.next;
n3.next = null;
while (slow != null) { // recover list
fast = slow.next;
slow.next = n3;
n3 = slow;
slow = fast;
}
return res;
}
public static void printLinkedList(Node node) {
System.out.print("Linked List: ");
while (node != null) {
System.out.print(node.value + " ");
node = node.next;
}
System.out.println();
}