- 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1] 输出:true
示例 2:
输入:head = [1,2] 输出:false
提示:
链表中节点数目在范围[1, 105] 内 0 <= Node.val <= 9
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/palindrome-linked-list
解法描述
- 遍历链表,依次将每个元素放入栈中,然后重新从头结点遍历,与栈中弹出元素比对是否相等,完全相等则为回文结构;
- 在方法1基础上进行优化,栈中不必保存所有元素,只需定位到链表中点,然后将后续元素放入栈中,再从头结点(与栈中弹出元素)开始比对;
- 不使用栈结构来实现:首先还是定位到链表的中点或上中间(偶数个节点情况下定位中间两个节点的上一个)结点,然后将中间结点后面的链表元素改变指针方向,中点或上中间结点的元素next指向null,最后,头结点指针与尾结点指针同时向中间遍历,比较各个元素是否相等。
最最后,不要忘记改变会原链表的指向。。
编码实现
方法1:
public boolean isPalindrome(ListNode head) {
Stack<ListNode> stack = new Stack<>();
ListNode cur = head;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
ListNode pop;
while (!stack.isEmpty()) {
pop = stack.pop();
if (pop.val != head.val) {
return false;
}
head = head.next;
}
return true;
}
方法2
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
ListNode midOrDown = head.next;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
midOrDown = midOrDown.next;
fast = fast.next.next;
}
Stack<ListNode> stack = new Stack<>();
ListNode cur = midOrDown;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
while (!stack.isEmpty()) {
ListNode pop = stack.pop();
if (pop.val != head.val) {
return false;
}
head = head.next;
}
return true;
}
方法3
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
ListNode midOrUp = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
midOrUp = midOrUp.next;
fast = fast.next.next;
}
ListNode cur = midOrUp.next;
midOrUp.next = null;
ListNode pre = midOrUp;
ListNode next;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
ListNode last = pre;
cur = pre;
ListNode left = head;
boolean res = true;
while (left != null && cur != null) {
if (left.val != cur.val) {
res = false;
break;
}
left = left.next;
cur = cur.next;
}
pre = null;
cur = last;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return res;
}
复杂度分析
三种实现方法,时间复杂度上都是O(N),空间复杂度上有所不同:
- 方法一将所有元素放入栈结构中,空间复杂度为O(N);
- 方法二在方法一基础上进行了优化,空间复杂度为O(N/2)
- 方法三则舍弃了栈结构,直接通过改变链表连接方向实现,空间复杂度为O(1),但要注意,方法三结束之前,需要改变回原来的链表连接方向!
实际使用时,我可能更倾向于使用方法二(在元素不多的情况下),毕竟方法三实现起来较为复杂,同时还要改变原来的机构,虽然最后会恢复原状,但需要注意很多细节。你更喜欢哪种方案呢?
欢迎关注我的公众号【CoolWrite】,了解更多内容:
|