代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表

代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表

文章目录

  • 代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表
    • 1 链表理论基础
      • 1.1 链表的定义
      • 1.2 链表的类型
      • 1.3 链表的存储方式
      • 1.4 链表的操作性能分析
      • 1.5 链表和数组的区别
    • 2 LeetCode 203.移除链表元素
      • 2.1 不带虚拟头节点的删除操作
      • 2.2 带虚拟头节点的删除操作
    • 3 LeetCode 707.设计链表
      • 3.1 Python版本代码
      • 3.2 C++版本代码
    • 4 LeetCode 206.反转链表
      • 4.1 双指针法
      • 4.2 递归法
      • 4.3 头插法

1 链表理论基础

链表是一种常见的数据结构,它在计算机科学中用于存储一系列元素,链表的特点是其元素不必在内存中连续存储,这种结构提供了在序列内部插入和删除元素的高效操作,下面将结合408相关知识介绍一下有关链表的一些基础知识,以及链表与数组的区别。

1.1 链表的定义

链表由一系列称为“节点”的元素组成,每个节点包含两个部分:数据和指向列表中下一个节点的引用(或链接),在最简单的形式中,每个节点包含数据和一个指向列表中下一个节点的指针,即数据域(data)和指针域(next)。

1.2 链表的类型

  • 单向链表:每个节点只有指向下一个节点的链接,其节点类型定义如下(参考王道数据结构单链表定义):

    typedef struct LNode{ElemType data;   //数据域struct LNode *next;  //指针域
    }LNode, *LinkList
    

    利用单链表可以解决顺序表需要大量连续存储单元的缺点,但单链表附加指针域,也存在浪费存储空间的缺点。由于单链表的元素离散地分布在存储空间中,所以单链表是非随机存取的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。

    通常用头指针来标识一个单链表,如单链表L,头指针为NULL时表示一个空表。此外,为了操作上的方便,在单链表第一个结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,也可以记录表长等信息。头结点的指针域指向线性表的第一个元素结点,如下图所示(来源于王道数据结构):

    在这里插入图片描述

    头结点和头指针的区分:不管带不带头结点,头指针都始终指向链表的第一个结点,而头结点是带头结点的链表中的第一个结点,结点内通常不存储信息。

    引入头结点后,可以带来两个优点:

    ①由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。

    ②无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就得到了统一。

  • 双向链表:每个节点有两个链接,一个指向前一个节点(即prior指针),另一个指向下一个节点(即next指针),是为了克服单链表的缺点,所以引入了双链表。

    其节点类型定义如下(参考王道数据结构双链表定义):

    typedef struct DNode{ElemType data;   //数据域struct DNode *prior,*next;  //前驱和后继指针
    }LNode, *DLinklist
    

    其表示示意图如下图所示(来源于王道数据结构):

    在这里插入图片描述

    双链表在单链表的结点中增加了一个指向其前驱的prior 指针,因此双链表中的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操作的实现上,与单链表有着较大的不同。这是因为“链”变化时也需要对prior 指针做出修改,其关键是保证在修改的过程中不断链。此外,双链表可以很方便地找到其前驱结点,因此,插入、删除操作的时间复杂度仅为O(1)。

  • 循环链表:链表中的最后一个节点指向第一个节点或其他之前的节点,形成一个环,循环单链表和单链表的区别在于,表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环,如下图所示(来源于王道数据结构):

    在这里插入图片描述

    在循环单链表中,表尾结点*r的next域指向L,故表中没有指针域为NULL的结点,因此循环单链表的判空条件不是头结点的指针是否为空,而是它是否等于头指针。

    循环单链表的插入、删除算法与单链表的几乎一样,所不同的是若操作是在表尾进行,则执行的操作不同,以让单链表继续保持循环的性质。当然,正是因为循环单链表是一个“环”,因此在任何一个位置上的插入和删除操作都是等价的,无须判断是否是表尾。

    在单链表中只能从表头结点开始往后顺序遍历整个链表,而循环单链表可以从表中的任意一个结点开始遍历整个链表。有时对循环单链表不设头指针而仅设尾指针,以使得操作效率更高。其原因是,若设的是头指针,对在表尾插入元素需要O(n)的时间复杂度,而若设的是尾指针r,r->next即为头指针,对在表头或表尾插入元素都只需要O(1)的时间复杂度。

  • 循环双链表:结合了双向链表和循环链表的特点,不同的是在循环双链表中,头节点的prior指针还要指向表尾节点,其表示示意图如下图所示(来源于王道数据结构):

    在这里插入图片描述

    在循环双链表L中,某结点*p为尾结点时,p->next==L;当循环双链表为空表时,其头结点的prior域和next域都等于L。

