【算法题解】回文链表(力扣234题)四种方法

法一:双指针(O(n)、O(n))

  1. 将链表转成数组
  2. 设置两个指针L和R指向数组的第一位和最后一位,
  3. 移动并判断下标L和R对应的数组元素是否相同
  4. 都相同则是回文链表返回true,不相同则不是回文链表直接返回false
// 方法一:双指针,O(n)
public boolean isPalindrome(ListNode head) {
    // base case
    if (head == null || head.next == null) return true;

    List<Integer> list = new ArrayList<>();
    while (head != null) {
        // 遍历链表,将链表转为数组,这样可以动的链表的长度
        list.add(head.val);
        head = head.next;
    }
    // 左指针,位于数组的第一位,依次往右遍历
    int L = 0;
    // 右指针,位于数组的最后一位,依次往左遍历,-1是因为数组下标从0开始,
    int R = list.size() - 1;
    // 双指针移动判断
    while (L < R) {// 此处 < 是不区分链表长度是奇数还是偶数
        // 比较当前的下标L和R对应元素不相等的话,则不是回文链表
        // 此处用equals方法比较的是对象,因为list存的是Integer对象,所以不能用==(比较的是基本数据类型)
        if (!list.get(L).equals(list.get(R))) return false;
        L++;// 左指针往右移动一位
        R--;// 右指针往左移动一位
    }
    // 全部比较完成且全部相等,则是回文链表
    return true;
}

法二:递归(O(n)、O(n))

  1. O(n)、O(n)
        // 方法二:递归,
        // p 指向头结点
        ListNode p ;
        public boolean isPalindrome(ListNode head) {
            p = head;
            return recursion(head);
        }
        // 递归方法,全部返回true才是回文,
        public boolean recursion(ListNode head) {
            // 递归出口,当遍历链表完时开始倒退
            if (head == null) return true;
            // 递归,倒退
            if (!recursion(head.next)) return false;
            // 当前p的值和倒退的值不一样则不是回文链表
            if (p.val != head.val) return false;
            // p 后移
            p = p.next;
            // 当前p的值和倒退的值一样则是回文链表
            return true;
        }

法三:栈(O(n)、O(n))

  1. O(n)、O(n)
  		// 方法三:栈
        public boolean isPalindrome(ListNode head) {
            // base case 空算回文
            if (head == null || head.next == null) return true;

            ListNode temp = head;
            Stack<Integer> stack = new Stack<>();
            // 链表全部入栈
            while (temp != null) {
                stack.push(temp.val);
                temp = temp.next;
            }
            // 出栈并比较
            while (head != null && !stack.isEmpty()) {
                // 出栈和当前链表结点比较,不同返回false 不是回文链表
                if (head.val != stack.pop()) return false;
                // 相同,继续比较下一位
                head = head.next;
            }
            // 比较完了,且都相等,证明是回文链表返回true
            return true;
        }

法四:快慢指针(推荐使用,O(n)、O(1))

  1. 快指针fast移动两步,慢指针slow移动一步,
    遍历链表完后慢指针slow移动到了链表的中点位置
  2. 遍历完后,将快指针fast重新指向头结点,将慢指针slow之后的链表翻转,
  3. 一次比较快指针fast的值和慢指针slow的值,如果有一个不相等直接返回false,不是回文链表;如果比较完后全部相等,那么就是回文链表,返回true。
		// 法四:快慢指针
        public boolean isPalindrome(ListNode head) {
            // base case 空算回文
            if (head == null || head.next == null) return true;

            // 设置两个快慢指针
            ListNode fast = head;
            ListNode slow = head;
            // 遍历、移动两个指针
            while (fast != null && fast.next != null) {// fast移动到链表末端
                // 快指针每次移动两步
                fast = fast.next.next;
                // 慢指针每次移动一步
                slow = slow.next;
            }
            // 将快指针重置为链表的头结点
            fast = head;
            // 翻转slow之后的链表
            ListNode reverseList = reverseList(slow);
            // 比较 fast 和 翻转后的reverseList 的值,结束条件:比较到链表的末尾
            while (reverseList != null) {
                // 出现一个不相等,则不是回文链表
                if (fast.val != reverseList.val) return false;
                // fast 和 翻转后的reverseList的指针后移一步
                fast = fast.next;
                reverseList = reverseList.next;
            }
            // 比较完了,全部相等,则是回文链表
            return true;
        }

        // 翻转链表
        public ListNode reverseList(ListNode head) {
            ListNode previous = null;
            ListNode current = head;
            while (current != null) {
                // 记录下一结点
                ListNode next = current.next;
                // 前面结点的赋给后面的
                current.next = previous;
                // 后面结点的赋给前面的
                previous = current;
                // 结点后移,即开始处理下一个结点
                current = next;
            }
            // 返回翻转后的链表
            return previous;
        }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值