链表OJ题目合集第一弹:移除元素,反转链表,中间结点,倒数第k个结点,合并有序链表,回文结构,相交链表判断。(C语言版,有详细解析、图示和链接)

news2024/11/23 22:05:13

目录

前言

1. 移除链表元素

(1)题目及示例

(2)解析

(3)代码

2. 反转链表

(1)题目及示例

(2)题目解析及思路

3.链表的中间结点

(1)题目及示例

(2)题目解析及思路

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

(1)题目及示例

(2)题目解析及思路

5.合并两个有序链表

(1)题目及示例

(2)题目解析及思路

6.链表的回文结构

(1)题目及测试样例

(2)题目解析及思路

7.相交链表

(1)题目及示例

(2)题目解析及思路

总结


前言

上篇文章是有关于两个较常用链表的结构的实现。实现完链表过后,我们还需要会熟练运用链表这种数据结构,所以这里将会有十道链表OJ题目,本篇文章将会先分析解决七道题目,剩下三道留在下一篇文章。每道题都题目后都有链接,还会有大量的图示,帮助你理解题目解法,附上解题代码


1. 移除链表元素

(1)题目及示例

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。链接--力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

 //题目结构题定义如下
 struct ListNode 
{
    int val;
    struct ListNode *next;
 };

 注意:之后题目若没有详细说明,都是以上面单链表结构体为准!!!

示例1:

输入:head = [1,2,6,3,4,5,6],val = 6

输出:[1,2,3,4,5]

示例2:

输入:head = [ ],val = 1

输出:[ ]

示例3:

输入:head = [7,7,7,7],val = 7

输出:[ ]

(2)解析

从题目和示例来看,就是去除链表中存储数据相同的结点时,跟单链表的删除操作十分相似。需要注意的是特殊情况,链表为空的时候直接返回空链表即可。在删除的过程中要分两种情况,分别是头部删除和中间删除,这是因为改题目要求返回新的头结点,中间的删除不会影响头结点的指向。

下面分析这两步操作,在执行前,我会定义prev和cur这两个指针,prev指向空指针,cur指向头结点。prev指向的是cur指针的前一个结点,但是一开始cur指向头结点,所以指向空。

  • 头部删除,假设val = 1。

  • 中间删除,假设val = 3。

  • 迭代往后走,是中间删除这一步的后续。

(3)代码

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* prev = NULL;
    struct ListNode* cur = head;
    while(cur)
    {
        if (cur->val == val)
        {
            //1.头部珊除
            //2.中间删除
            if (cur == head)
            {
                head = cur->next;
                free(cur);
                cur = head;
            }
            else
            {   //删除
                prev->next = cur->next;
                free(cur);
                cur = prev->next;
            }
        }
        else
        {   //往后走
            prev = cur;
            cur = cur->next;
        }
    }
    return head;
}

2. 反转链表

(1)题目及示例

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

示例1:

输入:head = [ 1,2,3,4,5 ]

输出:[ 5,4,3,2,1 ]

示例2:

输入:head = [ 1,2,3,4,5 ]

输出:[ 5,4,3,2,1 ]

示例3:

输入:head = [  ]

输出:[  ]

(2)题目解析及思路

这个题目意思比较明显,我们需要把链表整个指向反转过来。有以下几种思路:

1. 正常来说,最平常的思路就是自己开辟与题目示例所给相同的个数的结点,并先遍历链表找到尾结点,依次寻找前面的结点,但是十分麻烦。倘若有五个节点需要遍历4+3+2+1+0次次,时间复杂度相当于O(N^2),空间复杂度为O(N)

