剑指offer刷题笔记-链表

少年何妨梦摘星

敢挽桑弓射玉衡


解决与链表相关的问题总是有大量的指针操作,而指针操作的代码总是容易出错的。很多面试官喜欢出与链表相关的问题,就是想通过指针操作来考察应聘者的编码功底。

题目链接来自于 AcWingLeetcode(LCR)


目录

 从尾到头打印链表

题目描述

思路

代码测试

 删除链表的节点

题目描述

思路

代码测试

 链表中倒数第k个节点

题目描述

思路一

代码测试一

思路二

代码测试二

链表中环的入口结点 

题目描述

思路

结论整理

代码测试

反转链表 

题目描述

思路

代码测试

合并两个排序的链表

题目描述

思路一

代码测试一

思路二

代码测试二

删除链表中重复的节点

题目描述

思路

代码测试

 两个链表的第一个公共结点 

思路一

代码测试一

思路二

代码测试二

 复杂链表的复刻

思路

代码测试

 从尾到头打印链表

题目链接:从尾到头打印链表


题目描述

输入一个链表的头结点,按照 从尾到头 的顺序返回节点的值。

返回的结果用数组存储。

数据范围

0≤ 链表长度 ≤1000。

样例

输入:[2, 3, 5]
返回:[5, 3, 2]

思路

通常打印是一个只读的操作,我们不希望修改原链表的结构。接下来我们想到解决这个问题的肯定要遍历链表,遍历的顺序是从头到尾,而输出的顺序却是从尾到头。这就是典型的 后进先出 的问题。

我们可以使用 实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个读取结点的值,并赋给一个新数组,这样我们就可以从尾到头打印链表了。


代码测试

class Solution
{
public:
    vector<int> printListReversingly(ListNode* head) 
    {
        //创建栈
        stack<int> a;
        ListNode* pur = head;
        //入栈
        while(pur)
        {
            a.push(pur->val);
            pur = pur->next;
        }
        //创建新数组
        vector<int> b;
        //出栈
        while(!a.empty())
        {
        //提取栈顶元素
            b.push_back(a.top());
        //弹出栈顶元素
            a.pop();
        }
        return b;
    }
};

 删除链表的节点

题目链接:删除链表的节点


题目描述

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

说明:

  • 题目保证链表中节点的值互不相同
  • 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点

思路

<1>从链表的头节点开始循环遍历找到要删除节点的 前驱节点pur

<2>前驱节点与删除节点的后继节点链接(pur = pur->next->next)

注意

如果链表我们的 val 恰好为链表的头节点:我们直接返回剩余的链表即可(head->next)


代码测试

class Solution 
{
public:
    ListNode* deleteNode(ListNode* head, int val)
    {
        //判断 val 是否为链表的头节点
        if(head->val == val)
        {
            return head->next;
        }
        else
        {
            ListNode* pur = head;
        //循环遍历寻找 val 的前驱节点
        while(pur->next->val != val)
        {
            pur = pur->next;
        }
        //删除 val 节点
            pur->next = pur->next->next;
        return head;
        }
    }
};

 链表中倒数第k个节点

题目链接:链表中倒数第k个节点


题目描述

输入一个链表,输出该链表中倒数第 k 个结点。

注意:

  • k >= 1;
  • 如果 k 大于链表长度,则返回 NULL;

数据范围

链表长度 [0,30]。

样例

输入:链表:1->2->3->4->5 ,k=2

输出:4

思路一

两次遍历

假设整个链表有 n 个节点,那么倒数第 k 个节点就是从头节点开始的第 n-k+1 个节点。说明我们要遍历链表两次,第一次 统计 链表中节点的 个数 ,第二次就能找到倒数第 k 个节点。


代码测试一

