234. 回文链表
难度 简单
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
打开网页 拿到题目 难度简单 我超勇的!
二话不说
就想到了方法一:遍历整条链表,逐个将值添加到ArrayList数组
用双指针前后比较,不等则输出false。
时间复杂度O(n)
空间复杂度O(n)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> vals = new ArrayList<>();
ListNode currentNode = head;
while (currentNode != null) {
vals.add(currentNode.val);
currentNode = currentNode.next;
}
int front = 0;
int back = vals.size() - 1;
while (front < back) {
if (!vals.get(front).equals(vals.get(back))) {
return false;
}
front++;
back--;
}
return true;
}
}
然后又想到能不能稍微优化一下,毕竟过于简单了。
于是我就想到判断一个回文数(就像上面判断复制数组),我们能不能不另造空间直接在链表上比呢?
于是,就有了将链表反转的思路
反转全部是不可能的,因为那样判断还是要另造空间。细想一下一个回文链表我们只要判断它的前半段反转再和后半段是否一样就可以了,当然,链表长度为奇数的话不用判断中间的值。
举例 1->2->3->2->1 前半段 反转后 的图
此时我们只要遍历逐个判断pre.val和p.val
那么问题来了,我们怎么才能把指针指向中间的位置,并且将前半段反转呢?
于是,我就想到了 == 方式二:快慢指针==
也就是给定两个指针分别是fast和slow
slow一次走一个
fast一次走两个
即slow = slow.next
fast = fast.next.next
分析一下循环条件:
指针同颜色为同一步,fast走到底时slow刚好走到中间,并且此时是链长是奇数
那我们正好判断一下偶数链长情况:
fast到底时为空slow为链长中间偏右
于是判断条件可以是while(fast != null && fast.next != null)
接着就是反转链表了,可以注意到slow指针是一步一步往后走的,我们就可定义一个pres记录上一个slow,并定义一个pre记录pres的前一个。
最终代码如下:
class Solution {
public boolean isPalindrome(ListNode node) {
if (node==null||node.next==null) return true;
ListNode fast = node;
ListNode slow = node;
ListNode pres = null;
ListNode pre = null;
while (fast!=null&&fast.next!=null){
pres = slow;
slow=slow.next;
fast=fast.next.next;
pres.next = pre;
pre = pres;
}
if (fast!=null){
slow=slow.next;
}
while (pres!=null){
if (pres.val!=slow.val){
return false;
}
pres = pres.next;
slow=slow.next;
}
return true;
}
}
这样的处理使得我们没有用到额外的空间即空间复杂度优化到了O(1),而时间复杂度还是O(n).