LeetCode初级算法之链表: 回文链表

回文链表

请判断一个链表是否为回文链表。

示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

思路一: 借助外来的空间

这个题我的初步思路是借助外来的空间,也就不是O(1)的空间复杂度,那么这个就比较简单了,只需要遍历一遍链表,把每个元素存入到数组中,然后看看是不是回文数组就可以了,数组的优势就是内存连续,查找方便,这个就不多解释了,直接上代码

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> v;
        ListNode *p = head;
        while(p)
        {
            v.push_back(p->val);
            p = p->next;
        }

        for (int i=0,j=v.size()-1; i<=j;i++,j--)
        {
            if (v[i]!=v[j])
                return false;
        }
        return true;
    }
};

这个速度还是比较快的。但是空间复杂度O(n),毕竟弄了一个数组。

思路二: 快慢指针找中点

这个思路是借鉴人家的一个思路,使用快慢指针,竟然可以找到链表的中点,这个之前是不知道的,这次学到了,就是两个指针开始的时候,都指向第一个元素,之后,往前走,快的指针一次走两步,慢的指针一次走一步,这样的话当快的走到头的时候,慢的正好走到中点位置。 这个想法简直是太好了。 这个题就可以使用这个思想。
就是先找到中点,然后前面的部分逆置,然后前面的一半和后面的一半再比较。这样的话,空间复杂度就是O(1)了。

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head || !head->next) return true;
        
        ListNode *slow = head;
        ListNode *fast = head;
        ListNode *pre=head, *prepre=NULL;
        
        // 快慢指针遍历找中点的同时,把前半部分进行逆置
        while (fast && fast->next)
        {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
            
            pre->next = prepre;
            prepre = pre;
        }
        
        // 如果是奇数个节点,这时候fast正好是不为空,此时,slow正好是中间位置,需要往后移动一下
        if (fast)
            slow = slow->next;
        
        // 下面就可以开始比较了,前半部分是pre指向,后半部分是slow指向,如果不一样的话,就不是回文串
        while (pre && slow)
        {
            if (pre->val != slow->val)
                return false;
            pre = pre->next;
            slow = slow->next;
        }
        return true;
        
    }
};

python代码:

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        
        dummy = ListNode(-1)
        dummy.next = None
        
        fast = slow = head
        
        while fast and fast.next:
            temp = slow
            slow = slow.next
            fast = fast.next.next
            
            temp.next = dummy.next
            dummy.next = temp
        
        if fast:
            slow = slow.next
        
        p = dummy.next
        while p and slow:
            if p.val != slow.val:
                return False
            p = p.next
            slow = slow.next
        
        return True

这个快慢指针的思想值得借鉴,见后面的总结。

总结 - 神奇的快慢指针

最后稍微总结一下:快慢指针

  • 在删除倒数第n个数的时候用到了,就是让快指针走到第n个位置之后,然后快慢指针同行往后走,当快指针到达终点的时候,慢指针正好在倒数的第n个位置。
  • 找链表的中点的时候也用到了,以此类推的话可能找分位点的时候是不是都可以用到(调整步长?),这一个感觉是挺好的一种思想,之前真的是没想到过如何去找链表的中点,总觉得是遍历一遍数个数,然后除以2,但是没想到这种方法一次就可以找到。回文链表
  • 环形链表用到了。判断一个链表有没有环,竟然可以一个快指针一个慢指针互相追赶的方式,真的是神奇。
发布了66 篇原创文章 · 获赞 67 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wuzhongqiang/article/details/103336242