class Solution
{
public:
    ListNode* findKthToTail(ListNode* pListHead, int k)
    {
        //判断链表和 k 是否合法
        if(pListHead == NULL||k ==0) return NULL;
        ListNode* pur = pListHead;
        int count = 0;
        //统计链表中的节点个数
        while(pur)
        {
            count++;
            pur = pur->next;
        }
        pur = pListHead;
        //判断 k 是否满足条件
        if(k>count) return NULL;
        //遍历寻找 k 节点
        for(int i = 1; i < count-k+1; i++)
        pur = pur->next;
            return pur;
    }
};

但是如果是在面试中,考核官更期待只需要遍历链表一次的解法

思路二

快慢双指针

我们可以定义两个指针 left right ,快指针 left 先从链表的头指针开始遍历向前走 k-1 步,慢指针 right 保持不动;从第 k 步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在 k-1,当快指针 left 到达链表的尾节点时,慢指针指向的刚好是倒数的 k 个节点。


代码测试二

class Solution 
{
public:
    ListNode* findKthToTail(ListNode* pListHead, int k)
    {
        //判断链表和 k 是否合法
        if(pListHead == NULL||k ==0) return NULL;
        ListNode* left = pListHead;
        ListNode* right = pListHead;
        //快指针开始走 k-1 步
        for(int i = 0;i<k-1;i++)
        {
        //如果left->next == NULL则说明链表长度小于 k 
            if(left->next)
            left = left->next;
            else
            return NULL;
        }
        //共同遍历
        while(left->next)
        {
            left = left->next;
            right = right->next;
        }
        return right;
    }
};

链表中环的入口结点 

题目链接:链表中环的入口结点


题目描述

给定一个链表,若其中包含环,则输出环的入口节点。

若其中不包含环,则输出null

数据范围

节点 val 值取值范围 [1,1000]。
节点 val 值各不相同。
链表长度 [0,500]。

样例

给定如上所示的链表:
[1, 2, 3, 4, 5, 6]
2
注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。

则输出环的入口节点3.

思路

这道题的思路可以借鉴一下我之前做的博客会更详细:环形链表

<1>如何确定一个链表包含一个环?快慢双指针

定义两个快慢指针在链表上移动,left 跑得快,right 跑得慢。当 leftright 从链表上的同一个节点开始移动时,如果该链表中没有环,那么 left 将一直处于 right 的前方;如果该链表中有环,那么 left 会先于 right 进入环,并且一直在环内移动。等到 right 进入环时,由于 left 的速度快,它一定会在某个时刻与 right 相遇,则链表中存在环。否则快指针 left 率先走到链表的末尾。我们可以定义:慢指针一次走一步,快指针一次走两步。

<2>如何确定链表中环的入口节点?数学证明

设为进入环前的链表长度为L,入口点到相遇点的距离为X,环的长度为C

right 走的距离为L+X

设 left 追上 right 时,转了 n 圈(n>=1)

left 走的距离为L+n\times C+X

任意时刻,left 指针走过的距离都为指针 right 的 2 倍

即为2(L+X) = L+n\times C+X化简为:L= n\times C - X

为了更好的理解我们写成这样L= (n-1)\times C +C- X

(n-1) x C 是 left 转的圈数,转了 (n-1) 圈后回到相遇点

故可以推出:如将此时两指针分别放在 起始位置 和 相遇位置 ,并以 相同速度 前进,当一个指针走完距离 L 时,另一个指针恰好走出,绕环 n-1 圈加上 C-X 的距离。

故两指针会在环开始位置相遇。

结论整理

<1>设置快慢指针,假如有环,他们最后一定相遇在环中。

<2>两个指针相遇后,让两个指针分别从链表头和相遇点重新出发,每次走一步,最后一定相遇于环入口。


代码测试

class Solution {
public:
    ListNode *entryNodeOfLoop(ListNode *head)
    {
        ListNode* left = head,*right = head;
        while(left&&left->next)
        {
            //寻找快慢指针相遇点
            left = left->next->next;
            right = right->next;
            if(left == right)
            {
            //相遇点
                ListNode* mid = left;
                while(mid != head)
                {
                     head = head->next;   
                     mid = mid->next;
                }
            //入口点
                return head;        
            }
        }    
        return NULL;
    }
};

