中判断回文的代码_LeetCode(234. 回文链表) 题解

234. 回文链表

题目

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

何为回文?

维基百科是这样介绍的:

回文,亦称回环,是正读反读都能读通的句子,亦有将文字排列成圆圈者,是一种修辞方式和文字游戏。

北宋文学家苏轼创作的一首名为《菩萨蛮·回文夏闺怨》的词,就用到了回文的修辞方式。

菩萨蛮·回文夏闺怨 

苏轼

柳庭风静人眠昼。昼眠人静风庭柳。

香汗薄衫凉。凉衫薄汗香。

手红冰碗藕。藕碗冰红手。

郎笑藕丝长。长丝藕笑郎。

这首《夏闺怨》大意呢是上片写闺人昼寝的情景,下片写醒后的怨思。各位看官感受一下回文的妙处,至于诗歌赏析暂且按住不表,有兴趣的看官可以自行查阅解析。

回顾

之前做过判断回文的相似题,还记得怎么解吗:LeetCode(125. 验证回文串) 题解。

当时提到了两种解法,一种原地翻转,一种双指针。同样也适用于解这道题。区别在于125题是字符串,本题是单链表。基于单链表的线性的链式存储结构的特点,这里就需要一点点小技巧进行相应的转化与处理。

思路1-原地翻转

对于字符串的原地翻转,可以通过Java的API实现,也可以使用双指针的办法,手写一个原地翻转的函数。单链表,不能访问前驱节点,可以利用栈后入先出的特性,遍历一遍单链表将链表中的节点入栈,然后栈顶元素依次出栈和链表遍历比较,判断翻转后的链表是否与原链表相等。

上代码

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { val = x; } * } */class Solution {    public boolean isPalindrome(ListNode head) {        if(head == null || head.next == null) return true;        Stack stack = new Stack<>();        ListNode node = head;        while(node != null){            stack.push(node);            node = node.next;        }        while(head != null && !stack.isEmpty()){            ListNode tmpNode = stack.pop();            if(head.val != tmpNode.val) return false;            head = head.next;        }        return true;    }}

思路2-双指针法之快慢指针

对于字符串的双指针法,初始时,左右指针分别指向字符串的两侧,左指针左移,右指针右移,每次移动一步,并判断这两个指针指向的字符是否相同。对于链表,右指针右移的部分应该怎么处理呢?可以通过快慢指针法找到链表的中间节点,将后半部分翻转,然后两个链表依次遍历进行比较。后半部分翻转后的遍历相当于右指针右移部分。

上代码

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { val = x; } * } */class Solution {    public boolean isPalindrome(ListNode head) {        if(head == null || head.next == null) return true;        //快慢指针        ListNode fastNode = head;        ListNode slowNode = head;        //快指针走两步 慢指针走一步 找到链表中点        while(fastNode.next != null && fastNode.next.next != null){            slowNode = slowNode.next;            fastNode = fastNode.next.next;        }        //将后半部分反转        ListNode newHead = null;        ListNode curr = slowNode.next;        while(curr != null){            ListNode tmpNode = curr.next;            curr.next = newHead;            newHead = curr;            curr = tmpNode;        }        //两部分进行比较判断        while(head != null && newHead != null){            if(head.val != newHead.val) return false;            head = head.next;            newHead = newHead.next;        }        return true;    }}

分析

这种解法的优点在于没有开辟额外的内存空间,算法的空间复杂度为O(1)。

思路3-双指针法

双指针法需要左右指针进行遍历判断,对于链表无法实现,可将链表进行转换,将其复制到列表或数组中,使之可以使用左右指针相向而行的方法进行判断。

上代码

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { val = x; } * } */class Solution {    public boolean isPalindrome(ListNode head) {        if(head == null || head.next == null) return true;        List list = new ArrayList<>();        while(head != null){            list.add(head);            head = head.next;        }        int left = 0;        int right = list.size() - 1;        while(left < right){            if(list.get(left).val != list.get(right).val) return false;            left ++;            right --;        }        return true;    }}

思路4-递归

还有一种递归的解法,参照 思路2-原地翻转的思想,链表可以使用递归的方法进行逆序遍历,那么将逆序遍历的结果与原链表进行比较就可以完成判断。参考官方题解链接[1]。

上代码

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { val = x; } * } */class Solution {    ListNode front = null;    public boolean isPalindrome(ListNode head) {        if(head == null || head.next == null) return true;        front = head;        return recursion(head);    }    public boolean recursion(ListNode head){        if(head == null) return true;        boolean res = recursion(head.next);        if(head.val != front.val) return false;        front = front.next;         return res;    }}

References

[1] https://leetcode-cn.com/problems/happy-number/solution/kuai-le-shu-by-leetcode-solution/

70675b712e93c86090460c9fbf664fd7.png

程序员画工师|欢迎关注

持续分享Java相关编程技术、数据结构与算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值