2. 在第一种做法的基础上,进一步优化,还是开辟示例所给相同个数的结点,但是这次我们只需要遍历一次链表即可。我们需要三个指针,是cur,newCur,newPrev,分别指向原链表,新链表

  • 一开始cur指向原链表的头结点,newCur,newPrev都指向空。
  • 当开辟第一个结点时,newCur指向它,将其next指针指向空,并让newCur的val赋值为cur的val值,cur指向下一个结点。
  • 当开辟第二个结点时,newCur指向它,newPrev指向前一个结点,即第二个结点。让newCur的next指针指向第一个结点,也就是现在的newPrev,然后赋值,cur指向下一个结点。
  • 中间不断进行上述操作……
  • 当cur指向原链表最后一个结点的时候,进行赋值,修改指针指向,cur将会继续往后走,此时cur为NULL空指针。因此写一个while循环,判断条件就是cur指针,当它为空时循环结束,返回新链表头结点newCur。

这个做法只需遍历链表一次,时间复杂度为O(N),空间复杂度还是O(N)。代码如下:

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* cur = head;
    struct ListNode* newCur= NULL;
    struct ListNode* newPrev= NULL;
    while(cur)
    {
        newCur = (struct ListNode*)malloc(sizeof(struct ListNode));
        if (cur == head)
        {   //赋值
            newCur->val = cur->val;
            newCur->next = NULL;
            //迭代往后
            newPrev = newCur;
            cur = cur->next;
        }
        else
        {   //赋值
            newCur->val = cur->val;
            newCur->next = newPrev;
            //迭代往后
            newPrev = newCur;
            cur = cur->next;
        }
    }
    return newCur;
}

3. 不过大家可以仔细想想,既然我们创建新链表的时候可以反转,为什么不直接在原链表进行反转。这就是此题的最优解,在空间上,只需要创建几个指针变量,空间复杂度为O(1),在时间上,只需要遍历一次链表即可,时间复杂度为O(N)

在开始反转前,需要创建三个指针变量,cur,newhead和next,其中next是放在while循环中创建的指针变量。cur先指向头结点,newhead指向空指针。

  • 假设一个链表head = [ 1,2,3,4 ],一开始情况如下图,next指针指向的是cur的下一个结点。

  •  把cur的next指针指向newhead,即把第一个结点指向空,然后迭代往后走,next指针的作用就体现出来了。newhead指向cur的位置,cur指向next的位置。

  • 在下一次操作中,next指向cur下一个结点的位置,在改变第二个结点的指向。

  • 接下来重复上述操作,如图所示

  • 当cur指针到达最后一个结点的时候,再次改变指针指向。而cur指向空,newhead指向最后一个结点时,完成反转链表,所以while循环判断是cur不为空时,最后返回newhead指针就行。

代码如下:

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* cur = head;
    struct ListNode* newhead = NULL;
    while(cur)
    {
        struct ListNode* next = cur->next;
        //头插
        cur->next = newhead;
        newhead = cur;

        //迭代往后走
        cur = next;
    }
    return newhead;
}

3.链表的中间结点

(1)题目及示例

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

示例1:

输入:head = [ 1,2,3,4,5 ]

输出:[ 3,4,5 ]

解释:链表只有一个中间结点,值为3.

示例2:

输入:head = [ 1,2,3,4,5 ]

输出:[ 3,4,5 ]

解释:链表只有两个中间结点,值分别为3和4,返回第二个结点。

(2)题目解析及思路

寻找中间结点需要分奇数和偶数两种情况。

  • 如果是奇数,可以直接找中间结点
  • 如果是偶数,中间结点有两个,根据题目要求,返回第二个中间结点,这里是要注意的地方。

解法一:

正常来说,因为单链表不知道结点个数,需要利用一个指针变量遍历整个链表,记下链表长度,然后再次从头节点开始,让指针指向链表长度的一半。总的来说,在时间消耗上,如果有N个结点,需要执行N + N / 2 + 1次。

解法二:

