LeetCode日常之链表:234 回文链表 | 七日打卡

821 阅读3分钟

题目信息

题目地址:leetcode-cn.com/problems/pa…

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解法一:数组

比较容易想到的就是使用另一个容器存节点,再比较值,这里存到数组进行首尾比较。那就和字符串(数组)回文一样了

public boolean isPalindrome(ListNode head) {
    List<Integer> vals = new ArrayList();
    // 将链表的值复制到数组中
    ListNode cur = head;
    while (cur != null) {
        vals.add(cur.val);
        cur = cur.next;
    }
    // 使用双指针判断是否回文
    int length = vals.size();
    for(int i = 0, j = length -1; i < length/2; i++,j--){
        int val1 = vals.get(i);
        int val2 = vals.get(j);
        if( val1 != val2 ) return false;
    }
    return true;
}

解法二:快慢指针

我们仍然是要使空间复杂度为O(1) 的,所以还是要回到纯链表的操作不用别的数据结构。结合之前的练习可以采用原地链表反转的算法之后再和原链表挨个比较,整个反转再比较的话是行不通的因为我们要用原地的不存储另外的链表,并且本来只用比较一半,所以我们这里要去找到链表的中间,并把后一半反转再进行前一半比后一半即可。

问题其实就是我们怎么能找到链表的中间节点?

通过快慢指针,fast为slow两倍速度,最后fast为空时slow就停在后一半的开头(长度为偶数)如果是奇数呢?

定位之后进行反转,再进行双指针比较直到后一半走完

public boolean isPalindrome(ListNode head) {
    ListNode fast = head; 
    ListNode slow = head;
    //通过快慢指针找到中点
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    //如果fast不为空,说明链表的长度是奇数个
    if (fast != null) {
        slow = slow.next;
    }
    //反转后半部分链表
    slow = reverseList(slow);
    fast = head;
    while (slow != null) {
        //然后比较,判断节点值是否相等
        if (fast.val != slow.val) return false;
        fast = fast.next;
        slow = slow.next;
    }
    return true;
}
//反转链表
public ListNode reverseList(ListNode head) {
    ListNode cur = head;
    ListNode next = null;
    while( cur != null){
        //记住原链表的下一个
        ListNode temp = cur.next;
        //设下next
        cur.next = next;
        //更新next与cur
        next = cur;
        cur = temp;
    }
    return next;
}

总结

先是解法一也是和前面写的几题一样无脑解决的方式就是用另外的容器操作解除只能往下取的限制无论是数组也好还是栈也好都是用另外的容器直接进行我们想要的指针操作,接下来就是去挖掘链表的操作,只能next不能像数组一样任意使用索引的情况下我们怎么定位我们想要的地方,快慢指针的一个应用无论是在这题还有前面的删除倒数第几个节点,以及明天要完成的一题环形链表都有体现多思考。