反转链表 

题目链接:反转链表


题目描述

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

数据范围

链表长度 [0,30]。

样例

输入:1->2->3->4->5->NULL

输出:5->4->3->2->1->NULL

思路

快慢指针+前驱指针

我们在调节当前节点的指针 n2 的时候除了需要知道当前节点的本身还需要知道前驱节点(我们用 n1 来存储前驱节点的位置),这样只需要调节当前节点 n2 指针的指向便可完成链表的反转,为了避免调节时链表的丢失,我们需要在定义一个指针 n3 来存储后继节点的位置,然后循环遍历即可。


代码测试

class Solution 
{
public:
    ListNode* reverseList(ListNode* head) 
    {
         if(head == NULL)//判断链表是否为空
    {
        return head;
    }    
    ListNode *n1,*n2,*n3;
    n1 = NULL,n2 = head,n3 = head->next;
    while(n2)             //如果n2不为空就进入循环
    {
        n2->next = n1;    //修改n2的指向
        n1 = n2;         
        n2 = n3;
        if(n3)            //判断n3是否为空
        n3 = n3->next;    
    }
    return n1;
    }
};

合并两个排序的链表

题目链接:合并两个排序的链表


题目描述

输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。

数据范围

链表长度 [0,500]。

样例

输入:1->3->5 , 2->4->5

输出:1->2->3->4->5->5

思路一

递归

首先分析合并两个链表的过程:

<1>我们的分析从合并两个链表的头节点开始。链表 1 的头节点的值 小于 链表 2 的头节点的值,因此链表 1 的头节点就是我们合并新链表的头节点。

<2>我们继续合并两个链表中剩余的节点。在两个链表中剩下的节点依然是排序的,因此合并这两个链表的步骤和前面的步骤是一样的。我们还是比较两个头节点的值。此时链表 2 的头节点的值小于链表 1 的头节点的值,因此链表 2 的头节点的值将是合并剩余节点得到的链表的头节点。我们把这个节点和前面合并链表时得到的链表的尾节点 链接 起来。

当我们得到两个链表中值较小的头节点并把它链接到已经合并的链表之后,两个链表剩余的节点依然是排序的,因此合并的步骤和之前的步骤是样的。这就是典型的 递归 过程。


代码测试一

class Solution
{
public:
    ListNode* merge(ListNode* l1, ListNode* l2)
    {
        //判断链表是否为空
        if(l1 == NULL) return l2;
        else if(l2 == NULL) return l1;
        ListNode* head = NULL;
        //合并链表-比较两个链表的头节点
        if(l1->val>l2->val)
        {
            head =  l2;
        //递归
            head->next = merge(l2->next,l1);
        }
        else
        {
            head = l1;
            head->next = merge(l1->next,l2);
        }
        return head;
    }
};
在面试中考核管会更加青睐递归的做法,但是如果对递归不熟的我们可以 简单暴力 一点

思路二

迭代

l1l2 都不是空链表时,判断 l1 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

首先,我们设定一个哨兵节点 dummy  ,这可以在最后让我们比较容易地返回合并后的链表。我们维护一个 cur 指针,我们需要做的是调整它的 next 指针。

然后,我们重复以上过程,直到 l1 或者 l2 指向了 NULL:如果 l1 当前节点的值小于等于 l2 ,我们就把 l1 当前的节点接在 cur 节点的后面同时将 l1 指针往后移一位。否则,我们对 l2 做同样的操作。不管我们将哪一个元素接在了后面,我们都需要把 cur 向后移一位。

在循环终止的时候, l1 l2 至多有一个是非空的。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表即可。


代码测试二

