• 算法


    问题三 判断一个链表是否为回文结构

    给定一个链表的头节点 head,请判断该链表是否为回文结构。

    1->2->1,返回 true。
    1->2->2->1,返回 true。
    15->6->15,返回 true。
    1->2->3,返回 false。
    

    思路

    第一次遍历,使用一个栈结构存储节点,第二次遍历,与弹出栈存储的值比较,相同为 true 不同为 false。

    可以使用快慢指针得到链表的对称轴的下一个节点,然后将值压栈,然后重头开始遍历,省下一半的栈空间,但是在计算空间复杂度时还是会忽略不计系数。

    // need n extra space
    public static boolean isPalindromeOne(Node head) {
        if (head == null || head.next == null) return true;
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        while (head != null) {
            if (head.val != stack.pop().val) {
                return false;
            }
            head = head.next;
        }
        return true;    
    }
    
    // need n/2 extra space
    public static boolean isPalindromeTwo(Node head) {
        if (head == null || head.next == null) return true;
        // These steps ensure the rigth point can be the exactly position. 
        Node right = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null) {
            right = right.next;
            cur = cur.next.next;
        }
        
        Stack<Node> stack = new Stack<>();
        while (right != null) {
            stack.push(right);
            right = right.next;
        }
        
        while (!stack.isEmpty()) {
            if (stack.pop().val != head.val) {
                return false;
            }
            head = head.next;
        }
        return true;
    }
    

    快慢指针举例

    通过代码是可以适应链表长度为奇数和偶数的情况,right 指针都会指到右半部分的链表的初始位置。

    c: point cur
    r: point right
    
    1->2->3->2->1
        
    1.
    1->2->3->2->1
    ↑  ↑
    c  r
    
    2.
    1->2->3->2->1
          ↑
         c r
         
    3.
    1->2->3->2->1
             ↑  ↑
             r  c
             
    1->2->3->3->2->1
            
    1.
    1->2->3->3->2->1
    ↑  ↑
    c  r
    
    2.
    1->2->3->3->2->1
          ↑
         c r
    
    3.
    1->2->3->3->2->1
             ↑  ↑
             r  c
    

    进阶

    如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。

    思路

    1.快慢指针,得到链表的中点,将中点后的节点逆序。
    1->2->3->2->1
    1->2->3<-2<-1
    ↑           ↑
    2.两端开始遍历,当两根指针相遇说明是回文结构,当值不相等的时候说明不是回文结构
    3.最后,将中点的后的节点再逆序
    1->2->3->2->1
    

    实现

    public static boolean isPalindromeThree(Node head) {
        if (head == null || head.next == null) return true;
        Node n1 = head;
        Node n2 = head;
        // n1 will be the end of left part or center
        while (n2.next != null && n2.next.next != null) {
            n1 = n1.next;
            n2 = n2.next.next;
        }
        // n2 will be the begin of right part
        n2 = n1.next;
        n1.next = null;
        
        // convert the right part
        Node n3 = null;
        while (n2 != null) {
            n1 = n2.next; // save next node
            n2.next = n3;
            n3 = n2;
            n2 = n1;
        }
        // n3 point the end of list; n2 & n1 is null
        // n3 | n2 | n1
        n1 = head;
        n2 = n3;
        
        boolean res = true;
        // compare n1 n3; n2 save the end of list
        while (n1 != null && n3 != null) {
            if (n1.val != n3.val) {
                res = false;
                break;
            }
            n1 = n1.next;
            n3 = n3.next;
        }
        
        // reconvert the right part
        // reconvert the end of list
        n3 = n2.next;
        n2.next = null;
        
        // n1 | n3 | n2
        while (n3 != null) {
            n1 = n3.next; // save the node
            n3.next = n2;
            n2 = n3;
            n3 = n1;
        }
        
        return res;
    }
    

    在遍历的过程中,修改了链表的结构,无论结果如何,最终还是要将改变的结构再逆转回来。

  • 相关阅读:
    php设计模式 — 简单工厂模式(静态工厂方法模式)
    Vue-Router
    各种选项卡
    jq动画
    如何使用swiper写轮播
    Gulp代码压缩
    闭包
    jquery.validation校验
    grunt-js文件压缩
    CSS
  • 原文地址:https://www.cnblogs.com/chenxianbin/p/11949457.html
Copyright © 2020-2023  润新知