OJ——单链表练习题(二)

八、相交链表

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

有两种遍历方法

        一、先遍历两个链表算出长度,再将长度小的链表向后走两链表长度差个节点,

如图这时再开始同时遍历两个链表,如果中途cur1==cur2,那么两个链表就有叫点,返回cur1。cur1或cur2为空那么链表没有相交点。

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
    struct ListNode* cur1 = headA;
    int size1 = 0;
    struct ListNode* cur2 = headB;
    int size2 = 0;
    while (cur1)
    {
        size1++;
        cur1 = cur1->next;
    }
    while (cur2)
    {
        size2++;
        cur2 = cur2->next;
    }
    if (size1 < size2)
    {
        cur1 = headB;
        cur2 = headA;
        int tmp = size1;
        size1 = size2;
        size2 = tmp;
    }
    else
    {
        cur1 = headA;
        cur2 = headB;
    }
    for (int i = 0; i < size1 - size2; i++)
    {
        cur1 = cur1->next;
    }
    while (cur1 && cur2)
    {
        if (cur1 == cur2)
        {
            return cur1;
        }
        cur1 = cur1->next;
        cur2 = cur2->next;
    }
    return NULL;
}

        二、先判断,两个链表一个为空直接返回NULL(没有节点),然后同时遍历两个链表,遍历到下一个节点为NULL时,直接开始遍历另一个链表,两个链表都是。

情况一:A和B节点个数不同。如图cur1遍历完A后开始遍历B,可以想象一下在想后走一个节点,cur1到了b2,cur2到了a1,在向后走如果有交点如c1那么它们会相交,没有交点它们也会同时走完到NULL。

情况二:A和B节点个数相同。那么就不需要重新遍历另一个链表,遍历时的情况也和长度不同时遍历第二遍的情况相同。它们都会相交,这也是判断结束的条件。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if (headA == NULL || headB == NULL) {
        return NULL;
    }
    struct ListNode *pA = headA, *pB = headB;
    while (pA != pB) {
        pA = pA == NULL ? headB : pA->next;
        pB = pB == NULL ? headA : pB->next;
    }
    return pA;
}

九、环形链表

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

        这道题的解法是快慢指针,快慢指针往前走,fast为空或fast的下一个节点为空,那这个链表必然不是环形。在遍历链表时,fast的速度是slow的两倍,当fast入环时,slow走到了头节点和入环节点的中间。

继续向后走,slow入环,fast肯定在环中。假设这时fast和slow之间有n个节点,而slow每次走一个节点,fast每次走两个节点,每次循环之后它们的节点个数都会-1(n--),那么在slow走到下一圈前fast和slow肯定会相遇。

bool hasCycle(struct ListNode* head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast != NULL && fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)
            return true;
    }
    return false;
}

十、环形链表2

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

        这道题首先要判断这个链表是不是环形,可以直接使用上面的代码,在fast和slow相遇后就可以找入环节点了。

设:这时头节点到入环节点距离为L,入环节点到fast和slow相遇的节点距离为x,环一圈为C,而fast在环中已经走了n*C+x(n圈+x)

fast的距离有是slow的二倍,L+n*C+x=2*(L+x),化简得L=n*C-x。

slow的距离又是L+x,n*C是整圈数,那么slow再走L刚好就是入环节点。所以我们再使用一个指针和slow一起走,当它们相遇时就是入环节点。

typedef struct ListNode Node;
struct ListNode *detectCycle(struct ListNode *head) {
    	Node* slow = head;
        Node* fast = head;

        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            //走到相遇点
            if(slow == fast)
            {
                // 求环的入口点
                Node* meet = slow;
                Node* start = head;

                while(meet != start)
                {
                    meet = meet->next;
                    start = start->next;
                }

                return meet;
            }
        }

        return NULL;
}

十一、随机链表的复制

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

        遍历链表插入节点,在链表的每个节点后面插入一个相同val值的节点,插入节点的next指向当前的节点的next(当前节点的下一个节点),当前节点的next在指向插入的节点。

        再次遍历链表,将之前每个插入节点的random指向它前一个节点的random指向的那个节点的下一个节点(也是一个插入节点),如果前一个节点的random指向空那么插入节点的random直接指向空。

        最后再将插入的所有节点链接起来(只链接插入的节点),原节点重新链接回原本的样子。

返回插入的第一个节点。

struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)
        return NULL;
	struct Node* cur=head;
    while(cur)
    {
        struct Node* tmp=(struct Node*)malloc(sizeof(struct Node));
        tmp->val=cur->val;
        tmp->next=cur->next;
        cur->next=tmp;
        cur=tmp->next;
    }
    cur=head;
    while(cur)
    {
        if(cur->random==NULL)
            cur->next->random=NULL;
        else
            cur->next->random=cur->random->next;
        cur=cur->next->next;
    }
    struct Node* newhead=head->next;
    cur=head;
    //原链表节点的下一个节点不为空进入循环
    while(cur->next->next)
    {
        //创建的next表示原链表cur的下一个节点
        struct Node* next=cur->next->next;
        //插入节点的next指向原节点的下一个节点的插入节点
        cur->next->next=next->next;
        cur->next=next;
    }
    cur->next=NULL;
    return newhead;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值