class Solution 
{
public:
    ListNode* merge(ListNode* l1, ListNode* l2) 
    {
        //判断链表是否是空
        if(l1 == NULL) return l2;
        else if(l2 == NULL) return l1;
        //创建哨兵位记录首节点的位置
        ListNode* dummy = new ListNode(0);
        ListNode* cur = dummy;
        //合并链表
        while(l1&&l2)
        {
            if(l1->val>l2->val)
            {
                cur->next = l2;
                l2 =  l2->next;
            }
            else
            {
                cur->next = l1;
                l1 =  l1->next;
            }
            cur = cur->next;
        }
        //将非空链表链接到cur的后面
        cur->next = l1 == NULL?l2:l1;
        //返回合并链表
        return dummy->next;
    }
};

 

删除链表中重复的节点

题目链接:删除链表中重复的节点


题目描述

在一个排序的链表中,存在重复的节点,请删除该链表中重复的节点,重复的节点不保留。

数据范围

链表中节点 val 值取值范围 [0,100]。
链表长度 [0,100]。

样例1

输入:1->2->3->3->4->4->5

输出:1->2->5

样例2

输入:1->1->1->2->3

输出:2->3

思路

一次遍历

          

由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是 连续 的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。由于链表的头节点可能会被删除,因此我们需要使用哨兵位 dummy 来保存首节点的位置。

我们用指针 cur 指向链表的哨兵位 dummy ,随后开始对链表进行遍历。

如果当前  cur->next  cur->next->next 对应的元素相同,我们就将  cur->next   以及所有后面拥有相同元素值的节点全部删除。我们记下这个元素值 x ,随后不断将 cur->next   从链表中移除,直到空节点或者其元素值不等于 x 为止。此时,我们将链表中所有元素值为  的节点全部删除。

如果当前 cur->next  与 cur->next->next 对应的元素不相同,那么说明链表中只有一个的这样元素,那么我们就可以将 cur 指向  cur->next  

遍历完后我们返回 dummy->next 头节点即可。


代码测试

class Solution 
{
public:
    ListNode* deleteDuplication(ListNode* head)
    {
       //判断链表是否为空
        if (head == NULL) 
        {
            return NULL;
        }
       //创建哨兵位,并让其指向头节点
       ListNode* dummy = new ListNode(0);
       dummy->next = head;
       ListNode* cur = dummy;
       //循环遍历
       while(cur->next&&cur->next->next)
       {
       //判断是否有相同元素的节点
           if(cur->next->val == cur->next->next->val)
           {
       //记录重复元素
               int x = cur->next->val;
               while(cur->next&&cur->next->val == x)
               {
                   cur->next = cur->next->next;
               }
           }
           else
           {
               cur = cur->next;
           }
       }
      //返回链表的头节点
       return dummy->next;
    }
};

 

 两个链表的第一个公共结点 

题目链接:两个链表的第一个公共结点


输入两个链表,找出它们的第一个公共结点。

当不存在公共节点时,返回空节点。

数据范围

链表长度 [1,2000]。
保证两个链表不完全相同,即两链表的头结点不相同。

样例

给出两个链表如下所示:
A:        a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

输出第一个公共节点c1

思路一

双指针

在第一个链表上 顺序遍历 每个节点,每遍历到一个节点,就到第二个链表上顺序遍历每个节点。如果在第二个链表上有一个节点与第一个链表上的节点一样,则说明两个链表在这个节点重合。这样我们就找到了链表的公共节点。

<1>判断相交:先找两个链表的尾节点,节点的 地址相同 就相交。

<2>链表的长度不一样,两个指针不会同时到达链表的尾节点,所以我们要先遍历两个链表的长度,然后让长的链表先走 长度差 ,在同时找交点(第一个地址相同的即为交点)。

注意 要考虑两链表是否为空的情况


代码测试一

  • 时间复杂度:O(n+m)
  • 空间复杂度:O(1)

是一个即节省时间,又不浪费空间的最优解,足以获得面试官的青睐,拿到offer

