刷题笔记-链表相关

1. 反转链表

输入一个链表,反转链表后,输出新链表的表头。
  分析:初始时,将 preN 指向 nullptr,curN 指向链表首部,提前记录好链表的下一个节点。为了反转链表,要将 curN 的 next 指针指向 preN。

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode* preN = nullptr, *curN = nullptr;
        while(pHead){
            curN = pHead;
            pHead = pHead->next;
            curN->next = preN;
            preN = curN;
        }
        return curN;
    }
};

2. 链表倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。
  分析:设置两个指向链表首部的指针,快指针先移动 k 步,随后快慢指针一起移动,直到快指针指向链表尾部后一个结点,此时慢指针指向的就是倒数第 k 个结点。

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode *fast = pListHead, *slow = pListHead;
        while(k--){
            if(!fast) return nullptr;
            fast = fast->next;
        }
        while(fast)
        {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

3. 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

//非递归版本
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        ListNode* head = new ListNode(0), *headptr = head;
        
        while(pHead1 && pHead2)
        {
            if(pHead1->val <= pHead2->val)
            {
                headptr->next = pHead1;
                pHead1 = pHead1->next;
            }
            else{
                headptr->next = pHead2;
                pHead2 = pHead2->next;
            }
            headptr = headptr->next;
        }
        
        headptr->next = pHead1?pHead1:pHead2;
        
        return head->next;
    }
};

//递归版本
/*
链接:https://www.nowcoder.com/questionTerminal/d8b6b4358f774294a89de2a6ac4d9337?answerType=1&f=discussion
来源:牛客网
*/

class Solution {
public:
 ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
 {
     if (!pHead1) return pHead2;
     if (!pHead2) return pHead1;
     if (pHead1->val <= pHead2->val) {
         pHead1->next = Merge(pHead1->next, pHead2);
         return pHead1;
     }
     else {
         pHead2->next = Merge(pHead1, pHead2->next);
         return pHead2;
     }
 }
};

4. 链表中环的入口结点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
  分析:第一个想法是将遍历到的节点指针一一添加到 set 中,第一个重复的节点就是环的入口结点了。
  判断链表中是否有环可以使用快慢指针,但怎么判断入口结点呢?快慢指针相遇前,快指针已经在环中转了至少 1 圈,而慢指针进入环内的第 1 圈就会与快指针相遇,也就是说快慢指针相遇时,快指针比慢指针多走了 n 个环(n>=1)。
在这里插入图片描述
  如图,假设链表起始节点 A 距环入口结点 B 长度为 X,而慢指针在环内走了长度 Y 后与快指针相遇在 C 节点(由前面的分析可知,环长度L>Y>=0)。在这个过程中慢指针走了 X+Y,快指针速度是慢指针的 2 倍,所以快指针走了 2X+2Y。这时由图我们可以推断出:X = nL+(C->B)。如果此时我们让快指针定位到起始结点,并以与慢指针同样的速度沿链表运动,则当快指针到达环入口结点 B 时,慢指针也恰好到达 B 点,快慢指针再次相遇。
  注意链表无环、链表起始节点即为环入口节点几种特殊情况。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
//解法一:用set记录已遍历过的节点
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        set<ListNode*> s;
        while(pHead){
            if(s.find(pHead)==s.end())
                s.insert(pHead);
            else break;
            pHead = pHead->next;
        }
        return pHead;
    }
};
//解法二:快慢指针
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(!pHead) return nullptr;
        ListNode* slow = pHead, *fast = pHead;
        while(1){
            slow = slow->next;
            if(!fast) return nullptr;//如果无环则退出
            fast = fast->next;
            if(!fast) return nullptr;
            fast = fast->next;
            if(fast==slow) break;
        }
        fast = pHead;
        while(1)
        {
            if(fast==slow) break;
            slow = slow->next;
            fast = fast->next;
        }
        return fast;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值