那有没有更好的解法呢?那就得请出快慢指针了,在第一种解法上进一步优化,只需遍历一遍链表。怎么做呢?快慢指针顾名思义有两个指针,一个走的快,一个走得慢。

  • 假设是奇数个结点的链表,快指针走两步,慢指针走一步,以示例一为例,当slow指针走到中间结点时,fast指针刚好走到最后一个结点。

  • 如果是偶数结点,以示例二为例,下列图示第二张直接从第一个中间结点3开始。当走到第二个中间结点时,fast指针指向空。

综上所述,while循环结束条件是fast指针为空或者fast的next指针为空。

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

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

(1)题目及示例

输入一个链表,输出该链表中倒数第k个结点。链接:链表中倒数第k个结点_牛客题霸_牛客网

示例1:

输入:1, [ 1,2,3,4,5 ]

输出:[ 5 ]

解释:倒数第一个结点是5,返回5字后的链表

(2)题目解析及思路

这道题跟中间结点类似,只不过是求倒数第k个结点,下面我提供两种思路

解法一:

正常来说,大家首先想到的应该是遍历知道链表节点个数,然后再从头结点开始,走n-k步。在时间消耗上,最坏的情况是要走2 * n步。

解法二:

这里会使用快慢指针,但与找中间结点不同的是,这次是fast指针先走,然后slow指针和fast指针都走一步。为什么是这样子呢?我们以链表 [ 1,2,3,4,5 ],K = 2为例。

  • 上图我们可以发现倒数第K个结点与空结点相差2步,我们可以让slow指针和fast指针相差K步,然后每次都走一步直到结束。现在我们让fast指针先行K步。

  • 然后,slow指针和fast指针同时都走一步。

所以说在时间消耗上,只需要遍历一次链表,是第一种解法的优化。我们已经分析完了过程,代码怎么写呢?首先用一个while循环让fast指针先走K步。其次,再用while循环让两个指针一起走,结束条件是fast的指针为空。不过得注意的是,如果是空链表或者k小于零的情况,直接返回空指针。

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) 
{
    if (pListHead == NULL || k <= 0)
        return NULL;
    struct ListNode* slow, *fast;
    slow = fast = pListHead;
    while(k--)//先走K步
    {
        if (fast == NULL)
            return NULL;
        fast = fast->next;
    }

    while(fast != NULL)//同时走一步
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

5.合并两个有序链表

(1)题目及示例

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

struct ListNode* mergeTwoLists
(struct ListNode* list1, 
struct ListNode* list2) {
}

示例1:

输入:l1 = [ 1,2,4 ],l2 = [ 1,3,4 ]

输出:[ 1,1,2, 3,4,4 ]

示例2:

输入:l1 = [  ],l2 = [  ]

输出:[  ]

示例3:

输入:l1 = [  ],l2 = [ 0 ]

输出:[ 0 ]

(2)题目解析及思路

这道题有递归和迭代两种方式,这里只详解迭代的方式。迭代思路还是比较好想的,难的是代码实现。思路就是链表一和链表二从第一个结点开始比较,较小的结点就成为新链表的结点,较大的继续跟下一个结点比较,直到所有结点比较完。在写代码上,有两种形式,就是带不带哨兵位的结点。自己创建一个指针head表示新链表的头,还有一个tail指针,为插入后续节点服务,将这两个指针都赋值为空指针。

  • 如果不带哨兵位结点,需要注意第一次比较,不论是第一个链表还是第二个链表结点成为新链表的头,都要单独处理,head和tail都指向list1的头结点。其他的情况,让tail的next指针指向较小结点,并且每步的较小结点的链表需要指向下一个结点。

  • 此时list1已经走到tail指针的后面,就是空指针,我们写一个while循环结束的条件就是其中一个题目给的链表指针走到空指针。最后我们要加上一个判断,判断哪个链表为空,就将tail的next指针指向现在list1。

在这之前还要判断链表有没有空的情况。代码如下:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;
    struct ListNode* head = NULL, *tail = NULL;
    while (list1 && list2)
    {
        if (list1->val < list2->val)
        {
            if (head == NULL)
            {
                head = tail = list1;
            }
            else
            {
                tail->next = list1;
                tail = list1;
            }
            list1 = list1->next;
        }
        else
        {
            if (head == NULL)
            {
                head = tail = list2;
            }
            else
            {
                tail->next = list2;
                tail = list2;
            }
            list2 = list2->next;
        }
    }
    if (list1)
    {
        tail->next = list1;
    }
    if (list2)
    {
        tail->next = list2;
    }
    return head;
}
  • 如果有哨兵位结点,就不用处理head指针为空的情况。并且还要释放掉我们动态开辟的结点,返回head的下一个结点。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;
    struct ListNode* head = NULL, *tail = NULL;

    head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));

    while (list1 && list2)
    {
        if (list1->val < list2->val)
        {
            tail->next = list1;
            tail = list1;
            list1 = list1->next;
        }
        else
        {
            tail->next = list2;
            tail = list2;
            list2 = list2->next;
        }
    }
    if (list1)
    {
        tail->next = list1;
    }
    if (list2)
    {
        tail->next = list2;
    }

    struct ListNode* list = head->next;
    free(head);
    return list;
}

