[LeetCode]34. 回文链表

本文探讨了如何判断一个链表是否为回文结构,提供了三种高效算法:数学计算法、快慢指针法和栈对比法。通过实例解析,详细介绍了每种方法的实现步骤与原理。

34. 回文链表

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

示例 1:

输入: 1->2
输出: false

示例 2:

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

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

分析: 链表不能像数组一样操作,链表只能按照链表链接方向顺序操作。本题的关键是要使用计算法、快慢指针等方法找到链表中点,将链表翻转为前半部分+后半部分,由于链表只能顺序操作,所以关键是使用栈等方法将左半部分(或右半部分链表翻转),然后再比较前、后两半部分链表的值是否完全相同。

方法一:数学法计算链表中点+后半部翻转
/**
 * 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 p = head;
        ListNode q = head;
        ListNode left = null;
        int len = 0;
        while(p != null){
            p = p.next; 
            len++;
        }
        int min = len/2;
        while(min != 0){
            q = q.next;
            min--;
        }
        //根据链表长度确定后半部分链表起点
        if(len % 2 == 0){
            left = reverseListNode(q);
        } else{
            left = reverseListNode(q.next);
        }
        //比较链表前半部分和后半部分结点的值,判断是否满足回文规则
        p = head;
        while(p != null && left != null){
            if(p.val != left.val){
                return false;
            }
            p = p.next;
            left = left.next;
        }
        return true;
    }
    //翻转链表
    public ListNode reverseListNode(ListNode head){
        if(head == null || head.next == null){
            return head;
        }
        ListNode p = head.next;
        ListNode q = null;
        ListNode r = head;
        head.next = null;
        while(p != null){
            q = p.next;
            p.next = r;
            r = p;
            p = q;
        }
        return r;
    }
}
方法二:快慢双指针+后半部分翻转
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
// 如果链表长度 <=1,则直接返回 true
// 先找到链表的中点(快慢指针)
// 再以中点为起点,将后面链表翻转(迭代、遍历)
// 最后分别以头结点和中点为起点,向后遍历,比较值是否相等,如果出现不等,则不是回文链表
class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        // 找到链表的中点
        ListNode mid = findMid(head);
        // 翻转中点后的链表
        mid = reverseList(mid);
        // 比较两段链表
        while (mid != null) {
            if (head.val != mid.val) {
                return false;
            }
            head = head.next;
            mid = mid.next;
        }
        return true;
    }
    // 翻转链表(迭代、递归)
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }
    
    // 使用快慢指针找到链表的中间节点    
    private ListNode findMid(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
}
方法三:使用栈进行对比
  • 可以按链表所有元素入栈,栈中保存于原链表的逆序链表,依次比较新链表和原链表的值是否完全相同,如果是,原链表这是回文链表。但是这种方法比较次数可以优化
  • 优化:找到链表中点,将原链表前半部分或者后半部分结点入栈,再比较
class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack<ListNode> stack=new Stack<>();
        ListNode cur=head;
        while(cur!=null){
            stack.push(cur);
            cur=cur.next;
        }
        cur=head;
        while(cur!=null){
            if(cur.val != stack.pop().val){
                return false;
            }
            cur=cur.next;
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值