• 链表逆序+判断链表是否回文


    单链表逆序详解

    1.具有链表头的单链表

      假设需要逆序的单链表为:
    单链表逆序详解

      则逆序以后的链表为:
    单链表逆序详解
      过程:
    (1)取p1指向header->next (p1=stu->next);p2保留p1->next(p2=p1->next);将p1->next置为NULL,因为单链表逆序以后,当前的p1节点为尾节点 p1->next=NULL;

    单链表逆序详解

    (2)取p3保留p2->next (p3=p2->next);将p2插入p1之前(p2->next = p1);p1指向p2指向的节点(p1=p2);p2指向p3指向的节点(p2=p3);

    单链表逆序详解
      循环一次修改以后的单链表如下:

    单链表逆序详解

    (3)重复步骤(2)
    单链表逆序详解

      循环一次修改以后的单链表如下:

    单链表逆序详解

    (4)将header->next指向p1,完成整个单链表的逆序

    单链表逆序详解

    typedef struct student{
        int number;
        char name[20];
        int score;
        struct student *next;
    }student;
    student *reverse(student *stu){
        student *p1,*p2,*p3;
        if(stu == NULL ||stu->next == NULL)
            return stu;
        p1=stu->next;                           //p1指向链表头节点的下一个节点
        p2=p1->next;
        p1->next=NULL;
        while(p2){
            p3=p2->next;
            p2->next = p1;
            p1=p2;
            p2=p3;
        }
        stu->next=p1; 
        return stu;
    }
    
    2.链表回文
      判断一个单向链表是否是回文链表,要求O(n)的时间复杂度和O(1)的空间复杂度。算法有以下几种:
    1. 遍历整个链表,将链表每个节点的值记录在数组中,再判断数组是不是一个回文数组,时间复杂度为O(n),但空间复杂度也为O(n),不满足空间复杂度要求。
    2. 利用栈先进后出的性质,将链表前半段压入栈中,再逐个弹出与链表后半段比较。时间复杂度O(n),但仍然需要n/2的栈空间,空间复杂度为O(n)。
    3. 反转链表法,将链表后半段原地翻转,再将前半段、后半段依次比较,判断是否相等,时间复杂度O(n),空间复杂度为O(1)满足题目要求。
    使用快慢指针加栈实现判断的代码如下:
        public boolean chkPalindrome(ListNode A) {
            Stack<Integer> stack = new Stack<Integer>();
            if (A == null || A.next == null)
                return true;
            ListNode quick = A;
            ListNode slow = A;
            boolean flag = false;
            while (quick != null) {
                stack.add(slow.val);
                slow = slow.next;
                quick = quick.next;
                if (quick != null) {
                    quick = quick.next;
                } else {
                    flag = true;
                }
            }
            if (flag == true)
                stack.pop();
            while (!stack.isEmpty() && slow != null) {
                int va = stack.pop();
                if (va == slow.val)
                    slow = slow.next;
                else
                    return false;
            }
            if (slow == null && stack.isEmpty())
                return true;
            else
                return false;
        }
    View Code
    使用快慢指针和原地翻转的代码如下:
    public boolean chkPalindrome(ListNode A) {
            if (A == null)
                return false;
            if (A.next == null)
                return true;
            ListNode quick = A;
            ListNode slow = A;
            while (quick != null && quick.next != null) {
                quick = quick.next.next;
                slow = slow.next;
            }
            ListNode p = slow.next;
            ListNode p1 = p.next;
            while (p != null) {
                p.next = slow;
                slow = p;
                p = p1;
                if (p1 != null) {
                    p1 = p1.next;
                }
            }
            while (A != slow) {
                if (A.val != slow.val) {
                    return false;
                }
                if(A.next==slow){
                    return true;
                }
                A = A.next;
                slow = slow.next;
            }
            return true;
        }
    View Code
  • 相关阅读:
    swift
    swift
    swift
    swift
    swift
    swift
    swift
    选择排序
    组合 和 继承
    Android中使用LitePal操控SQLite数据库
  • 原文地址:https://www.cnblogs.com/wxgblogs/p/5766172.html
Copyright © 2020-2023  润新知