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

news2024/11/17 13:21:58

代码随想录算法训练营第三天 | 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 != None
            head = head.next
        # 现在头部节点不需要删除,cur指向第一个不需要删除的节点
        cur = head
        while(cur != None and cur.next != None):    # 注意cur.next != None
            if 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   # 虚拟头节点指向head
        cur = dummy    # cur指向虚拟头节点
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return 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 = val
        self.next = next

class 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 -1
        cur = self.dummy.next
        while index:
            cur = cur.next
            index -= 1
        return 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.dummy
        while cur.next:
            cur = cur.next
        cur.next = ListNode(val)
        self.size += 1

    # 在链表中的第 index 个节点之前,插入值为 `val` 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。
    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return
        cur = self.dummy
        while index:
            cur = cur.next
            index -= 1
        cur.next = ListNode(val, cur.next)
        self.size += 1

    # 删除链表中的第 index 个节点。如果 index 等于链表的长度,则删除链表中的最后一个节点。
    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:
            return
        cur = self.dummy
        while index:
            cur = cur.next
            index -= 1
        cur.next = cur.next.next
        self.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 pre
        temp = cur.next
        cur.next = pre
        return 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  # 新链表的头节点,初始为 None
        cur = head
        while 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;  // 新链表的头节点,初始为 nullptr
        ListNode* 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.coloradmin.cn/o/1377377.html

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

相关文章

电脑上不安装Oracle,但是虚拟机装了Oracle,怎么连接到虚拟机里的Oracle数据库呢?

1、准备工作 1.1、确定数据库版本信息 注&#xff1a;如果知道数据库的版本信息&#xff0c;这个步骤可以跳过。 比较简单的方法&#xff0c;直接看数据库的安装位置&#xff0c;也就是数字&#xff08;但是这个方法确定就是&#xff0c;不好确定是多少位的数据库&#xff09;…

高性能mysql 第三版 读书笔记

MySQL中的tmp_table_size和max_heap_table_size|极客笔记 mysql占用内存过高调优方法_tmp_table_size过大阻塞-CSDN博客 查看mysql分配的内存 mysql查看内存利用状态_mob6454cc6d81c9的技术博客_51CTO博客 https://www.cnblogs.com/stronger-xsw/p/13632505.html

企业信息化规划该如何落地?以制造型企业为例

企业信息化规划如何落地&#xff1f; 规划做好了&#xff0c;蓝图也画好了&#xff0c;人手一块大饼也已经揣好了&#xff0c;那么该怎么落地呢&#xff0c;这才是最关键的。 我将企业信息化规划落地分为4个周期&#xff0c;以最典型的制造行业为例&#xff0c;以简道云这个企…

JRT界面打开器

开发BS界面时候有个问题&#xff0c;如果新做页面还没挂菜单&#xff0c;那么测试新页面有两个办法&#xff0c;一是把菜单挂上用&#xff0c;一是手输URL。而我在开发阶段两个事都不想干&#xff0c;那么怎么解决呢&#xff1f; 以前WebLoader启动时候会启动C#写的URL辅助器 …

仓储|仓库管理水墨屏RFID电子标签2.4G基站CK-RTLS0501G功能说明与安装方式

随着全球智能制造进度的推进以及物流智能化管理水平的升级&#xff0c;行业亟需一种既能实现RFID批量读取、又能替代纸质标签在循环作业、供应链管理以及实现动态条码标签显示的产品。在此种行业需求背景下&#xff0c;我是适时推出了基于墨水屏显示技术的VT系列可视化超高频标…

Invalid bound statement(只有调用IService接口这一层会报错的)

问题描述:controller直接调用实现类可以,但是一旦调用IService这个接口这一层就报错. 找遍了大家都说是xml没对应好,但是我确实都可以一路往下跳,真的对应好了.结果发现是 MapperScan写错了,如下才是对的. MapperScan的作用是不需要在mapper上一直写注解了,只要启动类上写好就放…

OpenCV-Python(32):SIFT算法

目标 学习SIFT 算法的概念学习在图像中查找SIFT关键点和描述符 原理及介绍 在前面两节我们学习了一些角点检测技术&#xff1a;比如Harris 等。它们具有旋转不变特性&#xff0c;即使图片发生了旋转&#xff0c;我们也能找到同样的角点。很明显即使图像发生旋转之后角点还是角…

基于SkyEye仿真6678处理器:实现国产操作系统ReWorks仿真运行

信号处理的数据量以及实时性的要求随着嵌入式技术的发展不断提高&#xff0c;众多厂商和研究所选择多核DSP处理器芯片去替代原有的单核DSP&#xff0c;并运行嵌入式操作系统来保证信号处理的实时性以及精确性。然而受到硬件资源或者项目实施周期限制&#xff0c;软件工程师调试…

