• 【数据结构】——链表经典OJ(leetcode)


    一、 相交链表

    在这里插入图片描述
    双指针

    struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
        struct ListNode* curA = headA;
        struct ListNode* curB = headB;
        int lenA = 1,lenB = 1;
        while(curA->next)
        {
            curA = curA->next;
            lenA++;
        }
        while(curB->next)
        {
            curB = curB->next;
            lenB++;
        }
        //终点相同才能进行下一步
        if(curB != curA)
        {
            return NULL;
        }
        //假设法
        //长的先走
        int gap = abs(lenA - lenB);
        struct ListNode* longlist = headA;
        struct ListNode* shortlist = headB;
        if(lenB>lenA)
        {
            longlist = headB;
            shortlist = headA;
        }
        while(gap--)
        {
            longlist = longlist->next;
        }
        while(shortlist != longlist)
        {
            shortlist = shortlist->next;
            longlist = longlist->next;
        }
        return shortlist;
    }
    

    二、 反转链表

    在这里插入图片描述

    注意第一个节点的next要为空

     typedef struct ListNode ListNode;
    struct ListNode* reverseList(struct ListNode* head) {
        if(head == NULL)
        {
            return head;
        }
        ListNode* n1,* n2, *n3;
        n1 = NULL;
        n2 = head;
        n3 = n2->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if(n3)
            {
                n3 = n3->next;
            }
        } 
        return n1;
    
    }
    

    三、 回文链表

    在这里插入图片描述
    这题两个选择,反转前半部分再对比,或者反转后半部分再对比
    如果反转前半部分,那么找中间值的条件就为fast->next && fast->next->next不为空,我选择反转后半部分,相对更容易理解
    反转的部分参考反转链表

     typedef struct ListNode ListNode;
     ListNode* reverse(ListNode* head)
     {
         if(head == NULL)
        {
            return head;
        }
        ListNode* n1,* n2, *n3;
        n1 = NULL;
        n2 = head;
        n3 = n2->next;
        while(n2)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if(n3)
            {
                n3 = n3->next;
            }
        } 
        return n1;
     }
    bool isPalindrome(struct ListNode* head) {
        //先找到中间节点
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        
        //反转后一半节点
        ListNode* p = reverse(slow);
        ListNode* q = head;
        //对比
        while(q != slow)
        {
            if(q->val != p->val)
            return false;
            q = q->next;
            p = p->next;
        }
        return true;
    }
    

    四、 环形链表

    在这里插入图片描述
    快慢指针:用fast先走,等fast进圈后再去追slow

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

    五、 环形链表 II

    在这里插入图片描述
    先看代码,这题的代码很简单,但是要明白所以然

     typedef struct ListNode ListNode;
    struct ListNode *detectCycle(struct ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if(slow == fast)
            {
                ListNode* meet = slow;
                while(head != meet)
                {
                    head = head->next;
                    meet = meet->next;
                }
                return head;
            }
        }
        return NULL;
    }
    

    在这里插入图片描述
    当fast和slow相遇后,我们将meet点设为新的起点,然后head点和meet点往后走,终究会相遇,相遇的点就是环的入口。
    在这里插入图片描述

    六、 合并两个有序链表

    在这里插入图片描述
    这题需要注意返回新链表的头节点,所以新链表创建两个节点来记录头和尾节点最方便

    typedef struct ListNode ListNode;
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
        ListNode* l1 = list1;
        ListNode* l2 = list2;
        //判断链表为空
          if(l1 == NULL)
        {
            return l2;
        }
        if(l2 == NULL)
        {
            return l1;
        }
        //创建新的链表
        ListNode* newhead,* newtail;
        newhead = newtail = (ListNode*)malloc(sizeof(ListNode));
      
        while(l1 && l2)
        {
            if(l1->val < l2->val)
            {   //l1尾插
                newtail->next = l1  ;
                newtail = newtail->next;
                l1 = l1->next;
            }
            else
            {  //l2尾插
                newtail->next = l2;
                newtail = newtail->next;
                l2 = l2->next;
            }
        }//跳出循环后还有两种情况,不是l1走到空,就是l2先走到空
        if(l1)
        {
            newtail->next = l1;
        }
        if(l2)
        {
            newtail->next = l2;
        }
        //手动释放动态内存空间
        ListNode* ret = newhead->next;
        free(newhead);
        newhead = NULL;
        return ret;
    }
    

    七、 两数相加

    在这里插入图片描述
    这题使用递归的方法最好理解

     typedef struct ListNode ListNode;
    ListNode* _addTwoNumbers(ListNode* l1,ListNode* l2,int cur)
    {
        int sums = cur;
        if(l1 == NULL && l2 == NULL && cur == 0)
        {
            return NULL;
        }
        else{
            if(l1 != NULL)
        {
            sums += l1->val;
            l1 = l1->next;
        }
            if(l2 != NULL)
        {
            sums += l2->val;
            l2 = l2->next;
        }
        }
       
        ListNode* a = (ListNode*)malloc(sizeof(ListNode));
        a->val = sums%10;
        a->next = _addTwoNumbers(l1,l2,sums/10);
        return a;
    }
    struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
        return _addTwoNumbers(l1,l2,0);
    }
    

    cur为进位值,所以和就为l1->val+l2->val+cur
    在这里插入图片描述
    判断cur是防止极端情况的发生,例如:
    在这里插入图片描述

    八、 删除链表的倒数第N个节点

    在这里插入图片描述

    先记录链表长度,再找到要删除节点的上一个节点

    struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
        int length = 1;
        struct ListNode* p = head;
        struct ListNode* q = head;
        //记录链表长度
        while(p->next)
        {
            p = p->next;
            length++;
        }
        int del = length - n + 1;
        int j = 1;
        //找到要删除节点的上一个节点
        while(j + 1 < del)
        {
            q = q->next;
            j++;
        }
        if(del != 1)
        {
            q->next = q->next->next;
            return head;
        }
        else
        {
            return head = q->next;
        }
    
    }
    

    九、 随机链表的复制

    在这里插入图片描述
    创建一个copy链表

    在这里插入图片描述

    在这里插入图片描述
    再控制random
    在这里插入图片描述
    把copy取出尾插为新的链表(恢复原链表)
    在这里插入图片描述
    源代码:

    typedef struct Node Node;
    struct Node* copyRandomList(struct Node* head) {
    	Node* cur = head;
        //创建copy链表
        while(cur)
        {
            Node* copy = (Node*)malloc(sizeof(Node));
            copy->val = cur->val;
            copy->next = cur->next;
            cur->next = copy;
            cur = copy->next;
        }
        //完善random 
        cur = head;   
        while(cur)
        {
            Node* copy = cur->next;
            if(cur->random == NULL)
            {
                copy->random = NULL;
            }
            else
            {
                copy->random = cur->random->next;
            }
            cur = copy->next;
        }
        //copy取出尾插成为新的链表
        cur = head;
        Node* copyhead = NULL;
        Node* copytail = NULL;
        while(cur)
        {
            Node* copy = cur->next;
            Node* next = copy->next;
            if(copyhead == NULL)
            {
                copyhead = copytail = copy;
            }
            else
            {
                copytail->next = copy;
                copytail = copy;
            }
            //cur->next = next;
            cur = next;
            next = copy->next;
        }
        return copyhead;
    }
    
  • 相关阅读:
    华为交换机debug icmp数据包
    20天深度复习JavaSE的详细笔记(十九)——单元测试、反射、注解
    学习虚幻C++开发日志——基础案例(持续更新中)
    C++ explicit关键字的作用
    C. Bouncing Ball(从后往前的前缀和)
    精华!一张图进阶 RocketMQ
    密码CTF(4)——e和phi不互素
    WPF中以MVVM方式,实现RTSP视频播放
    【图论——第十讲】匈牙利算法实现二分图的最大匹配
    MATLAB算法实战应用案例精讲-【数模应用】欧氏距离(附MATLAB、Java、Python和R语言代码)
  • 原文地址:https://blog.csdn.net/super_coders/article/details/139902956