反转链表类的题型整体来说有两种解法,一种就是利用java特有的泛型,用栈的数据结构进行反转;另一种则是用多指针原地逐个反转。两种解法各有优缺,第一种胜在逻辑简单,但是空间复杂度较高;第二种逻辑上较为复杂,但是空间复杂度低
一、反转整个链表
泛型+栈的解法:
private static Node reverseNodeByStack(Node root) {
Stack<Node> stack = new Stack<>();
while (root != null) {
stack.add(root);
root = root.next;
}
Node root1 = stack.pop();
Node temp = root1;
while (!stack.isEmpty()) {
temp.next = stack.pop();
temp = temp.next;
}
temp.next = null;
return root1;
}
三指针原地反转:
private static Node reverseNodeByIndex(Node root) {
// 就地反转,需要三个指针
Node pre = null;
Node middle = root;
Node next = middle.next;
while (next != null) {
middle.next = pre;
pre = middle;
middle = next;
next = next.next;
}
middle.next = pre;
return middle;
}
二、反转部分链表
泛型+栈的解法:
private static Node reverseNodeByStack(Node root, int from, int to) {
int index = 0;
Node start = root;
for (int i = 1;i < from - 1;i++) {
start = start.next;
}
Stack<Node> stack = new Stack<>();
Node temp1 = start.next;
for (int i = 0;i <= to - from;i++) {
stack.add(temp1);
temp1 = temp1.next;
}
Node end = temp1;
while (!stack.isEmpty()) {
start.next = stack.pop();
start = start.next;
}
start.next = end;
return root;
}
三、判断链表是否回文中的反转链表应用
判断链表是否回文本质上和反转链表的原理相同
可以使用泛型+栈的解法,将一半的链表入栈,然后与后半部分对比
也可以先使用原地反转将后半部分反转,然后前后指针同时遍历判断是否回文,不过要记得无论是否回文,判断完后要先将链表反转回来,再返回值
泛型+栈的解法:
private static boolean simplePalindrome(Node head) {
// 简单的方式就是用栈即可
// 先判断一下链表长度
int length = 0;
Node temp1 = head;
while (temp1 != null) {
temp1 = temp1.next;
length++;
}
Stack<Node> stack = new Stack<>();
Node temp2 = head;
for (int i = 0;i < length / 2;i++) {
stack.add(temp2);
temp2 = temp2.next;
}
if (length % 2 == 1) {
temp2 = temp2.next;
}
for (int i = 0;i < length / 2;i++) {
if (temp2.value != stack.peek().value) {
return false;
} else {
stack.pop();
temp2 = temp2.next;
}
}
return true;
}
反转后半链表的解法:
private static boolean fastPalindrome(Node head) {
// 反转后半链表要记得,无论是否回文,都要先将链表反转回来再返回
if (head == null || head.next == null) {
return true;
}
// 空间复杂度O(1)的做法是将后半段链表反转,并前后同时遍历
// 第一步应该是判断链表长度,同时获得反转链表的起点,可以使用双指针法来做
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 从slow开始反转
Node pre = null;
Node middle = slow;
Node next = middle.next;
while (middle.next != null) {
middle.next = pre;
pre = middle;
middle = next;
next = next.next;
}
middle.next = pre;
// 现在得到了Middle和head
Node start = head;
Node end = middle;
boolean ans = true;
while (start != null) {
if (start.value != end.value) {
ans = false;
break;
} else {
start = start.next;
end = end.next;
}
}
// 将反转的后半部分再反转回来
pre = null;
next = middle.next;
while (next != null) {
middle.next = pre;
pre = middle;
middle = next;
next = next.next;
}
middle.next = pre;
return ans;
}