链表题目强化练

目录

前言(非题目)

两数相加

删除链表的倒数第N个结点

环形链表

相交链表

合并 K 个升序链表

复制带随机指针的链表


前言(非题目)

初学者在做链表的题目时有一个特点,就是每看一个链表的题都觉得很简单,但真正到了扣代码的时候不是这卡一块就是那卡一块。这是因为链表的题目往往并不会涉及很难的算法,但确很考验对边界问题的处理以及扣代码的能力。所以链表的题目看似简单,却不可忽视。初学者切忌好高骛远,觉得一看就会、很简单就不做了,最终只会害了自己。

两数相加

题目描述

2. 两数相加https://leetcode.cn/problems/add-two-numbers/

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:


输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.


示例 2:

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


示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
 

提示:

每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

这题一看感觉很简单,不就是我们小学学的列竖式的加法运算吗。但小白本人在第一次做这道题的时候却被卡了很多次。虽然我们一看题目就知道思路,但在前期代码能力不强的情况下,把想法落实到代码上却是一个很艰难的过程。

我们就模拟竖式加法来做。首先让两个链表中对应位置的数字相加,然后将和的个位添加到新的需要返回的链表中。此时需要借助一个额外的变量用来存储进位的数,然后在下一个位置的时候再另外把这这个数加上。循环往复,直至最后。但有一个很容易被卡住的点,就是如果两个链表中如果有一个链表先走到最后的NULL位置,就很容易出现访问NULL的错误点(这是新手很容易忽略的一个点)。另外,在走到最后的时候还需要检查一下是否还有一个需要进位的数,以防止结果的遗漏。具体的代码实现可以参照下方内容。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
    {
        int tmp_quotient = 0;
        ListNode* ListHead = nullptr, *ListTail = nullptr;
        //l1或l2:当l1和12都为nullptr(都走到尾结点)        
        while(l1 || l2) 
        {
            //提取当前位数的数字,如果当前节点为nullptr就用0代替
            int tmp_num1 = l1 != nullptr ? l1 -> val : 0;
            int tmp_num2 = l2 != nullptr ? l2 -> val : 0;
            //将提出来的两位数与上次进位的数相加
            int tmp_sum = tmp_num1 + tmp_num2 + tmp_quotient;
            //将余数存入链表,满十进一
            if(ListHead != nullptr)
            {
                ListTail -> next = new ListNode(tmp_sum % 10);
                ListTail = ListTail -> next;
            }
            else
            {
                ListHead = ListTail = new ListNode(tmp_sum % 10);
            }
            tmp_quotient = tmp_sum / 10;
            //l1、l2没到头就继续向后走
            if(l1)
                l1 = l1 -> next;
            if(l2)
                l2 = l2 -> next;
        }
        //检查是否需要插入最后一位
        if(tmp_quotient > 0)
        {
            ListTail -> next = new ListNode(tmp_quotient);
        }
        return ListHead;
    }
};

删除链表的倒数第N个结点

题目描述

19. 删除链表的倒数第 N 个结点https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:


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


示例 2:

输入:head = [1], n = 1
输出:[]


示例 3:

输入:head = [1,2], n = 1
输出:[1]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

这题很会很容易理解的一个思路就是双指针,即设置两个指针fast和slow。fast先走n-1步,然后fast和slow一起走,当fast走到最后就停止。但这里如果没拿捏好是很容易出错的,首先为什么fast先走n-1步而不是n步呢?这里我们可以通过分析示例的方式来理解。实例分析是一个很好用的方法,当遇到这种不确定具体需要走多少步之类的问题时,结合实例分析之后会很容易得出结论,而且并不需要浪费很多时间。比如这里假定删除的是倒数第1个个数,那么fast最终是和slow一起走到最后的,所以fast要往前走0步,那么n-1就得出来了。

那么具体实现时还需要考虑另一个问题,即如果删除的是头节点,即刚好倒数第n个位置刚好为链表的head,那么我们还需要对这种情况额外进行单独讨论处理。这是比较麻烦的,而对于这种需要考虑删除头节点情况的问题,我们一般选择借助一个额外的哑节点来解决。让哑节点的next指向需要处理链表的head节点,那么从哑节点开始操作,最后返回哑节点的next就很好的避免了还要对头节点额外讨论的冗杂情况。这两种写法都在下面了。