1.3 链表的存储方式

链表中的节点不需要在内存中连续存储(这一点和数组相反),每个节点只需存储其数据部分和指向列表中下一个(和/或前一个)节点的指针,这种存储方式使得链表在插入和删除操作时能够较少地移动或重新排列其他元素,如下图所示(来源于代码随想录):
在这里插入图片描述

1.4 链表的操作性能分析

  • 插入和删除:链表可以在任何位置高效地插入或删除节点,这些操作的时间复杂度通常是 O(1),但如果需要找到特定位置,则可能需要 O(n) 的时间,其中 n 是链表的长度。
  • 搜索:搜索一个元素在链表中的位置或者搜索链表中的特定元素的效率较低,时间复杂度为 O(n)。
  • 访问:对于链表的随机访问(例如访问第 n 个元素),效率低下,因为需要从头节点开始遍历链表,时间复杂度为 O(n)。

1.5 链表和数组的区别

特性数组链表
存储方式在内存中连续存储元素元素分布在内存中不连续的节点中
访问时间快速随机访问,O(1)需要从头遍历,O(n)
插入和删除操作可能需要移动元素,O(n)在已知位置快速操作,O(1);寻找位置时,O(n)
内存利用率可能造成内存浪费或空间不足动态分配,高效利用内存
内存分配静态或动态内存分配总是使用动态内存分配
实现实现简单,支持多种操作实现复杂,需要额外内存存储指针
应用场景元素数量固定,频繁访问元素数量变化大,频繁插入删除

2 LeetCode 203.移除链表元素

题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

示例 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
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104]
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

在移除链表元素时我们需要考虑是否需要给原始链表添加虚拟头节点(也叫哨兵节点),因为如果直接在原始链表上我们需要首先判断是否删除的是head所指的头节点,头节点的删除和其他的节点的删除是不一样的,但是如果我们使用虚拟头节点来进行操作的话,可以统一删除节点的操作,下面我们将两种情况的代码都写出来。

2.1 不带虚拟头节点的删除操作

(1)Python版本代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def removeElements(self, head, val):# 首先移除头部需要删除的节点while(head != None and head.val == val):    # 注意head != Nonehead = head.next# 现在头部节点不需要删除,cur指向第一个不需要删除的节点cur = headwhile(cur != None and cur.next != None):    # 注意cur.next != Noneif cur.next.val == val:    # 如果下一个节点需要删除cur.next = cur.next.next    # 删除下一个节点else:    # 如果下一个节点不需要删除cur = cur.next    # cur指向下一个节点return head

(2)C++版本代码:

/*** 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* removeElements(ListNode* head, int val) {// 首先移除头部需要删除的节点while (head != nullptr && head->val == val) {head = head->next;}// 现在头部节点不需要删除ListNode* cur = head;// 遍历链表while (cur != nullptr && cur->next != nullptr) {if (cur->next->val == val) {// 如果下一个节点需要删除cur->next = cur->next->next;} else {// 如果下一个节点不需要删除cur = cur->next;}}return head;}
};

2.2 带虚拟头节点的删除操作

(1)Python版本代码:

class Solution:def removeElements(self, head, val):dummy = ListNode(0, head)   # 创建虚拟头节点dummy.next = head   # 虚拟头节点指向headcur = dummy    # cur指向虚拟头节点while cur.next:if cur.next.val == val:cur.next = cur.next.nextelse:cur = cur.nextreturn dummy.next

(2)C++版本代码:

class Solution {
public:ListNode* removeElements(ListNode* head, int val) {// 创建一个虚拟头节点ListNode dummy(0);dummy.next = head;// cur 指向虚拟头节点ListNode* cur = &dummy;// 遍历链表while (cur->next != nullptr) {if (cur->next->val == val) {// 删除下一个节点cur->next = cur->next->next;} else {// 移动到下一个节点cur = cur->next;}}return dummy.next;}
};

本题比较简单,主要是介绍两种处理方法,最关键是要理解虚拟头结点的使用技巧,这个对链表题目很重要,我更偏向于使用虚拟头节点来进行操作,因为这样可以统一删除操作,同样添加操作也类似,可以简化代码。

3 LeetCode 707.设计链表

题目链接:https://leetcode.cn/problems/design-linked-list/description/

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

示例:

输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
myLinkedList.get(1);              // 返回 2
myLinkedList.deleteAtIndex(1);    // 现在,链表变为 1->3
myLinkedList.get(1);              // 返回 3

提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • 调用 getaddAtHeadaddAtTailaddAtIndexdeleteAtIndex 的次数不超过 2000

我们后续有关链表的操作都将默认使用虚拟头节点,这样会使代码看起来更加简洁,上面也介绍过了。

这道题目就是考察我们对链表常见的操作的掌握情况,也就是下面的这几种操作:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点

这道题目掌握牢固了,基本上链表操作也就可以了,其他类型的链表也都是类似的操作。

需要注意的是在链表的插入操作中,我们需要注意插入操作的执行顺序,防止出现断链的情况,这一点在408数据结构中也经常考察,就比如在刚过去的2024年408考试中第一道选择题就考察了链表的操作,需要特别注意。

下面我们直接写出每个函数的代码。

3.1 Python版本代码

class ListNode:def __init__(self, val = 0, next = None):self.val = valself.next = nextclass MyLinkedList:def __init__(self):self.dummy = ListNode()self.size = 0# 获取链表中下标为 `index` 的节点的值。如果下标无效,则返回 `-1` 。def get(self, index: int) -> int:if index < 0 or index >= self.size:     return -1cur = self.dummy.nextwhile index:cur = cur.nextindex -= 1return cur.val# 在链表头部插入一个节点,该节点的值为 `val` 。插入后,新节点将成为链表的第一个节点。def addAtHead(self, val: int) -> None:self.dummy.next = ListNode(val, self.dummy.next)self.size += 1# 将值为 `val` 的节点插入到链表中的第一个值为 `val` 的节点之后。def addAtTail(self, val: int) -> None:cur = self.dummywhile cur.next:cur = cur.nextcur.next = ListNode(val)self.size += 1# 在链表中的第 index 个节点之前,插入值为 `val` 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。def addAtIndex(self, index: int, val: int) -> None:if index < 0 or index > self.size:returncur = self.dummywhile index:cur = cur.nextindex -= 1cur.next = ListNode(val, cur.next)self.size += 1# 删除链表中的第 index 个节点。如果 index 等于链表的长度,则删除链表中的最后一个节点。def deleteAtIndex(self, index: int) -> None:if index < 0 or index >= self.size:returncur = self.dummywhile index:cur = cur.nextindex -= 1cur.next = cur.next.nextself.size -= 1

3.2 C++版本代码

// class ListNode {
// public:
//     int val;
//     ListNode *next;
//     ListNode(int val = 0, ListNode *next = nullptr) : val(val), next(next) {}
// };class MyLinkedList {
public:// 构造函数MyLinkedList() {dummy = new ListNode(0);  // 创建一个虚拟头节点size = 0;}// 析构函数,释放链表占用的内存~MyLinkedList() {ListNode* cur = dummy;while (cur != nullptr) {ListNode* next = cur->next;delete cur;  // 使用 delete 释放内存cur = next;}}// 获取指定索引的节点值int get(int index) {if (index < 0 || index >= size) {return -1;}ListNode* cur = dummy->next;while (index--) {cur = cur->next;}return cur->val;}// 在链表头部添加节点void addAtHead(int val) {dummy->next = new ListNode(val, dummy->next);size++;}// 在链表尾部添加节点void addAtTail(int val) {ListNode* cur = dummy;while (cur->next != nullptr) {cur = cur->next;}cur->next = new ListNode(val);size++;}// 在指定索引添加节点void addAtIndex(int index, int val) {if (index < 0 || index > size) {return;}ListNode* cur = dummy;while (index--) {cur = cur->next;}cur->next = new ListNode(val, cur->next);size++;}// 删除指定索引的节点void deleteAtIndex(int index) {if (index < 0 || index >= size) {return;}ListNode* cur = dummy;while (index--) {cur = cur->next;}ListNode* temp = cur->next;cur->next = cur->next->next;delete temp;  // 删除节点size--;}private:ListNode* dummy;  // 虚拟头节点int size;  // 链表大小
};

对于释放内存操作,需要注意的是在 C++ 中,应当使用 delete 而非 free() 来释放由 new 分配的内存,newdelete 是 C++ 中处理动态内存的标准方式,它们不仅分配和释放内存,还调用对象的构造函数和析构函数,相比之下,malloc()free() 是 C 语言中的函数,它们只处理内存的分配和释放,而不调用构造函数和析构函数。

4 LeetCode 206.反转链表

题目链接:https://leetcode.cn/problems/reverse-linked-list/

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

在这里插入图片描述

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

示例 2:

在这里插入图片描述

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

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

这道题目有点像有一年的408算法题,我去翻了一下,是2019年的算法题,那道题目需要反转三次,但是这两道题目都是类似的操作,下面我贴出408的2019年算法题:
在这里插入图片描述

下面是2024版王道数据结构中的解法:

在这里插入图片描述

回到这题来,这道题目我们可以首先考虑使用双指针方法来有效的反转链表。

4.1 双指针法

我们使用两个指针:curprecur 指向当前要处理的节点,而 pre 存储 cur 的前一个节点,通过遍历链表,逐个改变节点的指向,直到链表完全反转,需要注意的是反转代码的执行顺序,我们需要设置一个临时指针temp保存当前节点,避免首先反转之后cur的值已经变化然后出现指向错误。在每次迭代中,将 curnext 指针指向 pre,当 curNone 时,pre 将指向新的头节点,完成反转。

(1)Python版本实现代码:

class Solution:def reverseList(self, head):cur = head  # 当前节点pre = None  # 前一个节点while cur:  # 当前节点不为空temp = cur.next  # 临时节点cur.next = pre  # 当前节点指向前一个节点pre = cur     # 前一个节点指向当前节点cur = temp    # 当前节点指向下一个节点return pre  # 返回前一个节点

(2)C++版本实现代码:

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* cur = head;  // 当前节点ListNode* pre = nullptr;  // 前一个节点while (cur != nullptr) {ListNode* temp = cur->next;  // 临时节点,保存当前节点的下一个节点cur->next = pre;  // 当前节点指向前一个节点pre = cur;  // 前一个节点指向当前节点cur = temp;  // 当前节点指向下一个节点}return pre;  // 返回前一个节点,即新的头节点}
};

4.2 递归法

我们还可以使用递归的方法简化双指针法的代码,但是不推荐新手首先写递归方法,因为递归方法比较抽象,难以理解,更重要的还是双指针的实现思路,我们先写出双指针的解法之后我们就可以按照双指针的思路对应的写出递归版的代码。

(1)Python版本实现代码:

class Solution:def reverse(self, cur, pre):    if cur == None:return pretemp = cur.nextcur.next = prereturn self.reverse(temp, cur)def reverseList(self, head):return self.reverse(head, None)

(2)C++版本实现代码:

class Solution {
public:ListNode* reverse(ListNode* cur, ListNode* pre) {if (cur == nullptr) {return pre;}ListNode* temp = cur->next;cur->next = pre;return reverse(temp, cur);}ListNode* reverseList(ListNode* head) {return reverse(head, nullptr);}
};

4.3 头插法

另外我们再介绍一种实现思路,那就是利用链表的头插法来解决这道题目,头插法的基本思想是逐个将原链表的节点插入到一个新链表的头部,在本题中也就是逆用头插法,首先创建一个新的虚拟头节点,遍历原链表,每次迭代中,将当前节点从原链表中移除,将该节点插入到新链表的头部,继续遍历,直到原链表为空,最后新链表的头节点即为反转后的链表头节点。

(1)Python版本实现代码:

class Solution:def reverseList(self, head):new_head = None  # 新链表的头节点,初始为 Nonecur = headwhile cur:temp = cur.next  # 保存当前节点的下一个节点cur.next = new_head  # 将当前节点插入到新链表的头部new_head = cur  # 更新新链表的头节点cur = temp  # 移动到原链表的下一个节点return new_head

(2)C++版本实现代码:

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* new_head = nullptr;  // 新链表的头节点,初始为 nullptrListNode* cur = head;while (cur != nullptr) {ListNode* temp = cur->next;  // 保存当前节点的下一个节点cur->next = new_head;  // 将当前节点插入到新链表的头部new_head = cur;  // 更新新链表的头节点cur = temp;  // 移动到原链表的下一个节点}return new_head;  // 返回新链表的头节点,即反转后的头节点}
};

在头插法代码中new_head 代表新链表的头节点,最初为 None,在每次迭代中,我们将 cur(当前处理的节点)从原链表中移除,并将其插入到新链表的头部,这个过程一直持续到原链表被完全遍历,最终new_head 将成为反转后链表的头节点。

头插法算是提供了另一种有效的链表反转方法,特别适用于需要创建反转链表的副本的情况。

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

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

相关文章

使用Adobe Acrobat Pro DC给pdf文件填加水印

前言 GPT4的官方售价是每月20美元&#xff0c;很多人并不是天天用GPT&#xff0c;只是偶尔用一下。 如果调用官方的GPT4接口&#xff0c;就可以按使用量付费&#xff0c;用多少付多少&#xff0c;而且没有3个小时内只能提问50条的使用限制。 但是对很多人来说调用接口是比较麻烦…

使用new pm写一个pass

范例来自LLVM Techniques, Tips, and Best Practices Clang and Middle-End Libraries llvm ir到ir是由一个个pass处理的&#xff0c;从一个ir到另一个ir会改变一些东西 书里面就是说想要给指针变量添加一个noalias属性 书里面使用插件的形式&#xff0c;但是不知道怎么我搞不…

在阿里巴巴,领导提拔你不是看重你的能力

很多人都在想&#xff0c;为什么领导总是不提拔你&#xff0c;难道真的是如领导给你的反馈“你的能力不行”&#xff0c;这里我想告诉大家&#xff0c;这件事情绝对没有这么简单&#xff0c;尤其是在阿里巴巴这样“江湖气”非常浓的大厂。 Part.1 领导要提拔你&#xff0c;绝对…

网络变压器POE的功能

网络变压器&#xff0c;也被称为POE&#xff08;Power over Ethernet&#xff09;&#xff0c;是一种用于在以太网中传输数据和电力的技术。它的主要功能包括&#xff1a; 1. 传输数据&#xff1a;网络变压器可以传输高速的网络数据&#xff0c;如10/100/1000Mbps。 2. 传输电…

原型模式

为什么要使用原型模式 不用重新初始化对象&#xff0c;而是动态地获得对象运行时的状态。适用于当创建对象的成本较高时&#xff0c;如需进行复杂的数据库操作或复杂计算才能获得初始数据。 优点是可以隐藏对象创建的细节&#xff0c;减少重复的初始化代码&#xff1b;可以在…

代码随想录算法训练营第六天|哈希表理论基础,242.有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和

刷题建议 刷题建议与debug 代码随想录目前基本都有了视频讲解&#xff0c;一定要先看视频&#xff0c;事半功倍。写博客&#xff0c;将自己的感悟沉淀下来&#xff0c;不然会忘大家提问的时候&#xff0c;记得要把问题描述清楚&#xff0c;自己在哪一步遇到了问题&#xff0c…

【工具栏】jclasslib 插件的安装和使用

1. 安装 2.使用 安装之后 在 view 的 ToolWindows 里也有一个这样的窗口 jclasslib 的主要作用是查看字节码的相关信息 package com.test;public class Test {public static void main(String[] args) {Integer a 1;int b a 2;} }例如我写了一段这样的代码&#xff0c;然后去…

蓝凌EIS智慧协同平台 多处SQL注入漏洞复现

0x01 产品简介 蓝凌EIS智慧协同平台是一款专为企业提供高效协同办公和团队合作的产品。该平台集成了各种协同工具和功能,旨在提升企业内部沟通、协作和信息共享的效率。 0x02 漏洞概述 由于蓝凌EIS智慧协同平台 doc_fileedit_word.aspx、frm_form_list_main.aspx、frm_butt…

vcruntime140.dll已加载,但找不到入口点的处理方法分享

当遇到错误提示“vcruntime140.dll已加载&#xff0c;但找不到入口点”时&#xff0c;很多人可能会感到困惑&#xff0c;不知道如何去处理这个问题。不过没有必要紧张&#xff0c;在这里我会为大家详细解释 vcruntime140.dll 文件是什么&#xff0c;并指导大家如何高效地解决 v…

最佳实践:如何在 SoapUI 中进行 REST 服务的测试

SoapUI 频繁地被选择为 SOAP 和 REST API 的自动化测试利器&#xff0c;得益于其友好的用户界面&#xff0c;测试人员毫不费力便可校验 REST 和 SOAP 协议的 Web 服务。它尤其适用于那些需要进行复杂测试的场合。 1、设置接口 我利用了 Swagger 去设置了一批即将投入使用的接…

数字集成系统设计——物理设计

目录 一、布局规划 1.1 规划 1.2 I/O单元 1.3 电源网络 1.3.1 要求 1.3.2 网络架构 1.3.3 混合信号芯片示例 1.4 布局 二、时钟分布 2.1 时钟偏斜 2.2 时钟分布网络 2.3 时钟树综合 2.4 时钟树收敛 三、布线与参数提取 3.1 布线(Routing) 3.2 布线规则示例 …

全球化时代跨境企业协作之道:实用策略与实践分享

全球化时代跨境企业如何更好地异地协作&#xff1f;是许多跨境企业亟待解决的问题。ZOHO作为全球化企业服务品牌&#xff0c;又给出了怎样的答案&#xff1f; Zoho Workdrive企业网盘&#xff0c;为跨境企业提供了一种高效、安全的文件传输和协作方式。 Zoho Workdrive…

对比学习2024最新SOTA&应用方案分享,附14篇必读论文和代码

同学们发现没有&#xff0c;对比学习在我们的日常工作生活中已经很常见了&#xff0c;比如推荐系统任务&#xff0c;为用户推荐相似的商品或预测用户的购买行为&#xff1b;又比如图像检索&#xff0c;为用户找相似图片或识别不同物体。另外还有语音识别、人脸识别、NLP&#x…

C++:cout 的一些注意事项

有时cout不会将结果立即输出到屏幕&#xff08;也就是缓冲&#xff09;&#xff0c;该情况不会对竞赛测评有影响。 例子如下&#xff1a; ps:用puts立即输出 原因&#xff1a; 解决方法&#xff1a;在每一个cout后跟\n或flush cout << "This will be immediately d…

逆矩阵的基本性质(常用)

目录 一、最常用的屠龙公式 二、逆矩阵的一般是出题方式&#xff08;重点&#xff01;&#xff01;&#xff09;判断证明A是否可逆并求出A的逆矩阵 一、最常用的屠龙公式 1、 2、 3、A A |A|E 二、逆矩阵的一般是出题方式&#xff08;重点&#xff01;&#xff01;…

SwiftUI 为任意视图加上徽章(Badge)而想到的(上)

概览 在小伙伴们看来为 SwiftUI 视图添加徽章是一件轻松愉快的“消遣”,几乎不费吹灰之力。但随着需求的升级实现难度可能会“陡然而升”。 从上面演示图中可以看到:无论徽章中的数字是多少、无论徽章采用什么样的偏移方式,徽章的显示都“得体大方、游刃有余”,这是怎么做…

膜结构球形影院为观众打造观影新体验

在数字科技快速发展的当下&#xff0c;轻空间公司打破传统影院的束缚&#xff0c;领航未来娱乐体验的创新浪潮。膜结构球形影院问世&#xff0c;它不仅仅是一个娱乐场所&#xff0c;更是一场極致沉浸感的感官之旅&#xff0c;为观众带来震撼性的视听冲击。 沉浸式体验的新纪元 …

JDBC PrepareStatement 的使用(附各种场景 demo)

在 Java 中&#xff0c;与关系型数据库进行交互是非常常见的任务之一。JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 平台的一个标准 API&#xff0c;用于连接和操作各种关系型数据库。其中&#xff0c;PreparedStatement 是 JDBC 中的一个重要接口&#xf…

护眼灯有蓝光吗?没有蓝光的护眼灯推荐

现在的家长对于孩子的学习还是十分重视的&#xff0c;不仅会选择给他们报各种补习班、兴趣班&#xff0c;在学习设备方面也是尽可能地提供最好的&#xff0c;不管是各种文具还是良好的用光环境。为了拥有良好的光线条件&#xff0c;保护好孩子们的稚嫩的眼睛&#xff0c;他们会…

强化学习应用(一):基于Q-learning的无人机物流路径规划研究(提供Python代码)

一、Q-learning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个价值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是通过不断更新一个称为Q值的…