6.链表的回文结构

(1)题目及测试样例

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。链接:链表的回文结构_牛客题霸_牛客网

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
    }
};

这道题在牛客网中没有提供C语言版,有C++函数,可以直接在此函数内部写C语言版代码。因为C++兼容C语言。

测试样例:

输入:A = [ 1->2->2->1 ]

输出:true

(2)题目解析及思路

这道题目要判断是否为回文结构,我们可以观察回文链表,发现回文链表从中间结点断开,两边是对称的,那我们可以找到中间结点,并把中间结点之后的链表逆置,再进行比较存储的整型值。因此,之前写的两道题反转链表和找中间结点就可以派上用场了。不过得注意奇数偶数的情况。

  • 如果是奇数个结点,利用之前写的寻找中间结点刚好只有一个。

  •  如果是偶数个结点,中间结点有两个,之前的寻找中间结点函数是找到第二个中间结点。

要反转中间结点后的链表,有的人会直接断开,就像下面图例的情况,如果是偶数个结点,从头开始比较,到空指针的时候结束了。如果是奇数个结点,断开的时候会多出一个中间结点,只要其中一个链表走到空指针就结束,所以比较判断结束条件是其中一个链表为空。但是反转链表后,还需要断开链表,比较麻烦,我们可以看看不断开的情况。

如下图所示,这就是不断开的情况。如果是奇数个结点,从两边开始比较,最后都会走向空指针。如果是偶数个结点,从两边开始比较,其中一个会先走到空指针,就结束对比的过程。

你可以把寻找中间结点函数和反转链表函数再重新写一遍,也可以直接借用,再进行比较。

//寻找中间结点
struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* slow, *fast;
    slow = fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

//反转链表
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* cur = head;
    struct ListNode* newhead = nullptr;
    while(cur)
    {
        struct ListNode* next = cur->next;
        //头插
        cur->next = newhead;
        newhead = cur;
        //迭代往后走
        cur = next;
    }
    return newhead;
}

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) 
    {   //找到中间结点
        struct ListNode* mid = middleNode(A);
        //中间结点的头
        struct ListNode* rHead = reverseList(mid);
        //原链表的左右结点
        struct ListNode* curLeft = A;
        struct ListNode* curRight = rHead;
        while (curLeft && curRight)
        {
            if (curLeft->val != curRight->val)
            {
                return false;
            }
            else 
            {
                curLeft = curLeft->next;
                curRight = curRight->next;
            }
        }
        return true;
    }
};

7.相交链表

(1)题目及示例

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。注意,函数返回结果后,链表必须 保持其原始结构

示例1:

输入:intersectVal = 8, listA = [ 4,1,8,4,5 ],listB = [ 5,6,1,8,4,5 ],skipA = 2,skipB = 3