不带哑节点的写法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution 
{
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) 
    {
        //先找到倒数第n+1个节点
        ListNode* fast = head;
        ListNode* slow = head;
        while(n--)      
            fast = fast->next;        
        while(fast && fast->next)
        {
            fast = fast->next;
            slow = slow->next;
        }
        //删除头节点的情况需要额外判断
        if(fast == nullptr)
            return head->next;
        ListNode* next = slow->next;
        slow->next = next->next;
        delete next;
        return head;
    }
};

带哑节点的写法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode;
        dummy->next = head;
        int len = 0;
        while(head)        
            head = head->next,  len++;        
        ListNode* cur = dummy;
        while(len-- > n)
            cur = cur->next;
        cur->next = cur->next->next;
        return dummy->next;
    }
};

环形链表

题目分析

141. 环形链表https://leetcode.cn/problems/linked-list-cycle/

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。


示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。


示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
 

提示:

链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

这题就是属于那种知道就会,不知道就不会的那种。因为大多数人第一次接触这题很难有思路,但一旦知道怎么做之后很快就记住了。所以这题的重点并不在于如何解出来,而是在于如何证明这样解是就是对的。

好了我们不多废话,直接看解法:先定义一对快慢指针fast和slow,它们分别都从头开始,fast每次向后走两步,slow每次向后走一步。如果出现fast==slow的情况,那么就是有环。否则如果fast如果走到了NULL,那就说明没环。写法如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) 
{
    if(head == NULL)
        return false;
    struct ListNode *fast = head, *slow = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
            return true;
    }
    return false;
}

接下来我们开始证明: 

        如果没有环,那么fast就不会进入到环中循环,那么最终就会遇到NULL,说明此链表没环。

        如果链表中存在环,我们设fast刚走到带环部分时的位置为f1,当slow刚走到带环部分的位置时fast的位置为f2,令f2-f1=x。设环的长度为C,那么此时fast与slow的距离即为C-x,令C-x=L。那么此时就是一个典型的追及相遇问题(图示如下)。

​​​​​​​

        小红和小明都在一个环形跑道上跑步,小红在小明前方L处,小明的速度是小红的2倍,问小明可以追上小红吗?答案是当然可以,由于小明的速度是小红的2倍,所以小红每走a的距离,那么小明就走2a的距离,即它们之间的距离就缩小a,那么当a恰好为L的时候就刚好追上,而且还是在第一圈就追上了。

        注意,这里的fast并不是严格的每次需要走2步,其实走3步、4步也是可以的,但这样很容易在“第一圈”的时候错过,需要多走几圈,效率就变低了。

相交链表

题目描述

160. 相交链表https://leetcode.cn/problems/intersection-of-two-linked-lists/

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

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
listA - 第一个链表
listB - 第二个链表
skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected 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 中第四个节点) 在内存中指向相同的位置。
 

示例 2:

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。


示例 3:

输入: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 。
 

提示:

listA 中节点数目为 m
listB 中节点数目为 n
1 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA] == listB[skipB]
 

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/intersection-of-two-linked-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

这题一个很好理解的思路是快慢指针,先求出两个链表的长度,然后让长的链表先走它们的长度之差步(这里也要分析好具体是先走多少步),然后再让两个链表一起走,当走到相同链表时就是相交点了。代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    if(headA == NULL || headB == NULL)
        return NULL;
    struct ListNode *pA = headA, *pB = headB;
    int lenA = 0, lenB = 0;
    while(pA) lenA++, pA = pA->next;
    while(pB) lenB++, pB = pB->next;
    int len = abs(lenB - lenA);
    struct ListNode* longList = lenA > lenB ? headA : headB;
    struct ListNode* shortList = longList == headA ? headB : headA;
    while(len--) longList = longList->next;
    while(shortList)
    {
        if(longList == shortList)
            return longList;
        longList = longList->next;
        shortList = shortList->next;
    }
    return NULL;
}

但这题想介绍的并不是这个思路,而是下面这个思路:让两个链表一起走,当走到NULL时就让其从另一个链表的头部,这样当走到相同链表时就是相交点。

这个思路很好记,但也是重在理解。我们设两个链表不相交的部分长度分别为m和n,相交部分长度为L,那么当第一个链表走到NULL时就已经走了m+L的距离,此时其跑到另一个链表的头部,而另一个链表此时也是走了m+L的距离(不论它是否已经走到NULL并跑到另一个链表中,并且一定没有第二次走到相交部分),而当第一个链表再次走到首个相交位置时,其已经走过了m+L+n的距离,那么同理另一个链表也是走过这么多距离,所以此时他们一定是位于同一个节点的。

