• 使用java封装单链表判定回文


    一.需求

    使用JAVA实现单链表,使用单链表检测字符串是否是回文串

    二.需求分析

    回文串最重要的就是对称,那么最重要的问题就是找到那个中心,用快指针每步走两格,当他到达链表末端的时候,慢指针刚好到达中心,慢指针在遍历过程中(快指针到达末端时)把走过的节点进行反向操作,此时从中位点分为前后两部分,此时前半部分的指针开始往回指(取next的时候,取的是前一个节点),而慢指针继续向前,跟前半部分的数据依次进行比对,当慢指针扫完整个链表,就可以判断这是回文串,否则就提前退出,同时在前半部分往回遍历的过程中将前半部分的指针重置成正向。

    链表存在奇偶数情况。

    • 奇数的时候,快指针遍历到末端的时候,中点位即中间位置的点,此中位点下一个节点为后半部分比对开始的位置。
    • 偶数的时候,快指针遍历到末端的时候,中点位置此时为下中位点,此中位点就是后半部分比对开始的位置。

    三.代码实现

    1.单链表类封装

    public class ListNode<T> {
        /**
         * 根节点索引位置
         */
        private int foot;
        /**
         * 代表链表程度
         */
        private int count;
        /**
         * 标识根节点
         */
        private Node root;
    
        //链接点类,内部方法实现,外部使用
        private class Node {
            //数据信息
            private T data;
            //下一个节点引用
            private Node next;
    
            public Node(T data) {
                this.data = data;
            }
    
            //添加节点
            private void add(T data) {
                if (this.next == null) {
                    //如果当前节点的next为null,直接创建一个新的节点
                    this.next = new Node(data);
                } else {
                    //否则进行递归调用,直到最后在某个为空的节点创建一个新节点
                    this.next.add(data);
                }
            }
    
            //删除节点1
            public void remove(Node previous, int index) {
    
                if (ListNode.this.foot++ == index) {
                    //this表示当前要删除的节点
                    previous.next = this.next;
                    this.next = null;
                    ListNode.this.count--;
                    return;
                } else {
                    //递归删除
                    this.next.remove(this, index);
                }
    
            }
    
            //删除节点2
            public void remove(Node previous, T data) {
                if (this.data.equals(data)) {
                    previous.next = this.next;
                    this.next = null;
                    ListNode.this.count--;
                    return;
                } else {
                    if (this.next != null) {
                        this.next.remove(this, data);
                    } else {
                        return;
                    }
                }
            }
    
            //修改数据  -- 新数据替换旧数据
            public void replace(T oldData, T newData) {
                if (this.data.equals(newData)) {
                    this.data = newData;
                } else {
                    //递归修改,寻找当前节点下一个节点,直到某个节点的值匹配入参
                    this.next.replace(oldData, newData);
                }
    
            }
    
            //修改数据  -- 利用索引修改
            public void replace(int index, T newData) {
                if (ListNode.this.foot++ == index) {
                    //找到了某个值的索引和传入的索引相同,直接替换
                    this.data = newData;
                } else {
                    this.next.replace(index, newData);
                }
            }
    
            //查询
            public T get(int index) {
                if (ListNode.this.foot++ == index) {
                    return this.data;
                } else {
                    return this.next.get(index);
                }
            }
    
            //链表是否包含某个节点
            public boolean contains(T data) {
                //如果当前的这个data正好和传入的data匹配
                if (this.data.equals(data)) {
                    return true;
                } else {
                    //如果当前的这个不匹配,则需要查找下一个节点
                    if (this.next == null) {
                        return false;
                    } else {
                        return this.next.contains(data);
                    }
                }
            }
    
        }
    
        public ListNode() {
    
        }
    
        //检查链表是否为空
        public boolean isEmpty() {
            if (count == 0 || this.root == null) {
                return true;
            } else {
                return false;
            }
        }
    
        //获取链表的长度
        public int size() {
            return this.count;
        }
    
        //添加
        public void add(T data) {
            if (this.isEmpty()) { //如果链表为空,新建一个节点
                this.root = new Node(data);
            } else {
                this.root.add(data);
            }
            this.count++;
        }
    
        //删除  -- 按照索引删除
        public void remove(int index) {
            if (this.isEmpty()) {
                return;
            }
            if (index < 0 || this.count <= index) {
                return;
            }
            if (index == 0) {    //想要删除根节点
                Node temp = this.root;
                this.root = this.root.next;
                temp.next = null;
                this.count--;
                return;
            } else {
                this.foot = 0;
                this.root.remove(this.root, index);
            }
        }
    
        //根据传入的数值删除
        public void remove(T data) {
            if (this.isEmpty()) {
                return;
            }
            //如果删除的正好是根节点
            if (this.root.data.equals(data)) {
                Node temp = this.root;
                this.root = this.root.next;
                temp.next = null;
                this.count--;
                return;
            } else {
                this.root.remove(this.root, data);
            }
        }
    
        //修改  -- 根据索引修改
        public void replace(int index, T newData) {
            if (this.isEmpty()) {
                return;
            }
            if (index < 0 || this.count <= index) {
                return;
            }
            this.foot = 0;
            this.root.replace(index, newData);
        }
    
        //修改 -- 新老数据替换
        public void replace(T oldData, T newData) {
            if (this.isEmpty()) {
                return;
            }
            this.root.replace(oldData, newData);
        }
    
        //查询 --- 根据索引查找
        public T get(int index) {
            if (this.isEmpty()) {
                return null;
            }
            this.foot = 0;
            return this.root.get(index);
        }
    
        //是否包含
        public boolean contains(T data) {
            if (this.isEmpty()) {
                return false;
            }
            return this.root.contains(data);
        }
    
        //打印  toArray
        public Object[] toArray() {
            if (this.isEmpty()) {
                return null;
            }
            int count = this.count;
            Object[] retVal = new Object[count];
            for (int i = 0; i < count; i++) {
                retVal[i] = this.get(i);
            }
            return retVal;
        }
    }
    

    2.验证的具体方法

    boolean isPalindrome(ListNode.Node head) {
        if (head == null || head.next == null) {
          return true;
        }
        //
        ListNode.Node prev = null;
        //慢指针节点
        ListNode.Node slow = head;
        //快指针节点
        ListNode.Node fast = head;
        //奇数的中位节点或者是偶数的下中位节点
        ListNode.Node middle = head;
        while (fast != null && fast.next != null) {
          //快指针每次移动2个节点
          fast = fast.next.next;
          //慢指针每次移动1个节点
          ListNode.Node next = slow.next;
          //前半部分的指针反向。反向后前半部分节点的next节点都是他的前一个节点
          slow.next = prev;
          //当前的慢指针指向前一个节点
          prev = slow;
          //下一个节点变为慢节点
          slow = next;
          //记录中位节点
          middle = slow;
        }
        //如果fast不是null,说明此时有奇数个节点,偶数个节点时fast为null
        //还没有进行if处理之前slow节点和prev节点在奇偶数的情况下分别为
        // a b c d c b a  此种情况下slow节点是d,prev节点是第1个c
        // a b c c b a  此种情况下slow节点是第2个c,prev节点是第1个c
        if (fast != null) {
          //slow取中间节点的下一个节点,做为回文比较的起点
          slow = slow.next;
        }
        //进行if处理结束之后,slow代表的是后半段的第一个节点,指针向后移动
        //prev代表的是前半段的最后一个节点,指针向前移动
        // a b c d c b a  此种情况下slow节点是第2个c,prev节点是第1个c
        // a b c c b a  此种情况下slow节点是第2个c,prev节点是第1个c
        //前半部分指针恢复正常处理。将下一个节点记录下来
        ListNode.Node next = middle;
        while (slow != null) {
          //进行数据比对。如果不相等则不是回文
          if (slow.data != prev.data) {
            return false;
          }
          //前半部分当前节点
          ListNode.Node current = prev;
          //prev向前取节点
          prev = prev.next;
          //slow向后取节点
          slow = slow.next;
          //前半部分指针恢复正常处理。
          current.next = next;
          //本轮处理完之后,将next赋值为当前节点
          next = current;
        }
        return true;
    }
    

    四.代码测试

    public static void main(String[] args) {
        ListNode<String> listNode = new ListNode<String>();
        listNode.add("a");
        listNode.add("b");
        listNode.add("c");
        listNode.add("d");
        listNode.add("e");
        listNode.add("f");
        listNode.add("e");
        listNode.add("d");
        listNode.add("c");
        listNode.add("b");
        listNode.add("a");
        ListNode example = new ListNode();
        boolean b = example.isPalindrome(listNode.root);
        System.out.println("是否是回文:" + b);//true
    }
    

    五.完整代码

    public class ListNode<T> {
        /**
         * 根节点索引位置
         */
        private int foot;
        /**
         * 代表链表程度
         */
        private int count;
        /**
         * 标识根节点
         */
        private Node root;
    
        //链接点类,内部方法实现,外部使用
        private class Node {
            //数据信息
            private T data;
            //下一个节点引用
            private Node next;
    
            public Node(T data) {
                this.data = data;
            }
    
            //添加节点
            private void add(T data) {
                if (this.next == null) {
                    //如果当前节点的next为null,直接创建一个新的节点
                    this.next = new Node(data);
                } else {
                    //否则进行递归调用,直到最后在某个为空的节点创建一个新节点
                    this.next.add(data);
                }
            }
    
            //删除节点1
            public void remove(Node previous, int index) {
    
                if (ListNode.this.foot++ == index) {
                    //this表示当前要删除的节点
                    previous.next = this.next;
                    this.next = null;
                    ListNode.this.count--;
                    return;
                } else {
                    //递归删除
                    this.next.remove(this, index);
                }
    
            }
    
            //删除节点2
            public void remove(Node previous, T data) {
                if (this.data.equals(data)) {
                    previous.next = this.next;
                    this.next = null;
                    ListNode.this.count--;
                    return;
                } else {
                    if (this.next != null) {
                        this.next.remove(this, data);
                    } else {
                        return;
                    }
                }
            }
    
            //修改数据  -- 新数据替换旧数据
            public void replace(T oldData, T newData) {
                if (this.data.equals(newData)) {
                    this.data = newData;
                } else {
                    //递归修改,寻找当前节点下一个节点,直到某个节点的值匹配入参
                    this.next.replace(oldData, newData);
                }
    
            }
    
            //修改数据  -- 利用索引修改
            public void replace(int index, T newData) {
                if (ListNode.this.foot++ == index) {
                    //找到了某个值的索引和传入的索引相同,直接替换
                    this.data = newData;
                } else {
                    this.next.replace(index, newData);
                }
            }
    
            //查询
            public T get(int index) {
                if (ListNode.this.foot++ == index) {
                    return this.data;
                } else {
                    return this.next.get(index);
                }
            }
    
            //链表是否包含某个节点
            public boolean contains(T data) {
                //如果当前的这个data正好和传入的data匹配
                if (this.data.equals(data)) {
                    return true;
                } else {
                    //如果当前的这个不匹配,则需要查找下一个节点
                    if (this.next == null) {
                        return false;
                    } else {
                        return this.next.contains(data);
                    }
                }
            }
    
        }
    
        public ListNode() {
    
        }
    
        //检查链表是否为空
        public boolean isEmpty() {
            if (count == 0 || this.root == null) {
                return true;
            } else {
                return false;
            }
        }
    
        //获取链表的长度
        public int size() {
            return this.count;
        }
    
        //添加
        public void add(T data) {
            if (this.isEmpty()) { //如果链表为空,新建一个节点
                this.root = new Node(data);
            } else {
                this.root.add(data);
            }
            this.count++;
        }
    
        //删除  -- 按照索引删除
        public void remove(int index) {
            if (this.isEmpty()) {
                return;
            }
            if (index < 0 || this.count <= index) {
                return;
            }
            if (index == 0) {    //想要删除根节点
                Node temp = this.root;
                this.root = this.root.next;
                temp.next = null;
                this.count--;
                return;
            } else {
                this.foot = 0;
                this.root.remove(this.root, index);
            }
        }
    
        //根据传入的数值删除
        public void remove(T data) {
            if (this.isEmpty()) {
                return;
            }
            //如果删除的正好是根节点
            if (this.root.data.equals(data)) {
                Node temp = this.root;
                this.root = this.root.next;
                temp.next = null;
                this.count--;
                return;
            } else {
                this.root.remove(this.root, data);
            }
        }
    
        //修改  -- 根据索引修改
        public void replace(int index, T newData) {
            if (this.isEmpty()) {
                return;
            }
            if (index < 0 || this.count <= index) {
                return;
            }
            this.foot = 0;
            this.root.replace(index, newData);
        }
    
        //修改 -- 新老数据替换
        public void replace(T oldData, T newData) {
            if (this.isEmpty()) {
                return;
            }
            this.root.replace(oldData, newData);
        }
    
        //查询 --- 根据索引查找
        public T get(int index) {
            if (this.isEmpty()) {
                return null;
            }
            this.foot = 0;
            return this.root.get(index);
        }
    
        //是否包含
        public boolean contains(T data) {
            if (this.isEmpty()) {
                return false;
            }
            return this.root.contains(data);
        }
    
        //打印  toArray
        public Object[] toArray() {
            if (this.isEmpty()) {
                return null;
            }
            int count = this.count;
            Object[] retVal = new Object[count];
            for (int i = 0; i < count; i++) {
                retVal[i] = this.get(i);
            }
            return retVal;
        }
    
        boolean isPalindrome(ListNode.Node head) {
            if (head == null || head.next == null) {
                return true;
            }
            //
            ListNode.Node prev = null;
            //慢指针节点
            ListNode.Node slow = head;
            //快指针节点
            ListNode.Node fast = head;
            //奇数的中位节点或者是偶数的下中位节点
            ListNode.Node middle = head;
            while (fast != null && fast.next != null) {
                //快指针每次移动2个节点
                fast = fast.next.next;
                //慢指针每次移动1个节点
                ListNode.Node next = slow.next;
                //前半部分的指针反向。反向后前半部分节点的next节点都是他的前一个节点
                slow.next = prev;
                //当前的慢指针指向前一个节点
                prev = slow;
                //下一个节点变为慢节点
                slow = next;
                //记录中位节点
                middle = slow;
            }
            //如果fast不是null,说明此时有奇数个节点,偶数个节点时fast为null
            //还没有进行if处理之前slow节点和prev节点在奇偶数的情况下分别为
            // a b c d c b a  此种情况下slow节点是d,prev节点是第1个c
            // a b c c b a  此种情况下slow节点是第2个c,prev节点是第1个c
            if (fast != null) {
                //slow取中间节点的下一个节点,做为回文比较的起点
                slow = slow.next;
            }
            //进行if处理结束之后,slow代表的是后半段的第一个节点,指针向后移动
            //prev代表的是前半段的最后一个节点,指针向前移动
            // a b c d c b a  此种情况下slow节点是第2个c,prev节点是第1个c
            // a b c c b a  此种情况下slow节点是第2个c,prev节点是第1个c
            //前半部分指针恢复正常处理。将下一个节点记录下来
            ListNode.Node next = middle;
            while (slow != null) {
                //进行数据比对。如果不相等则不是回文
                if (slow.data != prev.data) {
                    return false;
                }
                //前半部分当前节点
                ListNode.Node current = prev;
                //prev向前取节点
                prev = prev.next;
                //slow向后取节点
                slow = slow.next;
                //前半部分指针恢复正常处理。
                current.next = next;
                //本轮处理完之后,将next赋值为当前节点
                next = current;
            }
            return true;
        }
    
        public static void main(String[] args) {
            ListNode<String> listNode = new ListNode<String>();
            listNode.add("a");
            listNode.add("b");
            listNode.add("c");
            listNode.add("d");
            listNode.add("e");
            listNode.add("f");
            listNode.add("e");
            listNode.add("d");
            listNode.add("c");
            listNode.add("b");
            listNode.add("a");
            ListNode example = new ListNode();
            boolean b = example.isPalindrome(listNode.root);
            System.out.println("是否是回文:" + b);
        }
    }
    

    站在巨人肩膀上摘苹果

    https://blog.csdn.net/zhangcongyi420/article/details/88259722

    https://github.com/andavid/leetcode-java/blob/master/note/234/README.md

  • 相关阅读:
    【BZOJ】1045: [HAOI2008]糖果传递(中位数)
    【BZOJ】1011: [HNOI2008]遥远的行星(近似)
    【BZOJ】1034: [ZJOI2008]泡泡堂BNB(贪心)
    【BZOJ】1029: [JSOI2007]建筑抢修(贪心)
    【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)
    【BZOJ】1010: [HNOI2008]玩具装箱toy(dp+斜率优化)
    noip2014滚粗记
    【NOIP模拟题】Permutation(dp+高精度)
    MySQL 关于自定义函数的操作
    MySQL 关于存储过程的操作
  • 原文地址:https://www.cnblogs.com/eternityz/p/13748152.html
Copyright © 2020-2023  润新知