class Solution 
{
public:
    ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) 
    {
        //判断链表是否为空
        if(headA == NULL) return NULL;
        if(headB == NULL) return NULL;
        ListNode* curA = headA;
        ListNode* curB = headB;
        int countA = 0,countB = 0;
        //遍历链表长度
        while(curA)
        {
            countA++;
            curA = curA->next;
        }
        while(curB)
        {
            countB++;
            curB = curB->next;
        }
        
       //两指针都已经遍历到末尾,比较尾节点判断是否相交
       if(curA != curB) return NULL;
       //较长的链表走完差值
       int gap = abs(countA-countB);
       ListNode* longList = headA;
       ListNode* shortList = headB;
       if(countB>countA)
       {
           longList = headB;
           shortList = headA;
       }
       while(gap--)
       {
           longList = longList->next;
       }
       //同时遍历两个链表寻找交点
       while(longList != shortList)
       {
           longList = longList->next;
           shortList = shortList->next;
       }
        return longList;
    }
};

思路二

如果两个链表有公共节点,那么公共节点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。可问题是,在单向链表中,我们只能从头节点开始按顺序遍历,最后才能到达尾节点。最后到达的尾节点却要最先被比较,这听起来是不是像 后进先出 ?于是我们就能想到用栈的特点来解决这个问题。

分别把两个链表的节点放入两个 里,这样两个链表的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的节点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的节点。


代码测试二

  • 时间复杂度:O(n+m)
  • 空间复杂度:O(n+m)

虽然不是最优解,但是还是比较容易想到和实现

class Solution 
{
public:
    ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB)
    {
        //创建栈
        stack<ListNode *> s1, s2;
        //入栈
        for (ListNode *p = headA; p != NULL; p = p->next) 
        {
            s1.push(p);
        }
        for (ListNode *p = headB; p != NULL; p = p->next) 
        {
            s2.push(p);
        }
        ListNode *ans = NULL;
        //比较栈中元素
        for ( ; !s1.empty() && !s2.empty() && s1.top() == s2.top(); s1.pop(), s2.pop())
            ans = s1.top();
        return ans;
    }
};

 献上最后的压轴题:该题是由 剑指offer面试题35 改编题,与原题类似、直观

 复杂链表的复刻

题目链接:复杂链表的复制


给你一个长度为 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
  • -10^4 <= Node.val <= 10^4
  • Node.random 为 null 或指向链表中的节点。

思路

迭代 + 节点拆分

(1)拷贝随机节点

我们首先将该链表中每一个节点拆分为两个相连的节点,例如对于链表 a→b→c ,我们可以将其拆分为 a→a′→b→b′→c→c′,其中 a′ 为原节点 a 的后继拷贝。

这样做的目的:建立原节点和拷贝节点的关联关系,因为位置是挨着的,找到了原节点就找到了拷贝节点

(2)拷贝随机指针

例如可以直接找到每一个拷贝节点 a′ 的随机指针应当指向的节点,即为其原节点 a 的随机指针 random  指向的节点 c 的后继拷贝节点 c′ :  copy->random = cur->random->next

注意 原节点的随机指针可能为空,我们需要特别判断这种情况。

(3)链接原链表和拷贝链表

<1>我们可以在原节点的后继位置进行对该节点的拷贝  

<2>然后拷贝节点的随机指针,即为原节点的 random 指针指向节点的后继拷贝节点

<3>链接原链表和拷贝链表


代码测试