通过上面两个题不难发现,对于链表相交、有环的这一类的题目,一般都是双指针或者快慢指针的思路,然后分析两个指针之间的数量关系,进而得出一个“公式”,利用这个“公式”来解决题目。

合并 K 个升序链表

题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6


示例 2:

输入:lists = []
输出:[]


示例 3:

输入:lists = [[]]
输出:[]
 

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

为了便于理解,我们在解决这道题之前先有一个函数可以排序两个升序链表,并返回排序后的链表。其实就是21. 合并两个有序链表这题,因为这题也不怎么难,所以就不再写题解了。

那么我们很容易想到的一个思路就是从头到尾将lists遍历一遍,每次合并头上的两个链表,直至最后。具体写法如下:

//写法1:顺序合并
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution 
{
public:
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
    {
        if(list1 == NULL && list2 == NULL)
            return NULL;
        if(list1 == NULL)
            return list2;
        if(list2 == NULL)
            return list1;

        struct ListNode* preHead = (struct ListNode*) calloc (1,sizeof(struct ListNode));
        struct ListNode* tail = preHead;
        while(list1 || list2) 
        {
            if(list1 == NULL)
            {
                tail->next = list2;
                break;
            }
            if(list2 == NULL)
            {
                tail->next = list1;
                break;
            }

            if(list1->val > list2->val)
            {
                tail->next = list2;
                list2 = list2->next;
            } 
            else
            {
                tail->next = list1;
                list1 = list1->next;            
            }
            tail = tail->next; 
        }   
        return preHead->next;
}
    ListNode* mergeKLists(vector<ListNode*>& lists) 
    {
        if(lists.empty())
            return NULL;
        int len = lists.size();
        ListNode* cur = lists[0];
        for(int i = 0; i < len - 1; i++)
        {
            ListNode* next = lists[i + 1];
            cur = mergeTwoLists(cur, next);
        }
        return cur;
    }
};

其实还可以进一步优化,我们可以将这个链表分为左右两部分,然后将左右两部分各自合并,最后将左右部分再合并就可以了。即分治的思路。不了解分治的可以看一下这篇博客的最后一个例题

递归详解 - C语言描述_小白麋鹿的博客-CSDN博客https://yt030917.blog.csdn.net/article/details/128678166代码实现如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution 
{
public:
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
    {
        if(list1 == NULL && list2 == NULL)
            return NULL;
        if(list1 == NULL)
            return list2;
        if(list2 == NULL)
            return list1;

        struct ListNode* preHead = (struct ListNode*) calloc (1,sizeof(struct ListNode));
        struct ListNode* tail = preHead;
        while(list1 || list2) 
        {
            if(list1 == NULL)
            {
                tail->next = list2;
                break;
            }
            if(list2 == NULL)
            {
                tail->next = list1;
                break;
            }

            if(list1->val > list2->val)
            {
                tail->next = list2;
                list2 = list2->next;
            } 
            else
            {
                tail->next = list1;
                list1 = list1->next;            
            }
            tail = tail->next; 
        }   
        return preHead->next;
}
    ListNode* mergeKLists(vector<ListNode*>& lists) 
    {
        if(lists.empty())
            return NULL;
        if(lists.size() == 1)
            return lists[0];
        if(lists.size() == 2)       
            return mergeTwoLists(lists[0], lists[1]);
        
        int len = lists.size();
        int mid = len / 2;
        vector<ListNode*> left_list(lists.begin(), lists.begin() + mid);
        vector<ListNode*> right_list(lists.begin() + mid, lists.end());

        ListNode* left = mergeKLists(left_list); 
        ListNode* right = mergeKLists(right_list); 
        return mergeTwoLists(left, right);

    }
};

复制带随机指针的链表

题目描述

138. 复制带随机指针的链表https://leetcode.cn/problems/copy-list-with-random-pointer/

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]


示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
 

提示:

0 <= n <= 1000
-104 <= Node.val <= 104
Node.random 为 null 或指向链表中的节点。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/copy-list-with-random-pointer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目分析

题目看起来有些长,简单说明一下就是:有一个链表,其节点不光有val和next还有有一个指向随机几点的random指针,要求我们完全拷贝这个链表,其中random的指向也要相同。

这题的一个思路就是用一个哈希表,将新链表和旧链表的节点一一对应,从前往后遍历旧的链表,其旧的random指向的节点在哈希表中与之对应的就是新的节点,所以可以根据这个来完成随机链表的拷贝。

