美文网首页
基于单链表的回文序列判断

基于单链表的回文序列判断

作者: Ridiculous_one | 来源:发表于2019-07-06 03:13 被阅读0次

    本文首发于 LOGI'S BLOG,由作者转载。

    问题

    假如字符串使用单向链表存储,如何判断其是否为回文序列?

    思路

    S1. 定义快慢指针,快指针每次走两步,慢指针每次走一步同时将所经链表指针逆向,直到快指针走至表尾(next 为 null),此时慢指针刚好处于中点(对于元素个数为偶数的链表,处于下中点,即后半部分的首节点)。

    S2. 同时遍历前后半段链表,如完全相同则为回文序列。

    S3. 恢复被逆序的链表。

    举例

    奇数序列:ABCBA

    A -> B -> C -> B -> A // 初态
    A <- B <- C -> B- > A // S1 后
             slow
    

    偶数序列:ABCCBA

    A -> B -> C -> C -> B -> A // 初态
    A <- B <- C <- C -> B -> A // S1 后
                  slow
    

    时空复杂度

    S1 的时间复杂度为 O(n/2),空间复杂度 O(1)。
    S2 的时间复杂度为 O(n/2),空间复杂度 O(1)。
    S3 的时间复杂度为 O(n/2),空间复杂度 O(1)。
    最终总的时间复杂度就是 O(n),空间复杂度 O(1)。

    代码实现

    package com.logi.algorithm;
    
    /**
     * @author LOGI
     * @version 1.0
     * @date 2019/7/6 0:46
     */
    public class PalindromeExamination {
        public static void main(String[] args) {
            PalindromeExamination.testSequence("ABCBA");
            PalindromeExamination.testSequence("ABCBB");
            PalindromeExamination.testSequence("ABCCBA");
            PalindromeExamination.testSequence("ABCCBB");
        }
    
        public static void testSequence(String sequence) {
            SinglyLinkedList list = new SinglyLinkedList(sequence);
            String determination = list.isPalindrome() ? "" : "not ";
            System.out.println(sequence + " is " + determination + "a palindrome.");
        }
    }
    
    class SinglyLinkedList {
        Node head;
    
        public SinglyLinkedList(String sequence) {
            for (int i = sequence.length() - 1; i >= 0; i--) {
                this.insert(sequence.charAt(i));
            }
        }
    
        public void insert(char elem) {
            Node newNode = new Node(elem);
            newNode.next = this.head;
            this.head = newNode;
        }
    
        public boolean isPalindrome() {
            if (this.head == null || this.head.next == null) {
                return false;
            }
            Node prev = null;
            Node next;
            Node slow = this.head;
            Node fast = this.head;
    
            // 判断 fast.next 是否为 null,在此之前也要保证 fast 不为 null
            while (fast != null && fast.next != null) {
                fast = fast.next.next;
                // 逆向 slow.next
                next = slow.next;
                slow.next = prev;
                prev = slow;
                slow = next;
            }
            // 保存中点用于恢复
            Node mid = slow;
            Node midPre = prev;
    
            // 奇数序列,从中点之后开始比较
            if (fast != null) {
                slow = slow.next;
            }
            while (slow != null) {
                if (slow.data != prev.data) {
                    return false;
                }
                slow = slow.next;
                prev = prev.next;
            }
    
            // 再次逆向 midPre.next,恢复链表
            while (midPre != null) {
                next = midPre.next;
                midPre.next = mid;
                mid = midPre;
                midPre = next;
            }
            return true;
        }
    }
    
    class Node {
        Node next;
        char data;
    
        public Node(char elem) {
            this.data = elem;
            this.next = null;
        }
    }
    

    相关文章

      网友评论

          本文标题:基于单链表的回文序列判断

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