输出:IntersectVal at ‘8’

解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 — 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置

示例1:

输入:intersectVal = 0, listA = [ 2,6,4 ],listB = [ 1,5 ],skipA = 3,skipB = 2

输出:null

解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。

(2)题目解析及思路

我们要判断是否为相交链表,并找出相交点,而且不能破坏原链表的结构。我们先要清楚相交链表的概念,题目给的图示就很直观,有两个链表的最后一个节点不指向空指针,但是同时指向一个结点。还要注意的是,不能形成环形链表,就是一个链表出现头尾相连的情况。

这道题我会提供两个思路。

思路一:

我们观察相交链表,会发现不管从A链表出发,还是B链表出发,在指向空指针之前的结点是相同的,我们可以根据这个判断是否为相交链表。并在遍历AB链表的时候,记录链表从A出发和从B出发的长度,算出差距多少步。定义两个指针变量,让长的链表指针变量先走差距步,然后两个链表指针同时走,当走的过程中,两个指针相同时,必然是相交的节点。

代码如下:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* tailA = headA;
    struct ListNode* tailB = headB;
    int lenA = 1;
    while(tailA->next)
    {
        lenA++;
        tailA = tailA->next;
    }
    int lenB = 1;
    while (tailB->next)
    {
        lenB++;
        tailB = tailB->next;
    }

    if(tailA != tailB)
    {
        return NULL;
    }
    //abs时绝对值
    int gap = abs(lenA - lenB);
    //先假设A链表是长链表,再比较,如果不是再重新赋值
    struct ListNode* longlist = headA;
    struct ListNode* shortlist = headB;
    if (lenA < lenB)
    {
        shortlist = headA;
        longlist =headB;
    }
    // 长的先走差距步,再同时走交点
    while(gap--)
    {
        longlist = longlist->next;
    }

    while(longlist != shortlist)
    {
        longlist = longlist->next;
        shortlist = shortlist->next;
    }

    return longlist;
}

思路二:

思路二更加巧妙,我用图示展示更直观。A链表结点总个数用totalA表示,在相交结点之前A链表节点个数用lenA表示,相交结点之后公共部分用comlenth表示。B链表同理。

totalA = lenA + comlenth

totalB = lenB + comlenth

  • 当curA和curB这两个指针同时走到最后一个结点时,curA走了totalA步,curB走了totalB步

  • 当遇上空指针的时候,把curA指针指向链表B,把curB指针指向链表A。继续走。

  • 当都走到相交结点时,我们会发现curB走的步数是totalB + lenA,是八步,curA走的步数是totalA + lenB,也是八步。这难道是巧合吗?还记得最开始的式子吗,我们做个化简,会发现按照我刚刚的方式走到相交结点时,他们俩的步数一定是一样。

totalA = lenA + comlenth                                                                                                        

totalB = lenB + comlenth

将其带入到curAlen和curBlen中,

curAlen = totalA + lenB = (lenA + comlenth) + lenB = (len A + lenB) + comlenth

curBlen = totalB + lenA = (lenB + comlenth) + lenA = (len A + lenB) + comlenth

  • 如果不是相交链表呢?还是想按照上面的办法,当走到各自链表最后一节点,遇到空指针,从头开始,但是位置互换,放走到空指针时,步数刚好相同都是两个链表个数之和返回空指针。

那么代码怎么写呢,先要注意如果有其中一个链表为空,就无法形成相交链表,直接返回空。先创建两个指针curA和curB,写一个while循环,结束条件是curA = curB的时候,最后返回其中一个指针变量即可。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    if (headA == NULL || headB == NULL) 
    {
        return NULL;
    }


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


总结

这次七道链表OJ题目的解析可以说是干货满满,建议收藏。每做一道题,可以参考上面的图示来分析理解思路,多画图有助于你思路顺畅,后期写代码不卡壳。事后可以尝试自己总结其中用到的方法,话不多说,练起来!