但另一个更好理解并且效率更高的思路是:在原链表中每一个节点后面添加一个节点,并复制其val值,其random就应该指向与之对应的原链表节点的下一个,然后将新节点分离出来即可。具体写法如下:

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) 
{
/*思路:
    将原始链表中的每一个节点后面放一个newnode,然后填充好newnode之后再把newnode分出来。这三个步骤分别用三个循环搞定。
*/
    if(head == NULL)
        return NULL;
    struct Node* tmp;
    tmp = head;
    while(tmp)
    {
        struct Node* next = tmp->next;
        struct Node* newNode = (struct Node*) malloc (sizeof(struct Node));
        newNode->val = tmp->val;
        newNode->next = next;
        tmp->next = newNode; 
        tmp = next; 
    }

    tmp = head; 
    while(tmp) 
    { 
        struct Node* next = tmp->next; 
        next->random = tmp->random != NULL ? tmp->random->next : NULL; 
        tmp = next->next; 
    } 

    tmp = head; 
    struct Node* newNode = head->next;
    while(tmp->next->next) 
    { 
        struct Node* next = tmp->next;  
        struct Node* nnext = next->next; 
        next->next = nnext->next; 
        tmp->next = nnext;
        tmp = tmp->next; 
    } 

    return newNode;
} 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python程序员职业现状分析,想提高竞争力,就要做到这六点

现今程序员群体数量已经高达几百万&#xff0c;学历和收入双高&#xff0c;月薪普遍过万。今天&#xff0c;我们就围绕90后程序员人群分析、职业现状、Python程序员分析等&#xff0c;进行较为全面的报告分析和观点论述。 一、程序员人群分析 人数规模上&#xff1a;截当前程…

【设计原则与思想:总结课】38 | 总结回顾面向对象、设计原则、编程规范、重构技巧等知识点

到今天为止&#xff0c;设计原则和思想已经全部讲完了&#xff0c;其中包括&#xff1a;面向对象、设计原则、规范与重构三个模块的内容。除此之外&#xff0c;我们还学习了贯穿整个专栏的代码质量评判标准。专栏的进度已经接近一半&#xff0c;马上就要进入设计模式内容的学习…

类似于ChatGPT的优秀应用notion

notion 是一款流行的笔记应用。不过功能实际远超笔记&#xff0c;官方自己定义是&#xff1a;“将笔记、知识库和任务管理无缝整合的协作平台”。其独特的 block 概念&#xff0c;极大的扩展了笔记文档的作用&#xff0c;一个 block 可以是个数据库、多媒体、超链接、公式等等。…

怎么用问卷工具做市场调研?

对于希望开发新产品或服务、拓展新市场或确定潜在客户的公司来说&#xff0c;市场调查是一个至关重要的过程。然而&#xff0c;进行市场调查可能既耗时又昂贵&#xff0c;特别是在涉及对大量人群进行调查的情况下。今天&#xff0c;小编将来聊一聊调查问卷工具如何帮助企业进行…

Rasa 3.x 学习系列-Rasa [3.5.8] -2023-05-12新版本发布

Rasa 3.x 学习系列-Rasa [3.5.8] -2023-05-12新版本发布 当自定义动作设置的值与槽的现有值相同时&#xff0c;将触发SlotSet事件。修复了这个问题&#xff0c;使AugmentedMemoizationPolicy能够正确地处理截断的跟踪器。 为了恢复以前的行为&#xff0c;自定义操作只有在槽值…

【C++进阶】继承详解

文章目录 前言一、继承的概念及定义1.概念2.继承定义定义格式继承关系和访问限定继承基类成员访问方式的变化 二、基类和派生类对象赋值转换三、继承中的作用域四、派生类的默认成员函数五、继承与友元六、继承与静态成员七、复杂的菱形继承及菱形虚拟继承1.单继承与多继承2.菱…

软件 工程

目录 第十章、软件工程1、瀑布模型&#xff08;SDLC&#xff09;2、快速原型模型3、增量模型4、螺旋模型5、Ⅴ模型6、喷泉模型7、构建组装模型&#xff08;CBSD&#xff09;8、统一过程&#xff08;RUP&#xff09;9、敏捷开发方法10、信息系统开发方法11、需求开发12、结构化设…

收藏|必读10本pcb设计书籍推荐

1."High-Speed Digital Design: A Handbook of Black Magic"。 作者是Howard Johnson和Martin Graham。这是一本关于高速数字电路设计的优秀教材&#xff0c;适合那些需要设计高速电路的工程师。 作为比较早出来的信号完整性参考书&#xff0c;对国内的信号完整性研…

