美文网首页
数据结构与算法 | 回文链表检测

数据结构与算法 | 回文链表检测

作者: wangwei_hz | 来源:发表于2019-01-31 20:56 被阅读22次
    pexels-photo-747964

    原文链接:https://wangwei.one/posts/java-algoDS-palindrome-linked-list.html

    如何判断一个单链表是否为回文链表?

    回文链表

    LeetCode 234. Palindrome Linked List

    例1:

    Input: 1->2
    Output: false
    

    例2:

    Input: 1->2->2->1
    Output: true
    

    提升:
    时间复杂度为O(n),空间复杂度为O(1).

    解法一

    直接将链表进行 反转 ,然后将新的反转链表与原链表进行比较,这种思路最为简单粗暴。

    此种解法的时间复杂度为O(n),空间复杂度为O(n).

    代码

    /**
     * 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){
                return true;
            }
            ListNode newCurr = null;
            ListNode newPrev = null;
            ListNode curr = head;
            while(curr != null){
                newCurr = new ListNode(curr.val);
                newCurr.next = newPrev;
                newPrev = newCurr;
                curr = curr.next;
            }
            
            ListNode p1 = newCurr;
            ListNode p2 = head;
            
            while(p2 != null && p2 != null){
                if(p2.val != p1.val){
                    return false;
                }
                p1 = p1.next;
                p2 = p2.next;
            }
            return true;
        }
    }
    
    

    LeetCode性能测试:

    Runtime: 3 ms, faster than 24.01% of Java online submissions forPalindrome Linked List.

    解法二

    为了降低空间复杂度到O(1),我们可以只对链表的后半部分直接反转,然后将反转后的后半部分与前半部分进行比较。

    如何对后半部分进行反转呢?这就涉及到我们前面的 如何找到中间节点 的方法,使用快慢指针,先找到中间节点,然后从中间节点开始反转。

    需要注意的是,在进行比较时,要以后半部分为基准进行遍历来比较,例如在链表长度位偶数的情况下:

    A -> B -> C -> C -> B -> A 反转得到 A -> B -> C -> C <- B <- A,以前半部分为基准的话,会出现 null 指针的异常。

    此种解法的时间复杂度为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){
                return true;
            }
            
            // 先找到中间节点,slow最后的结果就是中间节点
            ListNode slow = head;
            ListNode fast = head;
            
            for(ListNode curr = slow; slow != null; ){               
                if(fast == null || fast.next == null){
                    break;
                }else{
                    fast = fast.next.next;
                }
                slow = slow.next;
            }
            
            // 从slow开始,对后链表后半部分进行反转
            ListNode prev = null;
            ListNode curr = slow;
            ListNode next = null;
            
            while(curr != null){
                next = curr.next;
                curr.next = prev;
                prev = curr;
                curr = next;
            }
            
            // 对前后两个部分进行比较
            ListNode p1 = head;
            ListNode p2 = prev;
            
            while(p2 != null){
                if(p1.val != p2.val){
                    return false;
                }
                p1 = p1.next;
                p2 = p2.next;
            }     
            return true;
        }
    }
    

    LeetCode性能测试:

    Runtime: 1 ms, faster than 93.05% of Java online submissions forPalindrome Linked List.

    解法三

    解法三比较巧妙,不容易想到。思路如下:

    • 定义左右两个指针,左指针向有移动,"右指针向左移动",对比左右两个指针是否配置。
    • 我们这里是单链表,右指针怎么向左移动呢?这里通过递归的方式,当递归函数一层一层返回时,变相地实现了"右指针左移"的思路。

    代码

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        
        private ListNode head;
        private ListNode left;
            
        public boolean isPalindrome(ListNode head1) {
            head = head1;
            return isPalindromeUtil(head1);
        }
        
        private boolean isPalindromeUtil(ListNode right){ 
            left = head; 
            
            // 当指向NULL时,停止递归
            if (right == null){
                return true; 
            } 
      
            // 向右移动指针,递归调用
            boolean isp = isPalindromeUtil(right.next); 
            if (isp == false){
                return false; 
            } 
      
            // 比较左右指针是否匹配
            boolean isp1 = (right.val == left.val); 
    
            // 移动左指针
            left = left.next; 
      
            return isp1; 
        } 
    }
    

    LeetCode性能测试:

    Runtime: 3 ms, faster than 22.70% of Java online submissions forPalindrome Linked List.

    相关练习

    参考资料

    相关文章

      网友评论

          本文标题:数据结构与算法 | 回文链表检测

          本文链接:https://www.haomeiwen.com/subject/bxvlsqtx.html