单链表面试题——进阶篇

1.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。
判断是否带环:利用快慢指针,快指针每次走两步,慢指针每次走一步,如果快慢指针相遇,则该链表带环。

ListNode* IsHaveLoop(ListNode* plist)
{
    if (plist == NULL)
    {
        return NULL;
    }
    ListNode* fast = plist;
    ListNode* slow = plist;
    while (fast->next&&fast)
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
        {
            return slow;
        }
    }
    return NULL;
}

求环的长度:相遇之后,每次追一步,再次相遇刚好追一圈——环的长度。

int SizeofLoop(ListNode* plist)//求环长
{
    ListNode* meet = IsHaveLoop(plist);
    if (meet)
    {
        int count = 1;
        ListNode* tmp = meet->next;
        while (tmp != meet)
        {
            tmp = tmp->next;
            count++;
        }
        return count;
    }
    return 0;
}

求环入口点: T——尾长(非环长度),S——慢指针入环到被追上, C——快指针追慢指针多跑的圈。那么,慢指针走的路程为 T+S,快指针走的路程为 T+S+C,可得 2(T+S)=T+S+C,T=C-S,此时,一个指针从起点出发走T步,一个指针从快慢指针相遇点出发走 C-S 步,此时两指针刚好都在入口点。

ListNode* EnterNode(ListNode* plist) 
{
    ListNode* meet = IsHaveLoop(plist);
    if(meet)
    {
        while (meet != plist)
        {
            meet = meet->next;
            plist = plist->next;
        }
        return plist;
    }
    return NULL;
}

2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)

ListNode* Intersect(ListNode* pList1, ListNode* pList2)
{
    int count1 = 0, count2 = 0;
    ListNode* p1 = pList1, *p2 = pList2;
    while (p1->next)
    {
        count1++;
        p1 = p1->next;
    }
    while (p2->next)
    {
        count2++;
        p2 = p2->next;
    }
    if (p1 != p2)
    return NULL;
    if (count1 >= count2)
    {
        count1 -= count2;
        while (count1--)
            pList1 = pList1->next;
        while (pList1 != pList2)
        {
            pList1 = pList1->next;
            pList2 = pList2->next;
        }
        return pList1;
    }
    else
    {
        count2 -= count1;
        while (count2--)
            pList2 = pList2->next;
        while (pList1 != pList2)
        {
            pList1 = pList1->next;
            pList2 = pList2->next;
        }
        return pList1;
    }
}

3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
这里写图片描述

ListNode* Intersect(ListNode* plist1, ListNode* plist2)//判断链表是否相交升级版
{
    //先判断是否为空
    if ((plist1 == NULL) || (plist2 == NULL))
    {
        return NULL;
    }
    ListNode* enter1 = EnterNode(plist1);
    ListNode* enter2 = EnterNode(plist2);
    //1和2:若两个链表都无环,则直接用题目二的函数解决
    if ((enter1 == NULL) && (enter2 == NULL))
    {
        return IsListIntersect(plist1, plist2);
    }
        //4:若一个有环,一个无环,则不想交,返回NULL
       else if ((enter1 == NULL) && (enter2 != NULL) || (enter1 != NULL) && (enter2 == NULL))
    {
        return NULL;
    }
    //3: 若入口点相同都在尾巴,去掉环,转化成无环相交问题
    else if (enter1 == enter2)
    {
        enter1->next = NULL;
        enter2->next = NULL;
        return IsListIntersect(plist1, plist2);
    }
    //6 :同环,两个入口点  一个入口点开始遍历一圈,看环上是否有另一个入口点  
        // 找到则返回plist1的入口点  
    else
    {
        ListNode* tmp = enter1->next;
        while (tmp != enter1)
        {
            if (tmp == enter2)
            {
                return enter1;
            }
            tmp = tmp->next;
        }
        return NULL;
    }
}

4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

这里写图片描述
这里写图片描述
这里写图片描述

ComplexNode* CopyList(ComplexNode* plist)
{
    if (plist == NULL)
    {
        return NULL;
    }
    ComplexNode* newnode = NULL;
    ComplexNode* tmp = plist;
    //1.1 插入节点
    while (tmp != NULL)
    {
        newnode = (ComplexNode*)malloc(sizeof(ComplexNode));
        newnode->_data = tmp->_data;
        newnode->_next = tmp->_next;
        newnode->_random = NULL;
        tmp->_next = newnode;
        tmp = tmp->_next->_next;
    }
    //1.2开始连接random
    tmp = plist;
    newnode = plist->_next;
    while (tmp != NULL)
    {
        if (tmp->_random != NULL)
        {
            newnode->_random = tmp->_random->_next;
        }
        tmp = tmp->_next->_next;
        if (tmp)
        {
            newnode = tmp->_next;
        }
    }
    //2.分离两个链表
    ComplexNode* res = plist->_next;
    tmp = plist;
    tmp->_next = tmp->_next->_next;
    tmp = tmp->_next;
    newnode = plist->_next;
    while ((tmp->_next != NULL)&&(tmp != NULL))
    {
        newnode->_next = newnode->_next->_next;
        tmp->_next = tmp->_next->_next;
        tmp = tmp->_next;
        newnode = newnode->_next;
    }
    return res;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双链表是一种常见的数据结构,它与单链表相比,每个节点除了包含指向下一个节点的指针外,还包含指向前一个节点的指针。这样的设计使得双链表可以在O(1)的时间复杂度内实现在任意位置的插入和删除操作。 以下是一些关于双链表的面试题及其解答: 1. 如何实现双链表的插入操作? 双链表的插入操作需要修改前后节点的指针指向。具体步骤如下: - 创建一个新节点,并将其next指针指向要插入位置的节点。 - 将新节点的prev指针指向要插入位置的前一个节点。 - 将要插入位置的前一个节点的next指针指向新节点。 - 将要插入位置的节点的prev指针指向新节点。 2. 如何实现双链表的删除操作? 双链表的删除操作需要修改前后节点的指针指向。具体步骤如下: - 将要删除的节点的前一个节点的next指针指向要删除节点的下一个节点。 - 将要删除的节点的下一个节点的prev指针指向要删除节点的前一个节点。 3. 如何实现双链表的反转操作? 双链表的反转操作需要修改每个节点的prev和next指针。具体步骤如下: - 遍历双链表,将每个节点的prev指针和next指针进行交换。 - 最后将头节点和尾节点的指针进行交换。 4. 如何判断一个链表是否是循环双链表? 循环双链表是指尾节点的next指针指向头节点,头节点的prev指针指向尾节点。可以通过遍历链表,判断尾节点的next指针是否指向头节点,头节点的prev指针是否指向尾节点来判断。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值