时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
public:
    Node* copyRandomList(Node* head) {
        //拷贝链表,并插入到原节点的后面
        Node* cur = head;
        while(cur)
        {
            Node* next = cur->next;

            Node* copy = (Node*)malloc(sizeof(Node));
            copy->val = cur->val;

        //插入
            cur->next = copy;
            copy->next = next;

        //迭代往下走
            cur = next;
        }

        //置拷贝节点的随机指针random
        cur = head;
        while(cur)
        {
            Node* copy = cur->next;
        //判断原节点的随机指针是否为空
            if(cur->random != NULL)
                copy->random = cur->random->next;
            else
                copy->random = NULL;
            cur = copy->next;
        }

        //链接拷贝节点
        Node* copyHead = NULL, *copyTail = NULL;
        cur = head;
        while(cur)
        {
            Node* copy = cur->next;
            Node* next = copy->next;

        //copy解下来尾插
            if(copyTail == NULL)
            {
                copyHead = copyTail = copy;
            }
            else
            {   
                copyTail->next = copy;
                copyTail = copy;
            }

            cur->next = next;

            cur = next;
        }

        return copyHead;
    }
};

 

本次的 剑指offer 就介绍到这里, 希望大家早日拿到大厂offer

 

 

 

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

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

相关文章

燃气企业须知 :智慧燃气信息化管理平台的作用 ?

关键词&#xff1a;智慧燃气、燃气信息化、智慧燃气平台、智慧燃气建设、智慧燃气解决方案 智慧燃气信息化管理平台通过城市输气管网作为主要基础&#xff0c;各个终端用户进行协调&#xff0c;依托信息化数据进行管理&#xff0c;从而让整个工作环节流程达到高效智能优势。通…

【LeetCode】树的BFS(层序遍历)精选6题

目录 1. N 叉树的层序遍历&#xff08;中等&#xff09; 2. 二叉树的锯齿形层序遍历&#xff08;中等&#xff09; 3. 二叉树的最大宽度&#xff08;中等&#xff09; 4. 在每个树行中找最大值&#xff08;中等&#xff09; 5. 找树左下角的值&#xff08;中等&#xff09…

leetcode(动态规划)53.最大子数组和(C++详细解释)DAY12

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 提示 2.解答思…

数论 - 博弈论(Nim游戏)

文章目录 前言一、Nim游戏1.题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 2.算法 二、台阶-Nim游戏1.题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 2.算法 三、集合-Nim游戏1.题目描述输入格式输出格式数据范围输…

vue使用Nprogress进度条功能实现

下图中的这种顶部进度条是非常常见的&#xff0c;在vue项目中有对应的插件&#xff1a;Nprogress。 实现效果&#xff1a; csdn也在使用&#xff1a; 或者这样自己使用 1、安装 NProgress可以通过npm安装。 npm install --save nprogress 注意此处的--save等同于-s,就是将…

echats 时间直方图示例

需求背景 某订单有N个定时任务&#xff0c;每个任务的执行时间已经确定&#xff0c;希望直观的查看该订单的任务执行趋势 查询SQL&#xff1a; select UNIX_TIMESTAMP(DATE_FORMAT(exec_time,%Y-%m-%d %H:%i)) execTime, count(*) from order_detail_task where order_no 2…

【C++】vector模拟实现+迭代器失效

vector模拟实现 成员变量定义默认成员函数构造函数 迭代器范围for、对象类型匹配原则 容量操作sizeemptycapacityreserve成员变量未更新memcpy值拷贝 resize内置类型的构造函数 数据访问frontbackoperator[ ] 数据修改操作push_backpop_backswapclearinsertpos位置未更新无返回…

el-button 选择与非选择按钮批量处理

el-button 选择与非选择按钮批量处理 <el-button v-for"(voyage,i) in data[voyages][nowVoyage]":key"i"class"c-work-bts"type"primary":plain"nowWorkSpace!i"click"chooseWorkSpace(i)"size"small&qu…

C#快速配置NLog日志使用

首先我们需要在Nuget中安装Nlog和Nlog-Schema。 添加配置文件&#xff1a;NLog.config <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi"http://www.w3.org/2001…

CSS弹性布局

CSS弹性布局 一、概念 ​ 弹性盒子是 CSS3 的一种新的布局模式。 ​ CSS3 弹性盒&#xff08; Flexible Box 或 flexbox&#xff09;&#xff0c;是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。 ​ 引入弹性盒布局模型的目的是提供一…

