【LeetCode】234. 回文链表(Java)

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

进阶:
你能否用 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) {
        // 链表为空或者链表节点为1时,为回文链表
        if (head == null || head.next == null)  return true;

        // 数组
        // 循环得到链表的长度
        int count = 0;
        ListNode temp = head;
        while (temp != null) {
            temp = temp.next;
            count++;
        }

        // 创建数组,把链表中的val都放到数组中
        int[] arr = new int[count];
        temp = head;
        for (int i = 0; i < count; i++) {
            arr[i] = temp.val;
            temp = temp.next;
        }

        // 定义两个指针,从两头比较,往中间走
        int l = 0, r = count - 1;
        while (l < r) {
            if (arr[l++] != arr[r--]) {
                return false;
            }
        }
        return true;
    }
}

在这里插入图片描述

解法二

list,思路和第一种解法一样,只是少了前面的循环获取链表的长度。

class Solution {
    public boolean isPalindrome(ListNode head) {
        // 链表为空或者链表节点为1时,为回文链表
        if (head == null || head.next == null)  return true;
        // list
        List<Integer> list = new ArrayList<>();

        // 把链表的val都放到list中
        ListNode temp = head;
        while (temp != null) {
            list.add(temp.val);
            temp = temp.next;
        }
        // 双指针比较
        int l = 0, r = list.size() - 1;
        while (l < r) {
            // 这里要取反
            if (!list.get(l).equals(list.get(r))) {
                return false;
            }
            l++;
            r--;
        }
        return true;
    }
}

在这里插入图片描述

解法三

class Solution {
    public boolean isPalindrome(ListNode head) {
        // 链表为空或者链表节点为1时,为回文链表
        if (head == null || head.next == null)  return true;

        // 栈
        Deque<Integer> stack = new ArrayDeque<>();

        // 快慢指针,把前面一半放入栈中
        ListNode s = head, f = head;
        // 链表个数双数时保持慢指针的值,然后跳出,如果是单数,直接跳出
        while (f.next != null) {
            // 如果f的下下个节点为空,说明链表的个数为双数
            if (f.next.next == null) {
                stack.offerLast(s.val);
                break;
            }
            // 把慢指针的val保存到栈中,指针移动
            stack.offerLast(s.val);
            s = s.next;
            f = f.next.next;
        }
        // 慢指针指向下个节点,然后从栈中取值比较
        s = s.next;
        while (s != null) {
            // 不相等,返回false
            if (s.val != stack.pollLast()) {
                return false;
            }
            s = s.next;
        }
        return true;
    }
}

在这里插入图片描述
前两种做法都不满足进阶的条件,特别是第二种解法,存入取出慢。

解法四

递归

class Solution {
    private ListNode frontPointer;

    public boolean isPalindrome(ListNode head) {
        // 递归
        frontPointer = head;
        return recursivelyCheck(head);
    }

    private boolean recursivelyCheck(ListNode node) {
        if (node == null)   return true;

        // 会递归到最后一个节点,然后和 frontPointer 比较
        // 如果不是回文,返回false
        if (!recursivelyCheck(node.next)) {
            return false;
        }
        // 和 frontPointer 比较,如果不相同,说明不是回文,返回false
        if (node.val != frontPointer.val) {
            return false;
        }
        // frontPointer 指向下一位
        frontPointer = frontPointer.next;
        return true;
    }
}

在这里插入图片描述

解法五

快慢指针,反转后半部分,满足进阶条件,不过会破坏原链表。

class Solution {
    public boolean isPalindrome(ListNode head) {
        // 链表为空或者链表节点为1时,为回文链表
        if (head == null || head.next == null)  return true;

        //快慢指针,反转后半部分
        ListNode slow = head, fast = head;
        // 找出中点
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // 如果快指针不为空,说明链表的个数为单数,中间不用比较,慢指针指向下一个节点
        if (fast != null) {
            slow = slow.next;
        }

        // 反转后半部分
        ListNode pre = slow, prepre = null;
        while (slow != null) {
            // 保存当前慢指针的位置
            pre = slow;
            // 移动慢指针
            slow = slow.next;
            // 反转
            pre.next = prepre;
            prepre = pre;
        }

        // 跳出循环后,head为前半部分的头节点,pre为后半部分的头节点
        while (head != null && pre != null) {
            if (head.val != pre.val) {
                return false;
            }
            head = head.next;
            pre = pre.next;
        }
        return true;
    }
}

在这里插入图片描述

解法六

快慢指针,反转前半部分,也满足进阶条件,不过同样会破坏原链表,思路来着题解区芜湖大司码的题解。

class Solution {
    public boolean isPalindrome(ListNode head) {
	    // 链表为空或者链表节点为1时,为回文链表
	    if (head == null || head.next == null)  return true;
	
	    // 快慢指针,反转前半部分
	    ListNode slow = head, fast = head;
	    ListNode pre = head, prepre = null;
	    while (fast != null && fast.next != null) {
	        // 保存当前慢指针的位置
	        pre = slow;
	        // 移动慢指针、快指针
	        slow = slow.next;
	        fast = fast.next.next;
	        // 反转
	        pre.next = prepre;
	        prepre = pre;
	    }
	    // 跳出循环后,前半部分链表的头节点为pre,后半部分的头节点为slow
	    // 跳出循环后判断,如果快指针所指节点不为空,说明这条链表长度为单数,最中间节点不用比较,慢指针再移动一个节点
	    if (fast != null) {
	        slow = slow.next;
	    }
	    // 比较两条链表
	    while (slow != null && pre != null) {
	        if (slow.val != pre.val) {
	            return false;
	        }
	        slow = slow.next;
	        pre = pre.next;
	    }
	    return true;
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值