创作不易,希望这篇文章能给你带来启发和帮助,如果喜欢这篇文章,请留下你的三连哦,你的支持的我最大的动力!!!

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

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

相关文章

一起学量化之RSI指标

RSI指标 Relative Strength Index,相对强弱指数(RSI),是一个衡量资产过度买入或过度卖出状态的技术指标。 1. RSI的基本概念 当RSI超过70时,通常被认为是超买状态。当RSI低于30时,通常被认为是超卖状态。RSI超过80,被认为是严重超买状态。RSI低于20,被认为是严重超卖状…

马斯克评 OpenAI 视频模型,接地气又一针见血

马斯克评 OpenAI Sora 昨天&#xff0c;OpenAI 发布了首个视频生成模型 Sora。 一位 X&#xff08;前推特&#xff09;用户分享了 Sora 官网所展示的生成视频&#xff1a;一名女子在东京街头漫步。 该用户评论称&#xff1a;"OpenAI 今天宣布了 Sora&#xff0c;它使用混合…

STM32的三种下载方式

结果jlink&#xff0c;串口&#xff0c;stlink方式都没有问题&#xff0c;是当时缩减代码&#xff0c;看真正起作用的代码段有哪些&#xff0c;就把GPIO初始化中 /*开启GPIO外部时钟*/RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); 把开启外部时钟的代码注释掉了。…

【plt.imshow显示图像】:从入门到精通,只需一篇文章!【Matplotlib】

【plt.imshow显示图像】&#xff1a;从入门到精通&#xff0c;只需一篇文章&#xff01;【Matplotlib】 &#x1f680; 利用Matplotlib进行数据可视化示例 &#x1f335;文章目录&#x1f335; &#x1f4d8; 1. plt.imshow入门&#xff1a;认识并安装Matplotlib库&#x1f308…

Github 2024-02-17 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-17统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4TypeScript项目3Rust项目2Jupyter Notebook项目1PowerShell项目1JavaScript项目1 Black&#xff…

AutoKeras(Python自动化机器学习)多模态数据和多任务

要点拓扑 AutoKeras 拓扑 要点 常规机器学习&#xff1a;scikit-learn示例探索性数据分析和数据预处理&#xff0c;线性回归&#xff0c;决策树图像分类ResNet模型示例&#xff0c;合成数据集DenseNet模型示例绘图线性回归和决策树模型使用Python工具seaborn、matplotlib、pan…

PCL库学习及ROS使用

PCL库学习 c_cpp_properties.json {"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/usr/include","/usr/local/include"],"defines": [],"compiler…

把Activity当做dialog对话框使用

1、引言 在安卓开发中对话框的使用是不可避免的&#xff0c;但是原生的对话框用起来总感觉差点意思&#xff0c;而且位置不好控制&#xff0c;在与界面的交互上也不够灵活&#xff0c;没有像activity那样的生命周期方法&#xff0c;以至于某些特殊的功能无法实现。此时我们就希…

深度学习主流开源框架:Caffe、TensorFlow、Pytorch、Theano、Keras、MXNet、Chainer

2.6 深度学习主流开源框架 表2.1 深度学习主流框架参数对比 框架关键词总结 框架关键词基本数据结构&#xff08;都是高维数组&#xff09;Caffe“在工业中应用较为广泛”&#xff0c;“编译安装麻烦一点”BlobTensorFlow“安装简单pip”TensorPytorch“定位&#xff1a;快…

数据库MySQL中出现乱码和表格不对齐怎么解决

MySQL中出现乱码问题及解决办法&#xff1a; 情况类似&#xff1a; 首先进入到数据库中&#xff0c;命令&#xff1a;mysql -h localhost -uroot -p或者mysql -uroot -p;进入数据库后选择一个你的数据库查看表中的中文是否乱码 以上是数据库中表格出现乱码情况&#xff0c;原…