JS实现网页轮播图

轮播图也称为焦点图&#xff0c;是网页中比较常见的网页特效。 1、页面基本结构&#xff1a; 大盒子focus&#xff0c;里面包含 左右按钮ul 包含很多个li &#xff08;每个li里面包含了图片&#xff09;下面有很多个小圆圈 因为我们想要点击按钮&#xff0c;轮播图左右播放&a…

“消费新纪元:从传统消费到消费增值的跨越!“

你是否已经厌倦了传统消费模式&#xff0c;感觉每一次购物只是让钱从左手流到右手&#xff1f;现在&#xff0c;一个新的消费模式正在兴起&#xff0c;它让你的消费变得更有价值&#xff01; 消费增值是一种创新的消费理念&#xff0c;它让你在享受优质商品和服务的同时&#x…

学生公寓里如何进行安全用电管理

安科瑞武陈燕acrelcy 学校肩负着教育、科研和社会服务的重任&#xff0c;是构成社会的重要社区&#xff0c;也是资源能源消费的大户&#xff0c;其中学生公寓电能的消耗占到了学校整体能源消耗的很大部分&#xff0c;根据国家建设节约型校园的要求&#xff0c;各高校对电能的管…

2023年全国职业院校技能大赛软件测试赛题—单元测试卷①

单元测试 一、任务要求 题目1&#xff1a;根据下列流程图编写程序实现相应分析处理并显示结果。返回文字“xa*a*b的值&#xff1a;”和x的值&#xff1b;返回文字“xa-b的值&#xff1a;”和x的值&#xff1b;返回文字“xab的值&#xff1a;”和x的值。其中变量a、b均须为整型…

Oracle 19c OCP 1z0 082考场真题解析第32题

考试科目&#xff1a;1Z0-083 考试题量&#xff1a;85 通过分数&#xff1a;57% 考试时间&#xff1a;150min本文为云贝教育郭一军&#xff08;微信&#xff1a;guoyJoe&#xff09;原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎…

在 Nvidia Docker 容器编译构建显存优化加速组件 xFormers

本篇文章&#xff0c;聊聊如何在新版本 PyTorch 和 CUDA 容器环境中完成 xFormers 的编译构建。 让你的模型应用能够跑的更快。 写在前面 xFormers 是 FaceBook Research &#xff08;Meta&#xff09;开源的使用率非常高的 Transformers 加速选型&#xff0c;当我们使用大模…

可以打印试卷的软件有哪些?推荐这几款

可以打印试卷的软件有哪些&#xff1f;随着科技的飞速发展&#xff0c;越来越多的学习工具如雨后春笋般涌现&#xff0c;其中&#xff0c;能够打印试卷的软件尤其受到广大学生和家长的青睐。这些软件不仅方便快捷&#xff0c;而且内容丰富&#xff0c;可以满足不同学科、不同年…

从零学Java Set集合

Java Set集合 文章目录 Java Set集合1 Set 集合2 Set实现类2.1 HashSet【重点】2.2 LinkedHashSet2.3 TreeSet 3 Comparator 自定义比较器 1 Set 集合 特点&#xff1a;无序无下标、元素不可重复。 方法&#xff1a;全部继承自Collection中的方法。 常用方法&#xff1a; publ…

windos exe 以服务的形式运行(开机运行)

windos 品台编写的 小工具 exe 或者 批处理 .bat 经常需要开机自启动&#xff0c;可以直接把它 加在开启启动项&#xff0c;或者做成 windos服务&#xff0c;这样既可以开机自动启动而且还可以 防止误触关闭掉&#xff1b; windos 以服务启动 exe/bat 的通用方式&#xff1…

js逆向第18例:猿人学第15题备周则意怠-常见则不疑

文章目录 一、前言二、定位关键参数三、代码实现四、参考文献一、前言 任务十五:抓取这5页的数字,计算加和并提交结果 二、定位关键参数 先找到数据接口 可以看到接口的url地址中存在变量m如下 进入堆栈,定位m值 如下图逻辑很清晰,可以看到window.

ChatGPT到底能做什么呢?

1、熟练掌握ChatGPT提示词技巧及各种应用方法&#xff0c;并成为工作中的助手。 2、通过案例掌握ChatGPT撰写、修改论文及工作报告&#xff0c;提供写作能力及优化工作 3、熟练掌握ChatGPT融合相关插件的应用&#xff0c;完成数据分析、编程以及深度学习等相关科研项目。 4、…

【AI视野·今日Sound 声学论文速览 第四十三期】Mon, 8 Jan 2024

AI视野今日CS.Sound 声学论文速览 Mon, 8 Jan 2024 Totally 6 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers MusicAOG: an Energy-Based Model for Learning and Sampling a Hierarchical Representation of Symbolic Music Authors Yikai Qian, Tia…