回文链表

最近做算法题发现总是容易产生一种定势思维,或者说总是更倾向于先想到使用某些熟悉的数据结构或语法来解题,但往往从效果上来看时间复杂度和空间复杂度是大问题。

今天在力扣上看到了一道判断链表是否为回文链表的题目,如下所示:

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

示例 1:

输入: 1->2
输出: false

示例 2:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

最初想到的办法简单粗暴,将链表转字符串再翻转对比一下。然后试图想出一种不那么暴力的解法,也有可能是最近几天做了一些算法题的原因,灵光乍现想到了快慢指针,先找到中间节点,翻转后半段链表,再进行遍历对比... ...

讨厌翻转链表,看了一下参考题解发现其中有这种方案,也提到了这种方案在多线程环境下可能会出现问题,由于运算过程中会破坏链表,这个时候如果有其他线程需要访问链表,那就可能出问题。

第二种方案也果断放弃,由于短时间没有想出其他方案就参考了一下题解中的递归解法,初看有点迷,稍一思索明白了其中的含义,如果这里的单链表是一个数组的话,那么可以采用一种通俗易懂的双指针从数组两端开始遍历对比,但是,单链表不能从链表末端进行遍历,递归正是替代了末端指针的存在,果断决定自己按照理解到的思路写一遍。

首先,当节点不为null时,就直接进入下一个节点,直到节点为null,也就是递归到了末端节点的下一个节点,此时返回true。

在设计此处的时候又出现了一个误区,也算是定势思维,如果为null,应返回false。但实际上这个递归方法的返回值并不只代表节点是否为null,还有另一层含义是两节点是否相同,换句话说就是是否继续对比,还是直接返回结果。

所以,最终决定当节点为null时,返回true,算是便于后续的设计。

当判断下一次递归结果为true时,继续进行校验。

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    ListNode curr = null;
    
    public boolean isPalindrome(ListNode head) {
        curr = head;
        return check(head);
    }

    public boolean check(ListNode node) {
        if (node == null)
            return true;
        if (check(node.next)) {
            if (curr.val == node.val) {
                curr = curr.next;
                return true;
            }
        }
        return false;
    }
}

 

总的来讲代码不难,但在设计的时候仍旧觉得使用递归稍微有点绕,递归方法就像是一系列有关联的方法链,要注意下一次递归对上一次递归的影响,同时还要兼顾上一次递归在合适的位置调用下一次递归。

 

posted @ 2020-11-28 09:32  无心大魔王  阅读(165)  评论(0编辑  收藏  举报