算法通关村第一关——链表经典问题之回文序列笔记

题目描述

LeetCode234,这是一个简单且经典的链表题,判断一个链表 是否为回文链表

示例1

输入:1 -> 2 -> 2 ->1

输出:true 

方法分析

方法1:将链表元素全部压入栈(栈的特点:先进后出,将元素全部压入栈后就能达到链表最后一个元素最先出栈的效果),然后一边出栈,一边重新遍历链表 ,并且一边比较出栈的元素和链表的元素是否相等。如果完全相等,就说明该链表是一个回文序列的链表,返回true;但只要有一个元素不相等,就会返回false

代码实现

    /**
     * 判断是否为回文序列
     * @param head 头节点
     * @return 是回文序列/不是回文序列
     */
    public boolean isPalindrome(Node head){
        Node temp = head;
        Stack<Integer> stack = new Stack<>();
        // 将单链表全部压入栈
        while (temp != null){
            stack.push(temp.data);
            temp = temp.next;
        }
        // 一边出栈,一边比较
        while (head != null){
            if (head.data != stack.pop()){
                return false;
            }
            head = head.next;
        }
        return true;
    }

测试运行

主方法
    public static void main(String[] args) {
        // 将一个数组转换为链表
        int [] arr = {1,2,2,1};
        SingleLinkedList linkedList = new SingleLinkedList();
        Node head =SingleLinkedList.transformSingleList(arr);
        System.out.println("原始链表为:");
        linkedList.printSingleList(head);
        System.out.println();
        PalindromicSequence sequence = new PalindromicSequence();
        boolean palindrome = sequence.isPalindrome(head);
        System.out.println("palindrome = " + palindrome);
    }
 节点代码
public class Node {
    public  int data;
    public Node next;

    public Node(int data) {
        this.data = data;
    }
}
数组转链表代码
    /**
     * 将数组转为链表
     * @param arr 数组
     * @return 链表头节点
     */
    public static Node transformSingleList(int [] arr){
        Node head =new Node(arr[0]);
        // 使用辅助节点遍历将其余的元素 ,将其变为节点,添加在头节点之后
        Node node = head;
        for (int i = 1 ; i < arr.length ;i ++) {
            Node temp = new Node(arr[i]);
            node.next = temp;
            node = temp;
        }
        return head;
    }
遍历链表代码
    /**
     * 链表遍历
     * @param head  链表头节点
     */
    public void printSingleList(Node head){
        Node node = head;
        while (node != null){
                System.out.print(node.data + "->");
                node = node.next;
        }
    }

测试结果

原始链表为:
1->2->2->1->
palindrome = true 

优化思路

思路1:先遍历一遍链表,得到链表总长度。之后一边遍历,一遍压入栈。达到链表长度一半时就不再压栈,而是一边出栈,一边遍历,一边比较,只要有一个不相等,就不是回文序列。这样可以节省一半的空间

代码实现
    /**
     * 判断是否为回文序列
     * @param head 头节点
     * @return 是回文序列/不是回文序列
     */
    public boolean isPalindrome1(Node head){
        SingleLinkedList linkedList = new SingleLinkedList();
        Node temp = head;
        int length = linkedList.getLinkedListLength(temp);
        Stack<Integer> stack = new Stack<>();
        // 将单链表一半压入栈
        while (temp != null || stack.size()<=length/2){
            stack.push(temp.data);
            temp = temp.next;
        }
        // 一边出栈,一边比较
        while (head != null){
            if (head.data != stack.pop()){
                return false;
            }
            head = head.next;
        }
        return true;
    }

思路2:既然要得到长度,那还是要遍历一次链表才可以。那是不是可以一边遍历一边全部压栈,然后第二遍比较的时候,只比较一半的元素呢?也就是说,只有一半的元素出栈,链表也只遍历一半。 

其他思路1

 反转链表法:先创建一个链表newList,将原始链表oldList的元素值逆序保存到newList中,然后重新一边遍历两个链表,一边比较元素的值,只要有一个位置的元素不一样,就不是回文链表。

代码实现
   /**
     *  使用双指针 + 链表实现链表反转
     * @param head 链表头节点
     * @return 是否是回文序列
     */
    public boolean isPalindrimucByReverseList(Node head){
        if (head == null || head.next == null){
            return false;
        }
        // 定义快慢指针
        Node fast = head;
        Node slow = head;
        // 定义反转后的链表头
        Node pre = head;
        // 定义反转需要的临时头
        Node temp = null;

        while (fast != null && fast.next != null){
            pre = slow;
            // 双指针移动
            slow = slow.next;
            fast = fast.next.next;
            // 链表前半段反转
            pre.next = temp;
            temp = pre;
        }
        // 判断奇偶性,如果是偶数,不用这步,如果是奇数,执行这步
        if (fast != null){
            slow = slow.next;
        }

        while (pre != null && slow != null){
            if (pre.data != slow.data){
                return false;
            }
            pre = pre.next;
            slow = slow.next;
        }
        return true;
    }

反转链表法的优化

方法1:只反转一半的元素就行: 先遍历一边,得到链表的总长度,然后重新遍历,达到一半的位置后就不再反转,开始比较两个链表

方法2:使用双子针思想里的快慢指针:fast一次走两步,slow一次走一步。当fast到达表尾的时候,slow正好达到一半的位置,那么接下来就可以从头开始逆序一半的元素,或者从slow开始逆序一半的元素,都可。

 其他思路2

在遍历的时候是用递归来反转一半链表 等等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值