给你一个单链表的头节点 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刷题【876】链表的中间结点,不过这边的双指针方法的话不方便往回查找节点。
这边分奇偶长度,偶数长度直接和后一位对比,奇数长度中间节点不需要对比,拿中间节点的前一位和后一位开始对比。
class Solution {
public boolean isPalindrome(ListNode head) {
if (head.next == null){
return true;
}
List<ListNode> list = new ArrayList<>();
while (head!=null){
list.add(head);
head = head.next;
}
int mid = list.size() >> 1;
int l,r;
if (list.size()%2==0){
l = mid;
r = mid+1;
}else{
l = mid;
r = mid+2;
}
while (l>0){
if (list.get(l-1).val != list.get(r-1).val){
return false;
}
l--;
r++;
}
return true;
}
}
而O(n) 时间复杂度和 O(1)的方法,一开始没想出来,直到看了别人的解法,重新再看到题面的说明,每个节点的值在0-9之间才豁然开朗。所以,题面中的每一个信息都至关重要。
class Solution {
public boolean isPalindrome(ListNode head) {
int num1 = 0, num2 = 0, x = 1;
while (head!=null){
num1 = num1 * 10 + head.val;
num2 = x * head.val + num2;
x *= 10;
head = head.next;
}
return num1 == num2;
}
}
逻辑就是这样,构建两个值,不同的位上代表对应的节点的值,这样构建出来的整数和反向的位构建出来的整数应该值是相等的,则说明是回文链表。
不过这里的另一个条件,链表长度为10的5次方的话,我也不确定会不会出现越界超出Integer.MAX_VALUE之后恰好和另一个值相等的情况。
另外一个解法,用栈,将链表的前半段压入栈。从中间节点开始,依次和栈顶节点对比,如果都相同,说明是回文。
而在用栈的方法1此之前,我也曾经想过,用两个指针,一个从中间节点往后遍历,一个用递归的方法从中间节点往前返回,这两个指针的值进行比较。但是题面中的链表长度为10的5次方使这种方法成为了不可能,这样的递归深度,必然会导致栈溢出。不过其本质思想和用栈来解决是相同的。
发表评论