【数据结构和算法】判断回文链表,图文详解

判断一个链表是否为回文结构

http://www.nowcoder.com/questionTerminal/3fed228444e740c8be66232ce8b87c2f

1,反转后半部分链表

这题是让判断链表是否是回文链表,所谓的回文链表就是以链表中间为中心点两边对称。我们常见的有判断一个字符串是否是回文字符串,这个比较简单,可以使用两个指针,一个最左边一个最右边,两个指针同时往中间靠,判断所指的字符是否相等


但这题判断的是链表,因为这里是单向链表,只能从前往后访问,不能从后往前访问,所以使用判断字符串的那种方式是行不通的。但我们可以通过找到链表的中间节点然后把链表后半部分反转(关于链表的反转可以看下432,剑指 Offer-反转链表的3种方式),最后再用后半部分反转的链表和前半部分一个个比较即可。这里以示例2为例画个图看一下。 image.png

image.png

最后再来看下代码

public boolean isPail(ListNode head) {
    ListNode fast = head, slow = head;
    //通过快慢指针找到中点
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    //如果fast不为空,说明链表的长度是奇数个
    if (fast != null) {
        slow = slow.next;
    }
    //反转后半部分链表
    slow = reverse(slow);

    fast = head;
    while (slow != null) {
        //然后比较,判断节点值是否相等
        if (fast.val != slow.val)
            return false;
        fast = fast.next;
        slow = slow.next;
    }
    return true;
}

//反转链表
public ListNode reverse(ListNode head) {
    ListNode prev = null;
    while (head != null) {
        ListNode next = head.next;
        head.next = prev;
        prev = head;
        head = next;
    }
    return prev;
}

2,使用栈解决

我们知道栈是先进后出的一种数据结构,这里还可以使用栈先把链表的节点全部存放到栈中,然后再一个个出栈,这样就相当于链表从后往前访问了,通过这种方式也能解决,看下代码

public boolean isPail(ListNode head) {
    ListNode temp = head;
    Stack<integer> stack = new Stack();
    //把链表节点的值存放到栈中
    while (temp != null) {
        stack.push(temp.val);
        temp = temp.next;
    }

    //然后再出栈
    while (head != null) {
        if (head.val != stack.pop()) {
            return false;
        }
        head = head.next;
    }
    return true;
}

这里相当于链表从前往后全部都比较了一遍,其实我们只需要拿链表的后半部分和前半部分比较即可,没必要全部比较,所以这里可以优化一下

public boolean isPail(ListNode head) {
    if (head == null)
        return true;
    ListNode temp = head;
    Stack<integer> stack = new Stack();
    //链表的长度
    int len = 0;
    //把链表节点的值存放到栈中
    while (temp != null) {
        stack.push(temp.val);
        temp = temp.next;
        len++;
    }
    //len长度除以2
    len &gt;&gt;= 1;
    //然后再出栈
    while (len-- &gt;= 0) {
        if (head.val != stack.pop())
            return false;
        head = head.next;
    }
    return true;
}

3,递归方式

这种实现方式我在其他平台上运行是可以通过的,但在牛客网是通不过的,因为牛客网的数据太大了,所以这里的递归很容易导致堆栈溢出异常。可以作为一种实现思路了解一下

我们知道,如果对链表逆序打印可以这样写

private void printListNode(ListNode head) {
    if (head == null)
        return;
    printListNode(head.next);
    System.out.println(head.val);
}

也就是说最先打印的是链表的尾结点,他是从后往前打印的,如果以后谁再给你说单向链表不能从后往前遍历,你就拿这段代码怼他,哈哈。看到这里是不是有灵感了,我们来对上面的对面进行改造一下

ListNode temp;

public boolean isPail(ListNode head) {
    temp = head;
    return check(head);
}

private boolean check(ListNode head) {
    if (head == null)
        return true;
    boolean res = check(head.next) &amp;&amp; (temp.val == head.val);
    temp = temp.next;
    return res;
}

如果觉得有用就给个赞吧,还可以关注我的《牛客博客》查看更多的详细题解

数据结构和算法 文章被收录于专栏

专注于算法题的讲解,包含常见数据结构,排序,查找,动态规划,回溯算法,贪心算法,双指针,BFS和DFS等等。

全部评论
第一个方法可以在快慢指针遍历时候,顺便把前半部分节点反转。
1 回复 分享
发布于 2021-10-10 02:03
第二个方法的优化方法中,感觉在判断len--的时候不用加等于号,两者都正确,但是对于奇数链表来说,可以减少一次判断。
点赞 回复 分享
发布于 2024-07-19 17:04 山东

相关推荐

来个厂收我吧:首先,市场侧求职我不是很懂。 但是,如果hr把这份简历给我,我会觉得求职人不适合做产品经理。 问题点: 1,简历的字体格式不统一,排版不尽如人意 2,重点不突出,建议参考star法则写个人经历 3,印尼官方货币名称为印度尼西亚卢比(IDR),且GMV690000印尼盾换算为305人民币,总成交额不高。 4,右上角的意向职位在发给其他公司时记得删除。 5,你所有的经历都是新媒体运营,但是你要投市场营销岗位,jd和简历不匹配,建议用AI+提示词,参照多个jd改一下经历内容。 修改建议: 1,统一字体(中文:思源黑体或微软雅黑,英文数字:time new romans),在word中通过表格进行排版(b站学) 2,校招个人经历权重:实习经历=创业经历(大创另算)>项目经历>实训经历>校园经历 3,请将项目经历时间顺序改为倒序,最新的放最上方。 4,求职方向不同,简历文字描述侧重点也需要不同。
点赞 评论 收藏
分享
06-08 22:25
门头沟学院 Java
从零开始的转码生活:这hr不会打开手机不分青红皂白给所有人群发这句话,过一会再给所有人再发一遍,这肯定会有重复的,不管,再过一会再发一遍
点赞 评论 收藏
分享
评论
50
6
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务