回文链表

这个题目值得专门记一笔,其中有一个点(对我而言)实在是很精妙,颇有茅塞顿开之感。我觉得可以算是双指针这一块比较灵性的写法了。

其实判断回文数没什么难度,有各种各样的方法,但是把回文数放进链表里就不一样了。我感觉链表的一个特点就是局部性,每次只能知道下一个元素,不像数组一样能掌控全局,相对来说信息量比较少(所以为了更多的信息量,就有了双向链表);数组和链表一个全局一个局部,正好构成了数据结构的最基本的元素。

因为链表本身的特点,倒序遍历是不可行的,一开始不知道结尾在哪,就不能用头尾双指针来做。所以我一开始想到的办法是最简单的那种,顺序遍历的时候拿个数据结构把一路上遇到的东西存下来,然后再逆序,看看一不一样。在这个场景下,字符串就是一个挺好的容器:

bool isPalindrome(ListNode *head)
{
    string store;
    while (head)
    {
        store += head->val;
        head = head->next;
    }
    string copy = store;
    reverse(store.begin(), store.end());
    return store == copy;
}

这个好是好,但是总觉得有点美中不足。因为还是之前说的那个问题,能不能利用这个结构本身的特点,而不是一味去线性地思考问题。一开始想着能不能构造一个环,这也是链表中比较常见的特殊结构,但是在这里好像不太行。如果反转链表吧,那还不如直接拿个容器来存呢。后来看了看题解,看到一个我觉得很精妙的写法。当然了,这是“意译”过来的(看完题解之后自己写的):

bool isPalindrome(ListNode *head)
{
    ListNode *slow = head;
    ListNode *slow_next = nullptr;
    ListNode *fast = head;
    while (fast && fast->next)
    {
        fast = fast->next->next;

        ListNode *temp = slow->next;
        slow->next = slow_next;
        slow_next = slow;
        slow = temp;
    }
    // 这个很重要,通过fast是否结束来判断长度是奇数还是偶数
    if (fast)
    {
        slow = slow->next;
    }
    while (slow && slow_next)
    {
        if (slow_next->val != slow->val)
        {
            return false;
        }
        slow_next = slow_next->next;
        slow = slow->next;
    }
    return true;
}

思路很简单,通过快慢指针,找到整个链表的中点。但是这里有两个特殊的地方,第一个是一边遍历一边反转,这样找到中点之后直接next就行;第二个是对奇偶数的处理,因为对于回文来说,长度为奇数和长度为偶数的情况是不一样的。所以这里的处理就很巧妙,根据快指针是否指向nullptr来判断奇偶:

if (fast)
{
    slow = slow->next;
}

其他的一些简单题没什么写头,先这样吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值