链表的回文结构-----java

本文探讨了如何利用O(n)时间复杂度和O(1)空间复杂度的算法判断链表是否为回文结构,包括方法一:通过计数找中间节点和方法二:使用快慢指针。同时介绍了反转链表的方法及其在解决回文问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

题目描述

反转链表

 找链表的中间结点

方法一 :求出结点个数,找中间结点

方法二:使用快慢指针找到中间结点


题目描述

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。测试样例: 

1->2->2->1

返回:true

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/

题目链接:链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 

 思路1:直接反转整个链表,反转后的链表与反转前的链表相同

关键的问题是要怎么样反转链表?

反转链表

206. 反转链表 - 力扣(LeetCode)

对于单链表,反转时需要三个指针分别指向前中后三个结点,中间结点的next指向前结点完成中间结点的反转,后指针指向中间结点的原后继,防止链表丢失 

代码如下:

public ListNode reverseList(ListNode head) {
        //遍历,修改所有结点的next
        ListNode cur=head;   
        ListNode pev=null;    //指向cur的上一个结点
        while(cur!=null){
            ListNode next=cur.next;  //提前保存下一个结点
            cur.next=prev;
            pev=cur;
            cur=next;
        }
        return pev;
    }

图解如下:

第一次循环:

 会反转链表之后,这道题就变得很简单了,剩下的就是比较val的值是否相同

原代码:

public class PalindromeList {

    public ListNode reverseList(ListNode A) {
        //遍历,修改所有结点的next
        ListNode cur = A;
        ListNode prev = null;  //指向cur的上一个结点
        while (cur != null) {
            ListNode next = cur.next; //提前保存下一个结点
            cur.next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }

    public boolean chkPalindrome(ListNode A) {
        // write code here
        ListNode first = A;
        ListNode last = reverseList(A);   //反转后的链表
        while (first != null) {
            if (first.val != last.val) {
                return false;
            }
            first = first.next;
            last = last.next;
        }
        return true;
    }
}

思路二:其实可以看出,没有必要反转整个链表

1、可以尝试找到链表的中间结点

2、反转其中一半的链表,得到两条链表

3、依次比较两个链表中的每个结点,如果全部相等true,存在不相等false。所以现在最主要的问题是如何找到中间结点。

 找链表的中间结点

方法一 :求出结点个数,找中间结点

如果可以知道链表的结点个数n,无论结点是奇数个还是偶数个,向后跳 n/2步即可找到中间结点,具体解释如下图所示:

由图可知,在比较到第三次的时候,总有一个指针会为空,此时循环应该退出,因此,循环的条件可以设为cur!=null&&ans!=null

 原码如下:

    //计算结点个数
    public int countnum(ListNode A) {
        ListNode cur = A;
        int count = 0;
        //遍历
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }
    //找中间的结点
    public ListNode midNode(ListNode A) {
        ListNode cur = A;
        int count = countnum(A) / 2;
        for (int i = 0; i < count; i++) {
            cur = cur.next;
        }
        return cur;
    }

    //翻转后半段
    public ListNode reverseList(ListNode A) {
        ListNode pev = null; //记录前一个结点
        ListNode cur = A; //记录当前结点
        while (cur != null) {
            ListNode next = cur.next; //保存cur的后一个结点
            cur.next = pev;
            //改变链表方向
            pev = cur;
            cur = next;
        }
        return pev;
    }

    public boolean chkPalindrome(ListNode A) {
        ListNode midnode = midNode(A);
        //记录反转后的链表
        ListNode ans = reverseList(midnode);  //将中间结点传入
        ListNode cur = A;
        while (ans != null && cur != null) {
            if (ans.val != cur.val) {
                return false;
            } else {
                ans = ans.next;
                cur = cur.next;
            }
        }
        return true;
    }

方法二:使用快慢指针找到中间结点

使用快慢指针,两指针一开始都指向head,那么fast一次2步,slow一次1步,那么fast走到最后的节点,slow刚好指向中间

 

 

//找中间的结点
public ListNode midNode(ListNode A) {
    ListNode fast = A;
    ListNode slow = A;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}

 反转链表和比较跟前面是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值