剑指offer专题——链表(持续更新)

剑指offer 03——从尾到头打印链表

题目描述

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

输入
{67,0,24,58}
返回值
[58,24,0,67]

解题思路

使用递归

代码

void PrintOP(ListNode* node, vector<int> &res) {
    if(!node)
        return;
    PrintOP(node->next, res);
    res.push_back(node->val);
}

vector<int> printListFromTailToHead(ListNode* head) {
    vector<int> res;
    PrintOP(head, res);
    return res;
}

剑指offer 14——链表中倒数第K个节点

题目描述

输入一个链表,输出该链表中倒数第k个结点。
如果该链表长度小于k,请返回空。

输入
{1,2,3,4,5},1
返回值
{5}

解题思路

快慢指针
快指针先向后走k步
快慢指针每次各走一步
快指针为空,返回满指针

代码

ListNode* FindKthToTail(ListNode* pHead, int k) {
    // write code here
    if(!pHead) return pHead;
    ListNode* fast = pHead;
    ListNode* slow = pHead;
    while(k-- && fast){
        fast = fast -> next;
    }
    //k大于链表长度返回空值
    if(k >= 0) return nullptr;
    while(fast){
        fast = fast -> next;
        slow = slow -> next;
    }
    return slow;
}

剑指offer 15——反转链表

题目描述

输入一个链表,反转链表后,输出新链表的表头。

输入
{1,2,3}
返回值
{3,2,1}

解题思路

三指针法

代码

ListNode* ReverseList(ListNode* pHead) {
    if(!pHead) return nullptr;
    ListNode* pre = nullptr;
    ListNode* cur = pHead;
    ListNode* next = nullptr;
    while(cur){
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}

剑指offer 16——合并两个排序的链表

题目描述

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

输入
{1,3,5},{2,4,6}
返回值
{1,2,3,4,5,6}

解题思路

定义一个前驱节点(哨兵)和遍历节点,
遍历节点每次指向值最小的节点
当有一个链表为空跳出循环
遍历节点的next指向不为空的链表

代码

ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
	//哨兵节点
    ListNode* n1 = new ListNode(-1);
    ListNode* n2 = n1;
    while(pHead1 && pHead2) {
        if(pHead1 -> val < pHead2 -> val) {
            n2->next = pHead1;
            pHead1 = pHead1 ->next;
        }
        else {
            n2 -> next = pHead2;
            pHead2 = pHead2 -> next;
        }
        n2 = n2 -> next;
    }
    //指向仍有剩余节点的链表
    n2 ->next = pHead1 ? pHead1 : pHead2;
    return n1 -> next;
}

剑指offer 25——复杂链表的复制

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

解题思路

1.复制节点
2.复制节点random关系
3.断开原链表与复制链表
具体过程参考下面代码:

代码

RandomListNode* Clone(RandomListNode* pHead) {
    if(!pHead) return nullptr;
    RandomListNode* ret = nullptr;
    RandomListNode* node = pHead;
    //1.创建节点
    while(node) {
        RandomListNode* tmp = new RandomListNode(node->label);
        tmp->next = node->next;
        node->next = tmp;
        node = tmp->next;
    }
    node = pHead;
    //2.复制random关系
    while(node) {
    	//注意加上空结点的判断,否则会出现段错误
        node->next->random = node->random ? node ->random ->next : nullptr;
        node = node->next->next;
    }
    //3.断开链表,返回复制链表
    node = pHead;
    ret = pHead->next;
    while(node) {
        RandomListNode* tmp = node -> next;
        node -> next = tmp ? tmp -> next : nullptr;
        node = node -> next;
        tmp -> next = node ? node -> next : nullptr;
    }
    return ret;
}

剑指offer 36——两个链表的第一个公共节点

题目描述

输入两个链表,找出它们的第一个公共结点。

解题思路

设两个链表分别为L1、L2。表头节点为n1、n2。
n1和n2到公共节点的距离是不一定相等的,我们需要加以调整,使他们到公共节点的距离一致
具体操作:A尾节点指向B头,B尾节点指向A头,这样他们第二次一定会相遇。
在这里插入图片描述

代码

ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
    ListNode *n1 = pHead1, *n2 = pHead2;
    while(n1 != n2){
        n1 = n1 ? n1 -> next : pHead2;
        n2 = n2 ? n2 -> next : pHead1;
    }
    return n1;
}

剑指offer 55——链表中环的入口结点

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

解题思路

快慢指针
快指针、慢指针同时指向头节点,快指针一次走两步,慢指针一次走一步
相遇后,快指针指向头节点,然后快慢指针每次走一步,第二次相遇的点即为环的入口节点

代码

ListNode* EntryNodeOfLoop(ListNode* pHead)
{
    ListNode* fast = pHead;
    ListNode* slow = pHead;
    //快指针每次两步,慢指针每次一步
    while(fast && fast->next){
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow) break;
    }
    //是否有环判断
    if(!fast || !fast->next) return nullptr;
    fast = pHead;
    //如果有环,就一定能找到进入节点
    while(fast != slow){
        fast = fast->next;
        slow = slow->next;
    }
    return fast;
}

剑指offer 56——删除链表中的重复节点

题目描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

输入
{1,2,3,3,4,4,5}
返回值
{1,2,5}

解题思路

直接删除法
在遍历单链表的时候,检查当前节点与下一点是否为相同值,如果相同,继续查找祥同值的最大长度,然后指针改变指向。

代码

ListNode* deleteDuplication(ListNode* pHead) {
    //哨兵结点
    ListNode* vHead = new ListNode(-1);
    vHead -> next = pHead;
    ListNode* pre = vHead, *cur = pHead;
    while(cur){
        //找相同的连续结点
        if(cur->next && cur->val == cur->next->val) {
            cur = cur -> next;
            while(cur->next && cur ->val == cur ->next->val) {
                cur = cur -> next;
            }
            //当前不等于下一个,因此继续后移一位
            cur = cur -> next;
            pre ->next = cur;
        }
        else {
            pre = cur;
            cur = cur -> next;
        }
    }
    return vHead -> next;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值