关于LeetCode中Palindrome Linked List一题的理解

来源:互联网 发布:网络流行照片 编辑:程序博客网 时间:2024/06/07 02:37

题目如下:

Given a singly linked list, determine if it is a palindrome.

Follow up:
Could you do it in O(n) time and O(1) space?

    题目还是很简单,判断一个链表是不是“回文链表”。然后稍微难一点的是是否能够用O(n)的时间复杂度和O(1)空间复杂度完成这个方法?最容易想到的还是将链表转化成数组,然后判断一个数组是不是“回文数组”就非常容易了。这种思路太简单了,不多说,但是相当费时,直接放代码了,感觉是刚刚达到Accepted时间线的一个方法。

<span style="font-size:14px;">    public boolean isPalindrome(ListNode head) {        ArrayList<Integer> num_array = new ArrayList<Integer>();        while(head!=null){            num_array.add(head.val);            head = head.next;        }        int i=0;        int j=num_array.size()-1;        while(j>=0 && i<=j){            if(num_array.get(i).intValue() != num_array.get(j).intValue()){                return false;            }            i++;            j--;        }        return true;    }</span>
    上面那种方法还是太LOW了一些,所以按例还是介绍评论区真正的高大上方法。这个方法的中心思想是将链表的前半段进行reverse操作,然后将reverse操作后的前半段链表和后半段链表节点的val值进行一一比对,如果所有节点的值都相同,说明原链表是“回文链表”,输出true即可,反之则输出false。难点有两个,一个是怎么找到原链表的中间节点,另一个就是链表的reverse操作。第一个问题可以通过新建一个移动速度是原指针两倍的指针,这样在这个指针移动到链表末尾的时候,原指针应该刚好移动到一半或者一半+1的位置,这和节点数的奇偶有关系。另一个问题其实没有什么好的解决方法,就是要通过新建三个指针,通过对改变这三个指针的位置关系来实现链表的reverse。等会可以通过分析一下具体的例子来观察这三个指针的作用,那先上代码。当然了,这些代码之前我都在LeetCode上跑过,肯定是可以Accepted的,代码如下:

<span style="font-size:14px;">    public boolean isPalindrome(ListNode head) {         if(head == null) {            return true;        }        ListNode p1 = head;        ListNode p2 = head;        ListNode p3 = p1.next;        ListNode pre = p1;        //find mid pointer, and reverse head half part        while(p2.next != null && p2.next.next != null) {            p2 = p2.next.next;            pre = p1;            p1 = p3;            p3 = p3.next;            p1.next = pre;        }        //odd number of elements, need left move p1 one step        if(p2.next == null) {            p1 = p1.next;        }        else {   //even number of elements, do nothing                    }        //compare from mid to head/tail        while(p3 != null) {            if(p1.val != p3.val) {                return false;            }            p1 = p1.next;            p3 = p3.next;        }        return true;    }</span>
    其他的过程都不详细说了,单独举个例子分析一下reverse的过程。比如现在有一个链表1(N1)->2(N2)->3(N3)->2(N4)->1(N5),开始时p1指向的是N1位置,p3的位置是p1的next即N2位置,pre和p1都指向N1。

第一次循环:

将p1的值赋给pre,pre和p1都指向N1;

将p3的值赋给p1,这样p3和p1都指向N2,此时pre的next指向的也是N2;

将p3的next赋值给p3,这样p3的位置变成了N3,此时pre的next指向的也是N3,即N1的next变为了N3;

将p1的next赋值给pre,这样N1就变成了N2的next;

现在的链表变成了2(N2)->1(N1)->3(N3)->2(N4)->1(N5)。

第二次循环:

由于上一次循环过后,p1其实指向的就是N2位置,所以经过赋值后,pre也指向了N2位置;

然后将p3的值赋给p1,p1指向了N3位置;

将p3指向p3的next即N4,由于原来N1指向的是p3所对应的N3,但现在N3变成了N4,所以N1就自动指向N4了;

最后将p1的next指向pre,即把N3的next变成N1;

现在的链表变成了3(N3)->2(N2)->1(N1)->2(N4)->1(N5)。

    之后的过程以此类推即可,难点主要是理解这种reverse方法。




0 0
原创粉丝点击