山西电力市场日前价格预测【2024-02-21】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-21&#xff09;山西电力市场全天平均日前电价为470.29元/MWh。其中&#xff0c;最高日前电价为654.81元/MWh&#xff0c;预计出现在18:45。最低日前电价为355.63元/MWh&#xff0c;预计…

将Windows的系统日志自动收集并且转发到syslog服务器,百试百灵

将windows的系统日志自动收集并且转发到syslog服务器&#xff0c;百试百灵* **使用*Evtsys工具&#xff0c;他会自动收集windows系统日志&#xff0c;然后发送到syslog服务器&#xff0c;并且不乱码 下载链接&#xff1a;百度云永久链接 链接&#xff1a;https://pan.baidu.co…

D9741——用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。低电压输入时误操作保护电路, 定时闩锁、短路保护电路等功能

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点: 高精度基准电路 定时门锁、短路保护电路 低电压输入时误操作保护电路 输出基准电压(2.5V 超过工作范围能进行自动校正 封装形式: SOP16 应用: 电视摄像机 笔记本电…

5个顶级开源法学硕士大型语言模型 (LLM)

5个顶级开源法学硕士大型语言模型 (LLM)。 在快速发展的人工智能 (AI) 世界中&#xff0c;大型语言模型 (LLM) 已成为推动创新并重塑我们与技术交互方式的基石。 随着这些模型变得越来越复杂&#xff0c;人们越来越重视对它们的访问的民主化。 尤其是开源模型&#xff0c;在这…

算法面试八股文『 模型详解篇 』

说在前面 这是本系列的第二篇博客&#xff0c;主要是整理了一些经典模型的原理和结构&#xff0c;面试有时候也会问到这些模型的细节&#xff0c;因此都是需要十分熟悉的。光看原理还不够&#xff0c;最好是能用代码试着复现&#xff0c;可以看看李沐老师深度学习的教材&#…

线程池:优化多线程管理的利器

引言 同步和异步想必各位都有了解&#xff0c;同步简单来说就是一件事做完再去做下一件&#xff1b;异步则是不用等一件事做完&#xff0c;就可以去做另一件事&#xff0c;当一件事完成后可以收到对应的通知&#xff1b;异步一般应用于一些耗时较长的操作&#xff0c;比如大型…

量子计算:数据安全难题

当今数字技术面临的最大挑战之一是安全系统和数据。为此&#xff0c;人们设计了复杂的算法来加密数据并通过称为对称加密的框架来保护数据。虽然这已被证明是成功的&#xff0c;但量子计算的进步&#xff08;利用量子力学比传统计算机更快地解决复杂问题&#xff09;可能会彻底…

Flink的单元测试介绍及示例

本文详细的介绍了Flink的单元测试&#xff0c;分为有状态、无状态以及作业的测试&#xff0c;特别是针对无状态的单元测试给出了常见的使用示例。 本文除了maven依赖外&#xff0c;没有其他依赖。 一、Flink测试概述 Apache Flink 同样提供了在测试金字塔的多个级别上测试应用程…

离谱,华为食堂也要搞末位淘汰

华为饭堂 末位淘汰 今天逛职场 App&#xff0c;无意间翻到一篇帖子&#xff1a; 点开图片之前&#xff0c;我还以为只是普通的争霸赛被网友解读为末位淘汰。 点开图片后我却发现 ... 可以看出&#xff0c;是深圳华为的行政部做的海报&#xff0c;里面清晰写到&#xff1a;员工的…

QT-地形3D

QT-地形3D 一、 演示效果二、关键程序三、下载链接 一、 演示效果 二、关键程序 #include "ShaderProgram.h"namespace t3d::core {void ShaderProgram::init() {initializeOpenGLFunctions();loadShaders(); }void ShaderProgram::addShader(const QString &fil…