项目架构梳理

单点登录组件 CREATE TABLE user_info (id int(11) NOT NULL AUTO_INCREMENT COMMENT 自增主键,用户id,username varchar(30) NOT NULL COMMENT 用户姓名,password varchar(60) NOT NULL COMMENT 密码,token varchar(60) DEFAULT NULL COMMENT token,token_expire datetime DEF…

1.8 NLP自然语言处理

NLP自然语言处理 更多内容&#xff0c;请关注&#xff1a; github&#xff1a;https://github.com/gotonote/Autopilot-Notes.git 一、简介 seq2seq(Sequence to Sequence)是一种输入不定长序列&#xff0c;产生不定长序列的模型&#xff0c;典型的处理任务是机器翻译&#…

BUGKU-WEB game1

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 是一个盖楼的游戏&#xff01; 解题思路 先看看源码&#xff0c;好像没发现什么特别的是不是要得到一定的分数才会有对应的flag&#xff1f;查看下F12&#xff0c;请求链接发现&#xff0c;这不就提示了 相…

第13章 网络 Page738~741 13.8.3 TCP/UDP简述

libcurl是C语言写成的网络编程工具库&#xff0c;asio是C写的网络编程的基础类型库 libcurl只用于客户端&#xff0c;asio既可以写客户端&#xff0c;也可以写服务端 libcurl实现了HTTP\FTP等应用层协议&#xff0c;但asio却只实现了传输层TCP/UDP等协议。 在学习http时介绍…

九大问题困扰企业财务数字化转型,你准备好解决了吗?

随着数字化浪潮的推进&#xff0c;企业财务管理也迎来了转型的关键时刻。然而&#xff0c;多年的数字化转型经验告诉我们&#xff0c;企业在这一过程中普遍面临着许多挑战和痛点。接下来&#xff0c;我们将逐一深入剖析这些痛点&#xff0c;并探讨如何有效应对。 一、数据孤岛问…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(3)数据准备初步

今天来学习数据准备。 一个AI项目要包括构建数据集、数据清理和数据融合、数据采集、特征工程、算法改进和其他步骤。 数据采集和数据清洗&#xff0c;也就是数据准备&#xff0c;要占到人工智能项目一半以上的工作量。 训练的数据量越大&#xff0c;模型越准确。 建立数据标…

一篇文章入门postmain接口测试

一、了解接口和接口测试 1、什么是接口? 电脑&#xff1a;USB&#xff0c;投影机(数据传输) 软件&#xff1a;统称APl,application,program,interface,微信提现和充值&#xff0c;支付宝支付&#xff0c;银联支付接口。(鉴权码&#xff1a;token,key,appkey) 2、接口包括&…

关于umi ui图标未显示问题

使用ant design pro 时&#xff0c;安装了umi ui &#xff0c;安装命令&#xff1a; yarn add umijs/preset-ui -D但是启动项目后&#xff0c;发现没有显示umi ui的图标 找了许多解决方案&#xff0c;发现 umi的版本问题&#xff0c;由于我使用的ant design pro官网最新版本&a…

tf.linspace时出现Could not find valid device for node.

背景&#xff1a; 在使用tensorflow2.x的时候,当使用tf.linspace的时候会出现如下的报错&#xff1a; import os os.environ[TF_CPP_MIN_LOG_LEVEL] 2import tensorflow as tf from tensorflow import keras import numpy as npdef out():# x tf.constant(np.arange(12).re…

实现低功耗设计的嵌入式系统技术

&#xff08;本文为简单介绍&#xff0c;观点来源网络&#xff09; 在嵌入式系统设计中&#xff0c;追求低功耗已成为一个核心指标&#xff0c;旨在延长设备的运行时间并提升能效。实现这一目标的途径是多元的&#xff0c;涉及从硬件选型到软件算法的各个层面。 首先&#xf…