2021-06-19 回文链表

本文探讨了LeetCode中的回文链表问题,介绍了两种解法:暴力遍历数组和利用双指针结合反转链表。第一种方法涉及数组操作,第二种则是巧妙地利用链表特性简化了空间复杂度。

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

leetcode每日一题之回文链表

题目链接:https://leetcode-cn.com/problems/palindrome-linked-list-lcci/submissions/

题目描述:

编写一个函数,检查输入的链表是否是回文的。

示例 1:

输入: 1->2
输出: false 

示例 2:

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

解法1:自己的解法

首先声明,本人的解法是通过了的。

思想:

  • 首先遍历链表记录链表中的元素个数
  • 然后开辟一个数组,空间大小就是链表中元素的个数
  • 遍历链表将链表中的值依次放入数组
  • 利用双指针判断数组中元素是否为回文元素

代码实现:

package com.tao.linklist;
import java.util.Arrays;
/**
 * @Classname IsPalindrome
 * @Description TODO
 * @Date 2021/6/18 17:02
 * @Author Anonymous
 */
@SuppressWarnings("all")
public class IsPalindrome {
    public static void main(String[] args) {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        node1.next = node2;
        boolean palindrome = isPalindrome(node1);
        System.out.println(palindrome);
    }

    //解法1:
    //输入: 1->2->2->1
    //输出: true
    public static boolean isPalindrome(ListNode head) {
        ListNode temp = head;//用临时指针指向头节点
        int i = 0;//数组的索引
        int ans = 0;//链表中的元素个数,为了开辟ans个数组空间
        while (temp != null) {
            temp = temp.next;//如果不用temp直接用head的话,head的指向就变了,下面再遍历链表将链表中的值放入数组的时候由于head指向指向了最后一个,就没法办了
            ans++;
        }
        int[] array = new int[ans];
        //下面的while循环是为了循环链表将值放入数组中
        while (head != null) {//注意这里是head,不是head.next,因为测试的时候第一个节点直接放进去的就是1.
            array[i++] = head.val;
            head = head.next;
        }
        System.out.println(Arrays.toString(array));
        //下面的操作是利用双指针依次移动比较对称位置的值是否相等
        int m = 0;
        int n = array.length - 1;
        while (m <= n) {
            //如果对称位置有不相等的元素直接返回false
            if (array[m] != array[n]) {
                return false;
            }
            //如果哦相等,首尾指针分别前后移动继续进行循环比较
            m++;
            n--;
        }
        return true;
    }
}

最后打开题解发现官方解法1也是这种暴力解法,绝了简直,只不过它用的是list集合

官方代码:起始本质是一样的,因为List集合的底层实现还是数组,但是这种是不需要开辟数组空间的。

public boolean isPalindrome(ListNode head) {
        List<Integer> vals = new ArrayList<Integer>();

        // 将链表的值复制到数组中
        ListNode currentNode = head;
        while (currentNode != null) {
            vals.add(currentNode.val);
            currentNode = currentNode.next;
        }

        // 使用双指针判断是否回文
        int front = 0;
        int back = vals.size() - 1;
        while (front < back) {
            if (!vals.get(front).equals(vals.get(back))) {
                return false;
            }
            front++;
            back--;
        }
        return true;
    }

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-linked-list-lcci/solution/hui-wen-lian-biao-by-leetcode-solution-6cp3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解法2:此处摘抄官方,代码自己撸一遍就好。

双指针+反转链表

整个流程可以分为以下五个步骤:

  1. 找到前半部分链表的尾节点。
  2. 反转后半部分链表。
  3. 判断是否回文。
  4. 恢复链表。
  5. 返回结果

也是比较简单,直接上代码:

public static boolean isPalindrome2(ListNode head) {
        if (head == null) return true;
        //首先找到中间节点并且反转
        ListNode firstHalfEnd = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEnd.next);
        //判断是否回文
        ListNode p1 = head;
        ListNode p2 = secondHalfStart;
        boolean flag = true;
        while (flag && p2 != null) {//这里不能是p2.next,因为最后一个节点也要比较
            if (p1.val != p2.val) {
                flag = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }
        //还原链表并且返回结果
        firstHalfEnd.next = reverseList(secondHalfStart);
        return flag;
    }

    //找到前半部分的最后一个节点,也就是中间节点
    private static ListNode endOfFirstHalf(ListNode head) {
        //定义两个指针,一个一次走两步,一个一次走一步,当快的到达终点,慢的就到了中点
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    //反转链表的方法
    private static 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;
    }

测试:

public static void main(String[] args) {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(2);
        ListNode node4 = new ListNode(1);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = null;
        boolean palindrome = isPalindrome2(node1);
        System.out.println(palindrome);
    }

链表的中间节点也是一道题:https://leetcode-cn.com/problems/middle-of-the-linked-list/submissions/

但是此题要求的是假如是偶数的话,比如123456,中间节点是456,从4开始,而上面求链表的中间节点是3,因此将代码稍作修改即可得到这个题的答案,代码如下:

 private static ListNode endOfFirstHalf(ListNode head) {
        //定义两个指针,一个一次走两步,一个一次走一步,当快的到达终点,慢的就到了中点
        ListNode slow = head;
        ListNode fast = head;
        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、付费专栏及课程。

余额充值