一万五字的文章,超详细的画图,带你理解链表的基础和进阶题目(含快慢指针的讲解)

news2024/9/23 13:31:13

在今天的文章中,我将带来链表的面试题。在数据结构的学习过程中,画图是尤为重要的,所以在这些题目的讲解的过程中,我以画图为主。温馨提示:由于图片过大,手机观看可能出现模糊不清的情况,建议在电脑观看该篇文章(点击图片,Ctrl+鼠标滑轮看全图)。



目录

    • 1.移除链表的元素:[链接](https://leetcode.cn/problems/remove-linked-list-elements/description/)
    • 2.反转链表: [链接](https://leetcode.cn/problems/reverse-linked-list/description/)
    • 3.链表的中间结点[链接](https://leetcode.cn/problems/middle-of-the-linked-list/description/)
    • 4.链表中倒数第k个结点:[链接](https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking)
    • 5.合并两个有序链表:[链接](https://leetcode.cn/problems/merge-two-sorted-lists/description/)
    • 6.链表分割:[链接](https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking)
    • 7.链表的回文结构:[链接](https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking)
    • 8.相交链表:[链接](https://leetcode.cn/problems/intersection-of-two-linked-lists/description/)
    • 9.环形链表:[链接](https://leetcode.cn/problems/linked-list-cycle/description/)
    • 10.环形链表 II:[链接](https://leetcode.cn/problems/linked-list-cycle-ii/description/)
    • 11.复制带随机指针的链表:[链接](https://leetcode.cn/problems/copy-list-with-random-pointer/description/)
    • 其他链表题目:[牛客网](https://www.nowcoder.com/exam/oj) || [leetcode](https://leetcode.cn/tag/linked-list/problemset/)



1.移除链表的元素:链接

题目要求:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
请添加图片描述
如该题目的示例1,我们需要删除链表中的存储数值为6的结点,那么我们应该如何做呢?

在删除的过程中,头结点可能是我们要删除的目标,所以我们定义新的头结点NewHead,来更新链表。头结点NewHead赋值为NULL。
我们需要定义新的尾结点Ptail来更新新头结点的尾。尾结点Ptail赋值为NULL。
在删除链表的结点时,我们需要定义结点Next来存储要删除的结点的下一个结点的地址,以免找不到下一个结点。结点Next赋值为NULL。
我们要定义结点cur来遍历旧的链表。结点cur赋值为旧链表的头结点。

特殊情况:
当旧链表的最后一个结点被删除后,并且倒数第二个结点没有被删除,由于链表的next存储着下一个结点的地址,那么倒数第二个结点的next为野指针。因为旧链表倒数第一个结点被删除,所以旧链表倒数第二个结点就为新链表的尾指针,也就是赋值给Ptail,此时Ptail的next为野指针,那么Ptail的next要置为空指针。
当旧链表的所有的结点都要被删除时,那么Ptail一直没有被赋值,此时,Ptail的值为NULL,那么不能对Ptail进行解引用来修改next的值。(不能对空指针进行解引用)

思路1:
请添加图片描述
代码:

struct ListNode* removeElements(struct ListNode* head, int val)
{
    if(head == NULL)
        return NULL;
    struct ListNode* NewHead = NULL,*Ptail = NULL;
    struct ListNode* cur = head;
    while(cur != NULL)
    {
        struct ListNode* Next = cur->next;
        if(cur->val != val)                   //判断是否为要删除的结点
        {
            if(Ptail == NULL)                 //第一次对头指针NewHead和尾指针Ptail进行赋值
            {
                NewHead = Ptail = cur;
            }
            else                              //修改尾指针Ptail的next值和尾指针Ptail向后走
            {
                Ptail->next = cur;
                Ptail = Ptail->next;
            }
            cur = Next;
        }
        else                                 //删除结点
        {
            free(cur);
            cur = Next;
        }
    }
    if(Ptail)                               //如果Ptail不是空指针,那么将Ptail的next值改为NULL,防止野指针的存在
        Ptail->next = NULL;
    return NewHead;
}

思路2:

在前面的想法下,我进行改进,将NewHead、ptail指向NULL改为指向哨兵位,在加上哨兵位后,我们可以直接在哨兵位尾插结点,不用在判断Ptail是不是指向空指针后才进行尾插。
在前面的想法中,我们需要将尾结点Ptail的next置空,然而可能由于原来的链表的所有结点都被删除了,Ptail没有变化,一直指向空指针,所以在将尾结点的next置空前,需要判断Ptail是不是指向空指针。在加上哨兵位后,我们就不需要判断了,因为Pail一开始指向哨兵位,而不是空指针。

在加上哨兵位后,代码将被大大的优化。

请添加图片描述

代码:

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* cur = head;
    struct ListNode* guard,*Ptail;
    guard = Ptail = (struct ListNode*)malloc(sizeof(struct ListNode));
    while(cur != NULL)
    {
        if(cur->val != val)
        {
            Ptail->next = cur;
            Ptail = Ptail->next;
            cur = cur->next;
        }
        else
        {
            struct ListNode* Next = cur->next;
            free(cur);
            cur = Next;
        }
    }
    Ptail->next = NULL;
    struct ListNode* NewHead = guard->next;     //返回头结点,不要返回哨兵位
    free(guard);
    return NewHead;    
}     


2.反转链表: 链接

题目要求:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
请添加图片描述
如该题目的示例1,我们需要将把整个链表的结点给逆转过来。

思路1:

我们需要定义一个翻转链表后的头指针Rhead,初始化为NULL。
定义一个结点cur,遍历翻转前的链表。
定义一个结点next,存储着curr的下一个结点的地址。

请添加图片描述

代码:

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* cur = cur = head,*Rhead = NULL;
    while(cur != NULL)
    {
        struct ListNode* Next = cur->next;
        cur->next = Rhead;
        Rhead = cur;
        cur = Next;
    }
    return Rhead;
}

思路2:

定义三个结点n1、n2、n3,分别指向翻转前的链表的空指针、第一个结点、第二个结点,结点n3存储着结点n2的下一个结点,然后将结点n2的next值改为n1的地址,三个结点向后走,循环下去,直到结点n2指向空指针。

请添加图片描述
代码:

struct ListNode* reverseList(struct ListNode* head)
{
    if(head == NULL)                     //判断头指针非空,不然初始化n3时,存在着对空指针解引用的问题
        return NULL;
    struct ListNode* n1,*n2,*n3;
    n1 = NULL;
    n2 = head;
    n3 = n2->next;
    while(n2 != NULL)
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if(n2 != NULL)
            n3 = n2->next;
    }
    return n1;
}


3.链表的中间结点链接

题目要求:给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

请添加图片描述
如该题的示例1,我们找到中间结点,即存储的值为3的结点,将它做为新头指针并返回,那么我们应该怎么做呢?

使用快慢指针,定义两个指针分别是fast、slow,指针slow和指针fast都指向链表的头结点,指针slow每次往后走一步,指针fast每次往后走两步,当指针fast的next为NULL或者指针fast为NULL,指针slow分别指向中间结点或者第二个中间结点(在中间结点的个数为2个的时候)。

链表结点的个数为奇数时(链表只有一个中间结点):

请添加图片描述

链表的结点个数为偶数时(链表有两个中间结点):
请添加图片描述
代码:

struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode* slow,*fast;
    slow = fast = head;
    while(fast != NULL && fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}


4.链表中倒数第k个结点:链接

题目要求:输入一个链表,输出该链表中倒数第k个结点。
请添加图片描述
如示例1,我们需要找到链表的倒数第1个结点,也就是存储的数值为5的结点。

思路1:依然使用快慢指针,让快指针fast先走k步,再让快指针fast和慢指针slow一起往后走,当快指针fast指向空指针时,慢指针slow刚好指向链表中倒数第k个结点。

特殊情况:k可能过大,超过了链表的长度,导致快指针往后走的距离大于链表的长度,造成越界。

假设我要找到倒数第二个结点。
请添加图片描述
代码:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
    if(pListHead == NULL)
        return NULL;
    struct ListNode* slow,*fast;
    slow = fast = pListHead;
    while(--k)                    //k--总共循环k次,快指针fast往后走k步
    {
        fast = fast->next;
        if(fast == NULL)          //k的步长大于链表的长度
            return NULL;      
    }
    while(fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

思路2:依然使用快慢指针,让快指针fast先走k-1步,再让快指针fast和慢指针slow一起往后走,当快指针fast的next指向空指针时,慢指针slow刚好指向链表中倒数第k个结点。

假设我要找到倒数第二个结点。

请添加图片描述
代码:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
    if(pListHead == NULL)
        return NULL;
    struct ListNode* slow,*fast;
    slow = fast = pListHead;
    while(--k)                       //--k总共循环k-1次,快指针fast往后走k-1步
    {
        fast = fast->next;
        if(fast == NULL)            //k-1的步长大于链表的长度
            return NULL;
    }
    while(fast->next != NULL)       
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}


5.合并两个有序链表:链接

题目要求:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

请添加图片描述
如示例1,我们需要将两个链表按照从大到小的顺序和成一个新的链表。

思路1:题目中已经分别给出指向两个链表的头结点的指针,我们需要再定义指向新链表头结点的指针NewHead和指向新链表尾结点的指针Ptail,并初始化为NULL。遍历题目给的两个链表,谁存储的值小就先尾插到新链表。

特殊情况:当两个链表其中一个为空时,直接返回非空的链表。
在遍历的过程中,其中一个链表遍历完,而另外一个链表还没有遍历完,那么直接将没有遍历完的链表对应的结点尾插到Ptail,因为在上一条特殊情况的处理下,两个链表都是非空,那么程序就有进入下面代码的while循环,所以Ptail不可能是NULL,不用判断Ptail,直接尾插。
请添加图片描述
代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    if(list1 == NULL)
        return list2;
    if(list2 == NULL)
        return list1;
    struct ListNode* NewHead = NULL,*Ptail = NULL;
    while(list1 != NULL && list2 != NULL)
    {
        if(list1->val > list2->val)
        {
            if(Ptail == NULL)
            {
                NewHead = Ptail = list2;
            }
            else
            {
                Ptail->next = list2;
                Ptail = Ptail->next;
            }
            list2 = list2->next;
        }
        else
        {
            if(Ptail == NULL)
            {
                NewHead = Ptail = list1;
            }
            else
            {
                Ptail->next = list1;
                Ptail = Ptail->next;
            }
            list1 = list1->next;
        }
    }
    if(list1 != NULL)
        Ptail->next = list1;
    if(list2 != NULL)
        Ptail->next = list2;
    return NewHead;
}

思路2:加入哨兵位,那么在进入while循环进行第一次判断时,就不用判断Ptail是否指向空指针了,并且也不用判断两个链表都是非空的,如果有一个链表为空,直接尾插非空链表,因为Ptail指向哨兵位,Ptail不再是空指针。

请添加图片描述
代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    struct ListNode* guard,*Ptail;
    guard = Ptail = (struct ListNode*)malloc(sizeof(struct ListNode));
    if(guard == NULL)
    {
        perror("malloc fail");
        exit(1);
    }
    guard->next = NULL;
    while(list1 != NULL && list2 != NULL)
    {
        if(list1->val > list2->val)
        {
            Ptail->next = list2;
            Ptail = Ptail->next;
            list2 = list2->next;
        }
        else
        {
            Ptail->next = list1;
            Ptail = Ptail->next;
            list1 = list1->next;
        }
    }
    if(list1 != NULL)
        Ptail->next = list1;
    if(list2 != NULL)
        Ptail->next = list2;
    struct ListNode* NewHead = guard->next;
    free(guard);
    return NewHead;
}


6.链表分割:链接

题目要求:现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
请添加图片描述

如上面的链表中,我们要将小于3的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针,那么我们应该怎么做呢?

思路:定义一个指针,用来遍历题目给的链表。定义两个带哨兵位的新链表,一个尾插旧链表大于x的结点,一个尾插旧链表小于x、等于x的结点,最后,将存储大于x的结点的整个链表插到另外的存储着小于x、等于x的结点的链表的后面。

请添加图片描述
题目只要求小于x的结点排在其余结点之前,上面的图片修改一下,后面代码是正确的。

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) 
    {
        struct ListNode* greaterHead,*greaterTail = NULL;
        struct ListNode* LessHead,*LessTail = NULL;
        greaterHead = greaterTail = (ListNode*)malloc(sizeof(struct ListNode));
        LessHead = LessTail = (struct ListNode*)malloc(sizeof(struct ListNode*));
        greaterTail->next =LessTail->next = NULL;

        struct ListNode* cur = pHead;
        while(cur != NULL)
        {
            if(cur->val < x)
            {
                LessTail->next = cur;
                LessTail = LessTail->next;
            }
            else
            {
                greaterTail->next = cur;
                greaterTail = greaterTail->next;
            }
            cur = cur->next;
        }
        LessTail->next = greaterHead->next;
        greaterTail->next = NULL;
        struct ListNode* Phead = LessHead->next;
        free(greaterHead);
        free(LessHead);
        return Phead;
    }
};


7.链表的回文结构:链接

题目要求:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。回文结构的例子:1->2->2->1。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

思路:找到中间节点(链表个数为奇数)或者第二个中间结点(链表个数为偶数),反转该结点到尾结点的所有结点,将链表原来的头指针和反转后的头指针进行遍历前半段、后半段的链表,观察是不是链表的回文结构,详细看图。

链表结点个数为奇数的回文结构
请添加图片描述

链表结点个数为偶数的回文结构
请添加图片描述
代码:

class PalindromeList {
public:
    struct ListNode* FindMidNode(struct ListNode* Head)
    {
        struct ListNode* slow,*fast;
        slow = fast = Head;
        while(fast != NULL && fast->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    struct ListNode* ReverseList(struct ListNode* Head)
    {
        struct ListNode* cur = Head;
        struct ListNode* RHead = NULL;
        while(cur != NULL)
        {
            struct ListNode* Next = cur->next;
            cur->next = RHead;
            RHead = cur;
            cur = Next;
        }
        return RHead;
    }
    bool chkPalindrome(ListNode* A) 
    {
        struct ListNode* mid = FindMidNode(A);
        struct ListNode* Head = ReverseList(mid);
        while(Head->next != NULL)
        {
            if(A->val != Head->val)
                return false;
            
            A = A->next;
            Head = Head->next;
        }
        return true;
    }
};


8.相交链表:链接

题目要求:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回NULL。

请添加图片描述
如图片的情况,两个链表之间存在着相交结点,我们需要判断是否存在这种情况。

思路:先让两个链表找到各自的尾结点,并且在找尾结点的过程,记下两个链表的长度。找到尾结点后,判断两个尾结点是否相同,如果不相同,证明两个链表没有相交,相反就有相交(原因看上图)。在相交的情况下,我们就要找到交点,求出两个链表的长度之差,然后让长度较长的链表的头指针走完这个差值,此时,两个链表的头指针与交点的距离是相等的,让两个头指针一起往后走,直到两者相等,那么该结点就是交点了。

请添加图片描述
代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* curA = headA,*curB = headB;
    int lenA = 0,lenB = 0;
    //判断尾结点是否相同
    while(curA->next != NULL)
    {
        curA = curA->next;
        lenA++;
    }
    while(curB->next != NULL)
    {
        curB = curB->next;
        lenB++;
    }
    if(curA != curB)
        return NULL;
    //让长链表的头指针先走差值步数
    int gap = abs(lenA - lenB);
    struct ListNode* longList = headA,*shortList = headB;
    if(lenB > lenA)
    {
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
        longList = longList->next;
    }
    //让两个指针一起往后走,相等就是第一个交点
    while(longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }
    return longList;
}


9.环形链表:链接

题目要求:给你一个链表的头节点 head ,判断链表中是否有环。
请添加图片描述
如该题目的示例1,我们需要判断该链表是否带环。

思路:利用快慢指针,慢指针每次走一步,快指针每次走两步,所以快指针一直在慢指针的前面,然后快指针会追上慢指针,也就是相遇,此时就可以证明该链表带环。

请添加图片描述
这时就会有人说了,上面的方法是否只适用于示例一的特殊情况?下面,我就来证明该想法的适合于所有的情况。

请添加图片描述
如上面的链表中,我们尝试用快慢指针再次相遇来判断该链表带环。
请添加图片描述

因为N最大也只是接近于环的长度,所以追击小于一圈。

代码:

bool hasCycle(struct ListNode *head) 
{
    struct ListNode* slow,*fast;
    slow = fast = head;
    while(fast != NULL && fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next->next;

        if(slow == fast)
            return true;
    }
    return false;
}

此时,会不会又有人提出疑问,快指针每次走3步,或者4步、或者5步、或者n步,慢指针不变化,在两个指针距离为N个结点时,快指针能不能追上慢指针。

在快指针每次走4步下
快指针每次走4步,慢指针每次走1步,那么它们的差值就是3
两个指针之间的距离变化
N为偶数
N
N-3
N-6
……
4
1
-2

两个指针指针之间的距离为-2是去什么情况呢?如下图
请添加图片描述
两个指针之间的距离为-2,即为fast指针超过slow指针两个结点,此时,假设环有C个结点,那么fast指针要重新追到slow,就要走C-2个结点,如果C-2依然为偶数,那么两个指针将永远不会相遇。

如果C-2是奇数,如:3、9、12,那么可能相遇,如果是7,那么不可能相遇。即C-2为奇数,两个指针可能相遇。

在上面的情况中,如果fast指针想要追上slow指针,那么要追的圈数大于一圈。

其他情况也是如此,存在着一些追不上的情况,只有快指针每次走两步,慢指针每次走一步,它们之间的差值为1时,才能在所有情况能追上。



10.环形链表 II:链接

**题目要求:**给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回NULL。
请添加图片描述
如示例1,我们需要找到入环的第一个结点,也就是存储着2的结点。

思路:引用上一题的思路,我依然找到快、慢指针的相遇点,然后再定义一个指针从头结点开始,一个指针从相遇点开始,开始向后走,最后将会在入环的第一个结点相遇。

至于为什么一个指针从头结点开始,一个指针从相遇点开始,开始向后走,最后将会在入环的第一个结点相遇,我来说明一下。
请添加图片描述
代码:

struct ListNode *detectCycle(struct ListNode *head) 
{
      struct ListNode* slow,*fast;
      slow = fast = head;
      while(fast != NULL && fast->next != NULL)
      {
          slow = slow->next;
          fast = fast->next->next;

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


11.复制带随机指针的链表:链接

题目要求:给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节。构造这个链表的深拷贝。深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
请添加图片描述
如示例1,我们需要拷贝该链表,并且保证random的指向与原链表相同。

思路:在每个链表的非空结点后面链接一个新的结点,将该新结点的值改为相应的值,最近将所有链接的结点拆下来,构成一个新的链表,那么此时,链表的拷贝就结束了。

1.链接结点
请添加图片描述
2.设置链接结点的random
请添加图片描述
3.将链接的结点解下来,构成一个新链表
请添加图片描述
代码:

struct Node* copyRandomList(struct Node* head) 
{
    //链接结点
    struct Node* cur = head;
    while(cur != NULL)
    {
        struct Node* Next = cur->next;
        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        cur->next = copy;
        copy->next = Next;
        cur = Next;
    }

    //设置链接结点的random
    cur = head;
    while(cur != NULL)
    {
        struct Node* copy = cur->next;
        if(cur->random == NULL)
        {
            copy->random = NULL;
        }
        else
        {
            copy->random = cur->random->next;
        }
        cur = cur->next->next;
    }

    //将结点解下来,链接成新的链表
    struct Node* copyHead = NULL,*copyTail = NULL;
    cur = head;
    while(cur != NULL)
    {
        struct Node* Next = cur->next->next;
        struct Node* copy = cur->next;
        cur->next = Next;
        cur = Next;
        if(copyTail == NULL)
        {
            copyHead = copyTail = copy;
        }
        else
        {
            copyTail->next = copy;
            copyTail = copyTail->next;
        }
    }
    return copyHead;
}


其他链表题目:牛客网 || leetcode

今天,链表的题目讲解就到这里,关注点一点,下期更精彩。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/79319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis【10】-Redis发布订阅

简介 Redis 发布订阅(pub/sub)是一种消息通信模式&#xff1a;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 Redis 客 户端可以订阅任意数量的频道。 Redis 发布订阅(pub/sub)是一种消息通信模式&#xff1a;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 R…

R-CNN系列目标检测算法对比

引言 对比了R-CNN&#xff0c;Fast R-CNN&#xff0c;Faster R-CNN&#xff0c;Mask R-CNN目标检测算法的发展过程与优缺点。 R-CNN R-CNN是第一个成功第将深度学习应用到目标检测的算法。后面的Fast R-CNN&#xff0c;Faster R-CNN都是建立在R-CNN的基础上的。 R-CNN的检测…

实验2_前馈神经网络实验

文章目录实验要求数据集定义1 手动实现前馈神经网络解决上述回归、二分类、多分类任务1.1手动实现前馈网络-回归任务1.2 手动实现前馈网络-二分类任务1.3 手动实现前馈网络-多分类1.4 实验结果分析2 利用torch.nn实现前馈神经网络解决上述回归、二分类、多分类任务2.1 torch.nn…

[附源码]Node.js计算机毕业设计宠物短期寄养平台Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我们…

Mybatis 基础入门示例-步骤清晰简单

目录 1、新建数据库 2、新建项目 2.1导入依赖 2.2创建子工程&#xff08;新建模块&#xff09; 2.3添加配置文件mybatis-config.xml 2.4添加数据源 2.5编写mybatis核心配置文件 2.6编写MybatisUtils工具类 3、编写代码 3.1实体类 3.2 Mapper(UserDao)接口 3.3 接口…

如何在 Hexo Blog 网站上添加图标(iconfont 使用)

emsp; 因为在制作自己的个人主页的时候遇到了Hexo主题没有提供对应图标的问题&#xff0c;就查看了一下Hexo主题是如何添加图标的。发现主要的方法是直接修改fonts文件夹下的iconfont.svg文件。修改yilia theme下的font文件&#xff0c;这个也刚好是同学blog使用的主题&#x…

代码是如何控制硬件的?

简单来说&#xff0c;就是软件指令通过操作寄存器&#xff0c;控制与、或、非门搭建的芯片电路&#xff0c;产生、保存高低电平信号&#xff0c;实现相应的逻辑&#xff0c;最终通过IO、串口等输出。 要想更清楚的了解软件控制硬件的原理&#xff0c;就要明白cpu的框架及工作原…

Mysql 进阶(面向面试篇)索引

1、索引 1.1 索引概述 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足 特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c; 这样就可以…

springboot整合Swagger在线文档

SpringBoot整合Swagger2在线文档 一 什么是swagger&#xff1f; 我们前面有讲到说开发时会创建Restful风格的API接口&#xff0c;供第三方或前端人员使用&#xff0c;那么前端人员在使用的过程中怎么知道有哪些接口呢。这个时候可以通过写接口文档来解决&#xff0c;但不同的…

202/12/10 基础算法每日5道详解

21. Merge Two Sorted Lists合并两个排序列表 You are given the heads of two sorted linked lists list1 and list2. Merge the two lists in a one sorted list. The list should be made by splicing together the nodes of the first two lists. Return the head of the m…

Java基于springboot的人职匹配推荐系统-计算机毕业设计

项目介绍 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于人职匹配推荐系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了人职匹配推荐系统&#xff0c;它彻底改变…

[附源码]计算机毕业设计基于人脸识别的社区防疫管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

字节管理薪资被应届生倒挂7K,这真的是不把老员工当人?

一位字节跳动的小管理爆出&#xff0c;无意中看到了整个部门薪资&#xff0c;本以为自己算比较高的&#xff0c;但看完之后整个人都傻眼了。小组长的职位月薪28K&#xff0c;而手下组员却是35K&#xff0c;当天晚上抽了一包烟也没想明白是为什么。 楼主表示&#xff0c;自己是字…

算法基础篇-05-排序-LowB三人组(冒泡/选择/插入排序)

1. LowB 三人组介绍 LowB 三人组的时间复杂度都是 O(n^2) 1.1 冒泡排序(Bubble Sort) 列表每2个相邻的数&#xff0c;如果前面比后面大&#xff0c;则交换这两个数。一趟排序完成后&#xff0c;则无序区减少一个数&#xff0c;有序区增加一个数&#xff1b;时间复杂度 O(n^2…

Linux 伙伴系统

Linux 伙伴系统前言一、rmqueue1.1 流程图1.2 函数原型1.3 通过PCP分配1.4 大阶页面分配二、__rmqueue2.1 流程图三、__rmqueue_pcplist3.1 流程图四、__rmqueue_fallback五、__rmqueue_smallest5.1 源码5.1.1 get_page_from_free_area5.1.2 del_page_from_free_list5.1.3 expe…

从零开始把 SpringBoot 搬到 K8s 上运行,我用了这几步!

前言 大家好&#xff0c;我是网管。咱们的 K8s 入门和实践&#xff0c;在经历了三篇理论知识的后&#xff0c;相信各位都已经期待许久&#xff08;可能的吧&#xff09;&#xff0c;就差私信我&#xff0c;你整着理论整半天有啥用&#xff0c;本大人写的程序怎么能放到 K8s 上运…

Istio初探

Istio初探 前置环境&#xff1a;docker 一、安装k8s&#xff1a; ● https://segmentfault.com/a/1190000042204035 1、 https://github.com/gotok8s/k8s-docker-desktop-for-mac.git 2、 https://github.com/kubernetes/dashboard 3、 获取token curl ‘http://127.0.0.1:80…

SpringBoot实战项目杂货铺主页统计图表(折线图、饼状图、条形图)

统计图表的制作我们用到了Echarts&#xff0c;不得不说Echarts真的是百度的超级良心产品了。打Call!!!&#x1f44d;&#x1f44d;&#x1f44d; ✔小插曲&#xff1a; 这里博主顺带提一下&#xff0c;像处理访问量等等数据的时候&#xff0c;往往会涉及到一个并发问题。举个…

ADI Blackfin DSP处理器-BF533的开发详解27:扩展IO输出的详细讲解(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 硬件设计原理图 功能介绍 ADSP-EDU-BF53x 开发板上扩展接口的 PPORT3 中引出了 4 个扩展 IO 接口输出接口&#xff0c;这些连接到了 CPLD&#x…

【大数据入门核心技术-Hadoop】(八)Hadoop基本管理命令行

目录 一、 三种shell命令方式 二、常见Shell操作命令 三、dfs管理命令行 1、当前haoop环境变量 2、当前集群节点信息 3、运行HTTPFS服务器 4、高可用节点管理 5、单独启动某个节点服务 四、更多命令 一、 三种shell命令方式 HDFS有三种shell命令方式 hadoop fs&#…