H.265/HEVC编码原理及其处理流程的分析

H.265/HEVC编码原理及其处理流程的分析 H.265/HEVC编码的框架图&#xff0c;查了很多资料都没搞明白&#xff0c;各个模块的处理的分析网上有很多&#xff0c;很少有把这个流程串起来的。本文的主要目的是讲清楚H.265/HEVC视频编码的处理流程&#xff0c;不涉及复杂的计算过程。…

第3天学习Docker-Docker部署常见应用(MySQL、Tomcat、Nginx、Redis、Centos)

前提须知&#xff1a; &#xff08;1&#xff09;搜索镜像命令 格式&#xff1a;docker search 镜像名 &#xff08;2&#xff09;设置Docker镜像加速器 详见文章&#xff1a;Docker设置ustc的镜像源&#xff08;镜像加速器&#xff09; 1、部署MySQL 拉取镜像&#xff08;这…

从0到1无比流畅的React入门教程

无比流畅的React入门教程TOC React 是什么 简介 用于构建 Web 和原生交互界面的库React 用组件创建用户界面通俗来讲&#xff1a;是一个将数据渲染为HTML视图的开源JS库 其他信息 Facebook 开发&#xff0c;并且开源 为什么使用React? 原生JS使用DOM-API修改UI代码很繁…

4年外包出来人废了,5次面试全挂....

我的情况 大概介绍一下个人情况&#xff0c;男&#xff0c;毕业于普通二本院校非计算机专业&#xff0c;18年跨专业入行测试&#xff0c;第一份工作在湖南某软件公司&#xff0c;做了接近4年的外包测试工程师&#xff0c;今年年初&#xff0c;感觉自己不能够再这样下去了&…

软件设计模式介绍与入门

目录 1、软件设计模式的起源 2、什么是设计模式&#xff1f; 2.1、设计模式的设计意图 2.2、设计模式的分类准则 3、为什么要学习设计模式 4、如何学习设计模式 5、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#x…

Redis--弱口令未授权访问漏洞

Redis--弱口令未授权访问漏洞 一、漏洞简介二、危险等级三、漏洞影响四、入侵事件五、漏洞复现--Redis CrackIT入侵事件5.1、以root启动的redis&#xff0c;可以远程登入到redis console--------A主机5.2、生成公钥5.3、执行: redis-cli flushall 清空redis(非常暴力&#xff0…

《终身成长》笔记四——如何面对失败

目录 经典摘录 秉性 一个英雄具备的所有特质 ​编辑 什么是成功 什么是失败 掌控成功 领导力与固定型思维模式 成长型思维模式领导者的行为 害羞 经典摘录 秉性 天才们&#xff0c;因为自己拥有的优势而得意忘形&#xff0c;不去学习如何努力奋斗以及如何面对挫折。…

分享一个程序员接私活、兼职的平台

分享一个程序员接私活、兼职的平台 1、技术方向满足任一即可2、技术要求3、最后 1、技术方向满足任一即可 Python&#xff1a;熟练掌握Python编程语言&#xff0c;能够使用Python进行数据处理、机器学习和深度学习等相关工作。 MATLAB&#xff1a;熟练掌握MATLAB编程语言&…

MathType7公式编辑器新版详细介绍下载安装

由于CSDN这边不能发相关的教程等&#xff0c;若仅用于学习体验&#xff0c;请移步&#xff0c;有能力请支持正版。 wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;mathtype 免费获取MathType-win-zh.exe安装包 它是一款用于数学公式编辑和排版的软件。MathType可以在Mi…

粪菌移植——一种治疗人体疾病的新型疗法

谷禾健康 粪菌移植是一项近年来备受关注的医疗技术&#xff0c;它涉及将健康捐赠者的粪便物质转移至患有疾病或障碍患者的胃肠道。 简单来说就是选择健康合适的人粪便&#xff0c;通过科学方法提取出有用的微生物&#xff0c;去除有害与无用的部分&#xff0c;然后制成制剂&…

基于布谷鸟优化算法(CS)在微电网优化中的应用研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ChatGPT应用场景巡航之广告文案

此文为ChatGPT应用场景巡航第二篇&#xff1a;广告文案。 写出成功的文案&#xff0c;需要专业的技术水准&#xff0c;如果加以辅助工具&#xff0c;那会更加如虎添翼&#xff0c;事半功倍&#xff0c;本文会给大家介绍一下广告文案的写作技巧和辅助工具的使用。 01 — 指导原…