判断一个链表是否为回文链表的三种思路及JAVA代码实现

package day09;
//合并两个有序链表

import java.util.ArrayList;
import java.util.List;

public class MergeTwoLists {
    public static void main(String[] args) {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(2);

        ListNode node4 = new ListNode(1);

        ListNode node5 = new ListNode(3);
        ListNode node6 = new ListNode(4);

        //测试合并
        /*node1.next = node2;
        node2.next = node3;// 1->2->4

        node4.next = node5;
        node5.next = node6;//1->3->4

        ListNode newList = mergeTwoLists(node1, node4);
        System.out.println(newList);*/

        //测试回文链表
        node1.next = node2;//1->2 false
        //node2.next = node3;
       // node3.next = node4;//1->2->2->1 true

        //测试思路1
        //boolean res = isPalindrome(node1);
        //System.out.println(res);


        MergeTwoLists test = new MergeTwoLists();

        //测试思路2
        //boolean res = test.isPalindrome02(node1);
       // System.out.println(res);

        //测试思路3
        boolean res = test.isPalindromeList(node1);
        System.out.println(res);

    }
    //输入:1->2->4, 1->3->4
    //输出:1->1->2->3->4->4
    public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }

        ListNode tmp1 = l1;
        ListNode tmp2 = l2;

        ListNode newHead = new ListNode(-1);//新链表的头节点
        ListNode cur = newHead;//总是指向新链表的最后一个结点,方便插入新结点

        while (tmp1 != null && tmp2 != null) {
            if (tmp1.val <= tmp2.val) {
                cur.next = tmp1;
                tmp1 = tmp1.next;//这两条语句使得当前需要插入的结点插入到新链表末尾并与l1断链
            } else {
                cur.next = tmp2;
                tmp2 = tmp2.next;// 这两条语句使得当前需要插入的结点插入到新链表末尾并与l2断链
            }

            cur = cur.next;//总是指向新链表的最后一个结点,方便插入新结点

        }

        //将非空的那一个链表 tmp1或者tmp2 与新链表的末尾 连接
        cur.next = (tmp1 != null)? tmp1:tmp2;

        //头结点是我们用来方便插入的
        return newHead.next;
    }

    //判断一个链表是否是回文链表
    //输入: 1->2
    //输出: false
    //输入: 1->2->2->1
    //输出: true

    //思路1:直接将链表的每个数字取出来放到列表中,然后使用双指针法判断是否为回文链表
    //时间复杂度O(n),空间复杂度为O(n)
    public static boolean isPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }
        ListNode tmp = head;
        List<Integer> vals = new ArrayList<>();

        while (tmp != null) {
            vals.add(tmp.val);
            tmp = tmp.next;
        }

        int i = 0;
        int j = vals.size() - 1;
        while (i < j) {
           if (vals.get(i).equals(vals.get(j))) {// 注意!!!这里get方法返回的是Integer类型,不能直接用==比较
               i ++;
               j --;
           } else {
               return false;
           }
        }

        return true;
    }

    //思路2:使用递归,定义一个curNode递归指向链表尾部,一个frontNode指向链表头部
    //递归回溯时(也就是curNode到达链表末尾时),比较curNode.val是否等于frontNode.val
    //相等-->frontNode指向下一个结点,curNode继续 回溯
    //不相等则返回false
    ListNode frontNode;
    public boolean recursionCheck(ListNode curNode) {
        //当curNode指向链表最后一个结点时,curNode.next == null,不在进入此 if 语句,跳到程序末尾return true
        //这是回文最基本的情况,当为空时,是回文链表
        if (curNode != null) {
            //curNode递归指向链表尾部
            if (!recursionCheck(curNode.next)) {
                return false;
            }

            //递归回溯时(也就是curNode到达链表末尾时),比较curNode.val是否等于frontNode.val
            //不相等则返回false
            if (frontNode.val != curNode.val) {
                return false;
            }

            //相等-->frontNode指向下一个结点,curNode继续 回溯
            frontNode = frontNode.next;
        }

        return true;
    }

    public boolean isPalindrome02(ListNode head) {
        if (head == null) {
            return true;
        }

        frontNode = head;//frontNode指向链表头部

        return recursionCheck(head);//curNode递归指向链表尾部
    }

    //思路3:我们希望空间复杂度为O(1), 这时我们只能在链表本身上比较,回文就是前面一半 和 后面一半相同
    //容易想到,找到链表前半部分的尾结点,反转后半部分的链表,然后判断是否为回文
    //回复链表为原样
    public boolean isPalindromeList(ListNode head) {
        if (head == null) {
            return true;
        }

        ListNode firstHalfEndNode = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEndNode.next);

        ListNode p1 = head;
        ListNode p2 = secondHalfStart;

        boolean result = true;
        while (result && p2 != null) {
            if (p1.val == p2.val) {
                p1 = p1.next;
                p2 = p2.next;
            } else {
                result = false;
            }
        }

        //还原链表
        firstHalfEndNode.next = reverseList(secondHalfStart);
        //返回结果
        return result;
    }

    //找到前半部分的尾结点,使用快慢指针若链表有奇数个节点,则中间的节点应该看作是前半部分。
    public ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //快指针走两步,慢指针走一步,快指针到达末尾时,慢指针刚好是前半部分的尾结点
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }

        return slow;
    }

    //反转后半部分的结点
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode tmpNext = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmpNext;
        }

        return pre;
    }


}

class ListNode {
    int val;
    ListNode next;
    public ListNode() {

    }

    public ListNode(int val) {
        this.val = val;
    }

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }

    @Override
    public String toString() {
        return "ListNode{" +
                "val=" + val +
                ", next=" + next +
                '}';
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值