反转链表并插值

遇到一个面试题,大意是这样的:

希望对于链表 0,1,2,3,4,5,6

希望反转之后得到 0,6,1,5,2,4,3

对于链表 0,1,2,3,4,5, 反转之后得到 0,5,1,4,2,3

考虑O(n) 的时间复杂度和 O(1)的空间复杂度

思路

实际上很简单,只不过是反转链表的变式罢了

再回顾一下反转链表:

使用3个指针,一个指向前节点 pre, 一个指向当前节点cur, 一个指向下一节点next。

做以下循环:

  1. 获取 下一节点 next = cur.next
  2. 将当前节点反向 cur.next = pre
  3. 更新指针 pre = cur, cur = next

注意最后记得使头结点的next指向null, 否则会再头结点处留下一个环

代码如下:

LinkNode* reverse(LinkNode *phead){
    if(phead == nullptr){
        return nullptr;
    }

    LinkNode *pCur=phead->next, *pPre=phead, *pNext;
    while (pCur!=nullptr){
        pNext = pCur->next;
        pCur->next = pPre;
        pPre = pCur;
        pCur = pNext;
    }
    phead->next = nullptr;
    phead = pPre;
    return phead;
}

回到这个问题, 实际只是把后半截的部分反向,然后再添加到前半截处

所以思路大概如下:

  1. 找到整个链表的中间节点
  2. 通过中间节点把链表一分为二,并把后半部分反向
  3. 合并两个子链表,把第二个反向的链表中的节点插入到第一个链表中

整个过程不会新创建链表或占用新的存储空间,总共遍历了 N + N/2 + N/2 也就是O(n)的时间复杂度

LinkNode* reverse2(LinkNode *phead){
    if(phead == nullptr){
        return nullptr;
    }

    LinkNode *pSlow = phead, *pFast = phead;
    // 通过快慢指针,遍历1次找到中间节点
    while(pFast->next!=nullptr && pFast->next->next != nullptr){
        pSlow = pSlow->next;
        pFast = pFast->next->next;
    }
    // 将整个链表一分为二并且将后半部分反向
    LinkNode *pRev = pSlow->next, *pCur = phead, *pNext=pCur->next, *pRevNext;
    // 一分为二
    pSlow->next = nullptr;
    // 反转后半部分
    pRev = reverse(pRev); // 这个reverse实际就是前面的链表反转

    // 合并两个链表
    while(pRev!=nullptr && pNext!=nullptr){
        pRevNext = pRev->next;
        pNext = pCur->next;
        // 因为插入了一个节点,所以pCur需要移动两步才是原本插入前的下一节点
        pCur->next = pRev;
        pCur = pCur->next;
        pCur->next = pNext;
        pCur = pCur->next;
        pRev = pRevNext;
    }

    return phead;
}

最后结果:

prev link:-- 
 node 0
 node 5
 node 1
 node 4
 node 2
 node 3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃肉夹馍不要夹馍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值