代码随想录算法训练营day6 | 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1.两数之和

文章目录

    • 哈希表
    • 哈希函数
    • 哈希冲突
      • 拉链法
      • 线性探测法
    • 常见的三种哈希结构
      • 集合
      • 映射
      • C++实现
        • std::unordered_set
        • std::map
    • 小结
    • 242.有效的字母异位词
      • 思路
      • 复习
    • 349. 两个数组的交集
      • 使用数组实现哈希表的情况
      • 思路
      • 使用set实现哈希表的情况
    • 202. 快乐数
      • 思路
    • 1.两数之和
      • 思路
    • 总结

今天是哈希表专题的第一天

Q:什么时候要用到哈希法?

A当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

哈希表

哈希表 是一种通过哈希函数将键映射到表中位置的数据结构

哈希表的一些基本定义:

定义

  • 键是用来唯一标识哈希表中每个元素的部分。每个键在哈希表中必须是唯一的,即同一个哈希表中不能有两个相同的键。

作用

  • 定位:哈希表使用哈希函数将键转换为哈希值,然后用这个哈希值来决定元素存储的位置(桶/槽)。通过键可以高效地查找、插入或删除对应的元素。
  • 冲突解决:如果不同的键映射到同一个位置(即发生冲突),哈希表会使用冲突解决机制(如链表法或开放寻址法)来处理这些冲突。

例子

在一个学生成绩管理系统中,学生的学号可以作为键,用来唯一标识每个学生的成绩记录

定义

  • 值是与每个键关联的数据部分。每个键都对应一个值,值是存储在哈希表中的具体数据。

作用

  • 存储信息:值部分包含了与键相关的实际信息或数据。在哈希表中,通过键可以访问到对应的值。
  • 数据访问:当需要查询或操作数据时,通过键可以快速获取到相关的值。

例子

  • 在上述学生成绩管理系统中,学生的成绩可以作为值,存储在与学号关联的哈希表条目中。

实际上,数组就是一张哈希表:数组中的元素是键,它们被存放到数组的不同位置,在数组中可以通过下标直接访问数组中的元素,因此数组是一张哈希表

哈希表1

举个例子,如果想查询一个名字是否在这所学校里,如果使用枚举的话,时间复杂度是O(n);如果使用哈希表的话,只需要O(1)就能做到

如果使用哈希表存储和查找学生姓名,则在存储信息时把这所学校里学生的名字都存在哈希表里,在查询时通过索引直接就可以知道这位同学在不在这所学校里了

那么如何构建哈希表呢?这就涉及到了哈希函数,哈希函数将映射到哈希表中的某个位置

哈希函数

还是以“查询一个名字是否在这所学校里”为例,哈希函数将学生的姓名直接映射为哈希表上的索引。通过查询索引下标,我们能快速知道这位同学是否在这所学校里了

哈希函数的设计是哈希表的关键,在存储时,可能出现多个键对应同一个位置,这些键存储在哈希表的同一个位置处,这就是哈希冲突。如果哈希函数设计的不好,则会出现大量的哈希冲突

哈希函数如下图所示,hashCode使用特定的编码方式,把名字转化为数值,这样就把学生名字映射为哈希表上的索引数字了。由于哈希表的大小限制,为了保证映射出的索引数值都落在哈希表上,我们需要对hadhCode(name)取模,这保证了学生姓名一定可以映射到哈希表上

即使哈希函数计算的再均匀,也避免不了会有几位学生的名字同时映射到哈希表中同一个索引下标的位置。我们只能尽量寻找一个计算均匀的哈希函数,避免大量的哈希冲突

哈希表2

哈希冲突

下图展示的就是哈希冲突

哈希表3

如图,小李和小王都映射到了索引下标1的位置,这种现象就是哈希冲突

遇到哈希冲突有两种解决的思路:

  • 既然一个位置存不了多个键,那么就在这个位置后面做扩充。具体来说,哈希表的每个位置都指向一个链表的头节点,如果一个键对应到某个位置,则在该位置的链表末尾增加一个节点来存储这个键
  • 如果不想做扩展,那么我们就把键放到它对应位置附近的地方。具体来说,当发生冲突时,从冲突位置的下一个位置起,依次寻找空的散列地址,然后把这个键放到这个地址处

上面的两种思路对应哈希冲突的两种解决方案:拉链法 和 线性探测法

拉链法

思想:将所有哈希地址相同的记录存储在一个单链表中,在哈希表中存储的是所有子表的头指针

举例

哈希表4

小李和小王在索引1的位置处发生了冲突,发生冲突的元素都被存储在索引1的链表中,这样就可以通过索引查找到小李和小王了

注意:拉链法需要选择适当的哈希表大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间

线性探测法

思想:依靠哈希表中的空位来解决冲突。有多种探测空位的方法,这里介绍线性探测方法:当发生冲突时,从冲突位置的下一个位置起,依次寻找空的散列地址,然后把这个键放到这个地址处

为了能容纳所有的数据,一定要保证 哈希表大小 > 数据个数

举例

同样处理这个冲突,我们从索引1的下一个位置处起,寻找空的哈希位置。索引2的位置是空的,我们可以将小王存放到索引2的位置

哈希表5

常见的三种哈希结构

C++中是怎么使用哈希法解决问题呢?当使用哈希表时,我们一般会选择如下三种数据结构:

  • 数组
  • set(集合)
  • map(映射)

这三种结构的使用方式是依靠键(key)来访问值(value),所以使用这些数据结构来解决映射问题的方法叫作哈希法

集合

集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::set红黑树有序O(log n)O(log n)
std::multiset红黑树有序O(logn)O(logn)
std::unordered_set哈希表无序O(1)O(1)

红黑树是一种平衡二叉树,所以std::set和std::multiset的键值是有序的。但是键不可以修改,改动键的值会导致整棵树的错乱,所以只能删除和增加

当使用集合解决哈希问题时,优先使用undordered_set,它的查询和增删效率是最优的。如果集合是有序的,那么就用set。如果要求不仅有序还要有重复数据的话,那么就使用multiset

注意

  • **集合中的键值概念与其他数据结构(如映射或字典)中的有所不同。**集合中的每个元素都是一个唯一的“键”。在集合中,元素没有“值”这个概念,因为集合的主要目的是确保元素的唯一性和支持高效的集合操作(如插入、查找和删除),因此键即为值。集合只关心元素的存在性,不关心元素的附加数据或额外信息。

  • 虽然std::set和std::multiset 的底层实现基于红黑树而非哈希表,它们通过红黑树来索引和存储数据。不过给我们的使用方式,还是哈希法的使用方式,即依靠键(key)来访问值(value)。所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。std:map同理

映射

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可重复key不可修改O(logn)O(logn)
std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

同理,std::map和std::multimap的key值也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解——Carl)

注意:在map数据结构中,只对键有特定的要求和限制,而对值则没有限制:

  • 键是可比较的,以便能在红黑树中进行排序和查找操作,键必须能实现某种比较接口(例如在 C++ 中,键类型需要实现 < 运算符;在 Java 中,键类型需要实现 Comparable 接口)
  • 键是不可重复的(std::map、std::unordered_map)
  • 键是不可修改的,否则会扰乱红黑树的平衡结构(std::map、std::multimap)或者 会破坏哈希表的数据结构和性能(std::unordered_map)

值可以是任何数据类型,没有必须实现特定接口或运算符的要求。因为在map中,值只是与对应的键一起存储,不参与树结构的比较和排序操作

举例

#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> myMap;

    // 插入键值对
    myMap[1] = "one";
    myMap[2] = "two";
    myMap[3] = "three";

    // 打印 map 中的所有元素
    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

在这个例子中:

  • 键是整数类型,必须能够进行比较操作(红黑树需要对键进行排序和查找)
  • 值是字符串类型,可以是任意数据类型(没有特定要求)

C++实现

上面给出了C++标准库的集合和映射的实现方法。除此之外,还有hash_set hash_map,它们是由民间高手自发造的轮子(C++11标准之前造的)。实际上,hash_set hash_map与unordered_set,unordered_map的功能是一样的,但是unordered_set在C++11的时候被引入标准库了,而hash_set并没有,所以建议还是使用unordered_set比较好

哈希表6

std::unordered_set

特点

  • 元素无序
  • 插入、删除和查找操作的平均时间复杂度为 O(1)
  • 元素唯一
#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_set<int> mySet;

    // 插入元素
    mySet.insert(5);
    mySet.insert(3);
    mySet.insert(8);
    mySet.insert(1);

    // 打印集合中的元素
    for (const int& elem : mySet) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // 查找元素
    auto it = mySet.find(3);
    if (it != mySet.end()) {
        std::cout << "Element found: " << *it << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }

    return 0;
}
std::map

特点

  • 键自动排序
  • 插入、删除和查找操作的时间复杂度为 O(log⁡n)
  • 键唯一,值可重复
#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> myMap;

    // 插入键值对
    myMap[1] = "one";
    myMap[2] = "two";
    myMap[3] = "three";
    // pair函数构造键值对,存储到map容器中
    myMap.insert(std::pair<int, std::string>(4, "four"));

    // 打印键值对
    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    // 查找键
    // find函数返回一个迭代器,指向包含指定键的元素,返回类型是 std::map<Key, T>::iterator
    auto it = myMap.find(2);
    if (it != myMap.end()) {
        std::cout << "Found: " << it->first << " -> " << it->second << std::endl;
    } else {
        std::cout << "Not found" << std::endl;
    }

    return 0;
}

小结

直接贴上Carl的总结

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!

今天的四道题很好,覆盖了三种哈希结构:数组、集合、映射

242.有效的字母异位词

题目链接:242. 有效的字母异位词 - 力扣(LeetCode)

这道题使用数组作为哈希表,数组作为哈希表在遍历上很方便

思路

数组其实就是一个简单哈希表,既然题目中字符串只有小写字符,那么就定义一个大小为26的数组record,用来统计字符串s、t中各种字符出现的次数。哈希函数:hash(key) = key-'a'

首先使用record统计字符串s中的各个字符:遍历字符串s,根据哈希函数,令record[key-‘a’]++

然后再统计字符串t中的各个字符。可以使用一个新的数组来统计,也可以使用原数组,我们使用原数组:遍历字符串t,根据哈希函数,令record[key-‘a’]–

经过上述统计,如果字符串s和字符串t是异位词,那么record数组的所有元素都应该为0。record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false

242.有效的字母异位词

代码实现

class Solution {
public:
    bool isAnagram(string s, string t) {
        // 统计两个字符串中各个字符出现的次数,依次比较即可
        // 设计hash函数为key-'a',哈希表(数组)大小为0~25
        std::vector<int> record(26, 0);
        for(char c : s)
        {
            record[c-'a']++;
        }
        for(char c : t)
        {
            record[c-'a']--;
        }
        // 检查record中的所有元素
        for(int count : record)
        {
            if(count != 0)
            {
                return false;
            }
        }
        return true;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

这道题的思路很简单,主要复习一下字符串的遍历和数组的定义

复习

数组定义和操作

C++中,std::vector<int> 可以用来定义一个动态数组

#include<iostream>
#include<vector>
int main()
{
    // 1.数组的定义
    std::vector<int> array1;	// 定义一个空的vector
    std::vector<int> array2 = {10, 20, 30, 40, 50};	// 使用初始值列表初始化vector
    std::vector<int> array3(5, 0);	// 定义一个大小为5的vector,所有元素初始化为0
    std::vector<int> array4(array3.begin(), array3,end());	//	范围构造函数,用array3创建array4
    
    // 2.访问和修改元素
    std::vector<int> myVector = {1, 2, 3, 4, 5};
    // 访问元素
    std::cout << "Element at index 2: " << myVector[2] << std::endl;
    // 修改元素
    myVector[2] = 10;
    std::cout << "Element at index 2 after modification: " << myVector[2] << std::endl;
    
    // 3.增加和删除元素(都是在末尾增删)
    // 添加元素
    myVector.push_back(4);
    myVector.push_back(5);
	// 移除最后一个元素
    myVector.pop_back();
    
    // 4.删除所有等于val的元素
    // 使用 std::remove 移动所有等于 val 的元素到末尾,返回指向移除操作后容器的逻辑末尾(不含所有val元素的容器末尾)
    auto new_end = std::remove(vec.begin(), vec.end(), val);
    // 使用 vector::erase 移除这些元素
    vec.erase(new_end, vec.end());
    
    // 5.删除第index位的元素
    if (index < vec.size()) {
        // 使用 vector::erase 删除第 index 位的元素
        vec.erase(vec.begin() + index);
    } else {
        std::cout << "Index out of bounds." << std::endl;
    }
    
    // 6.使用迭代器遍历 vector
    for (std::vector<int>::iterator it = myVector.begin(); it != myVector.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

范围for循环

C++11引入了范围for循环,用于遍历容器,基本语法:

for (declaration : expression) {
    // loop body
}
  • declaration:声明一个变量,这个变量在每次迭代中都会被赋值为当前元素。

  • expression:一个表达式,返回一个可迭代的范围,例如数组、容器(如 std::vector)、初始化列表等。

for(int count : array)
{
    // loop body
    	 ···
}

相当于

for(int i=0; i<arrat.size(); ++i)
{
    count = array[i];
    // loop body
         ···
}

349. 两个数组的交集

Carl建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set

题目链接:349. 两个数组的交集 - 力扣(LeetCode)

这道题目用集合作为哈希表,集合能对元素做去重,而元素是无序的

使用数组实现哈希表的情况

这道题可以使用数组吗?不可以,使用数组来做哈希的题目,是因为题目都限制了数值的大小,比如上一道题限制字符串中都是小写字母,key只有26种,而本题没有限制数值的大小,就无法使用数组做哈希表了。而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费

思路

题目说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序

如果使用集合,C++提供了三种可用的数据结构:

  • std::set
  • std::multiset
  • std::unordered_set

我们该选择哪一个?

std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set

set哈希法

代码实现

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        std::unordered_set<int> result_set; // 存放结果,定义为set是为了去重
        for(int num : nums2)
        {
            // 使用std::find函数在nums1中查找num
            if(find(num1.begin(), nums1.end(), num) != nums1.end())
            {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};

std::find是C++标准库中的一个通用查找算法,用于在给定范围内查找指定元素。它接受两个迭代器作为参数,分别表示搜索范围的起始和结束位置。如果找到指定元素,则返回指向该元素的迭代器;否则,返回指向搜索范围末尾的迭代器。可以用于查找数组的元素 或 链表的节点

我们也可以先对其中一个数组进行去重,然后再求交集

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        std::unordered_set<int> result_set;	// 存放结果,定义为set是为了去重
        std::unordered_set<int> num_set(nums1.begin(), nums1.end());	// 先对nums1做去重
        for(int num : nums2)
        {
            if(num_set.find(num) != num_set.end())
            {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};
  • 时间复杂度: O(n + m) m 是最后要把 set转成vector
  • 空间复杂度: O(n)

使用set实现哈希表的情况

那有同学可能问了,遇到哈希问题我直接都用set不就得了,用什么数组啊。

直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。

不要小瞧 这个耗时,在数据量大的情况,差距是很明显的

202. 快乐数

建议:这道题目也是set的应用,其实和上一题差不多,就是 套在快乐数一个壳子

题目链接:202. 快乐数 - 力扣(LeetCode)

本题使用集合作为哈希表

思路

这道题的难点在如何判断是否进入了无限循环,出现无限循环一定是因为sum重复出现了。我们可以通过判断sum是否重复,进而判断是否进入了无限循环

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了

所以这道题目使用哈希法,来判断sum是否重复出现

除此之外,本题还有一个难点:需要对数值各位做取数操作

代码实现

class Solution {
public:
    int getSum(int n)
    {
        int sum = 0;
        while(n != 0)
        {
            sum += (n % 10) * (n % 10);
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> set;
        while(1)
        {
            int sum = getSum(n);    // 各位求和
            if(sum == 1)
            {
                return true;
            }
            // 检查sum是否曾经出现过,如果出现过,则陷入了死循环
            if(set.find(sum) != set.end())
            {
                return false;
            }else
            {
                set.insert(sum);
            }
            n = sum;    // 进行下一轮循环
        }
    }
};

1.两数之和

建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。

题目链接:1. 两数之和 - 力扣(LeetCode)

本题使用map作为哈希表

思路

  • 为什么会想到用哈希法?

    当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

    这道题只需要遍历一趟数组,需要用一个集合记录我们遍历过的元素。定义:若元素1+元素2=target,则称元素1与元素2相匹配。当我们遍历到一个元素a时,我们查询集合中是否有与该元素a相匹配的元素b。这符合哈希法的使用原则:需要查询一个元素是否出现过,或者一个元素是否在集合里

  • 哈希表为什么用map

    • 数组作为哈希表的局限:数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。

    • set集合作为哈希表的局限:set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用

    • 使用map作为哈希表的原因:本题不仅需要知道元素是否遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适

    那么我们该选择哪种类型的map?

    映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
    std::map红黑树key有序key不可重复key不可修改O(log n)O(log n)
    std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
    std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

    **本题不需要key有序,选择std::unordered_map效率更高!**因此选择std::unordered_map实现map

  • map用来做什么

    在遍历数组的过程中,map需要记录我们访问过的元素的值和对应的下标,这样才能找到与当前元素a相匹配的元素b,并获得元素b的下标

  • map中key和value分别表示什么

    map使用key寻找value。在数组的遍历过程中,我们需要判断 与当前元素a相匹配的 元素b是否出现过,即b=taregt-a是否在集合中。若元素b出现过,则返回元素b的下标。我们使用元素b的值寻找元素b的下标,因此map的存储结构为:

    • key:数组元素值
    • value:数组元素对应的下标
  • 整体思路

    遍历数组时,只需要在map中查询是否有和当前遍历到的元素a相匹配的元素b,具体来说,为auto it = map.find(target-a)

    • 如果元素b在map中,即it != map.end(),则找到了对应的匹配对,返回元素a、b的下标{i, it.second}
    • 如果没有找到元素b,则需要把当前遍历的元素a存放到map中,即map.insert(pair<int, int>(a, i)),这样map存放的就是我们访问过的元素,然后继续遍历数组

    过程如下:

    过程一

    过程二

代码实现

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 返回匹配上的两个元素的下标
        // 定义一个map,用来存放在数组遍历过程中,见过的所有元素
        // 然后每次遍历到一个新的元素时,都查询traget-该元素 是否在map中
        // 如果在map中,则返回;否则,将该元素直接加入到map中
        std::unordered_map<int, int> map;
        for(int i=0; i<nums.size(); ++i)
        {
            auto it = map.find(target-nums[i]);
            if(it != map.end())
            {
                return {it->second, i};
            }else
            {
                map.insert(pair<int, int>(nums[i], i));
            }
        }
        return {};
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

总结

今天是哈希表专题的第一天,复习了哈希表的基本知识,学习了哈希法的思想:当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。学习了 数组、集合、映射实现哈希表的方法和基本操作,以及C++中如何实现这些数据结构。今天的四道题覆盖了这三种哈希结构,可以总结一下三种结构的优缺点:

  • 数组:

    • 优点:数组作为哈希表在遍历上很方便
    • 缺点:数组的大小是受限制的,所以要处理的数据是有大小限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • 集合:

    • 优点:集合能对元素做去重,当需要对数据进行去重处理时,可以考虑使用集合。集合对处理的数据没有大小限制

    • 缺点:set是一个集合,里面放的元素只能是一个key。实际上,集合没有“值”的概念,或者说 键就是值。因此想要存放一些与键相关的信息,就不能使用集合。另外,直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。

      不要小瞧 这个耗时,在数据量大的情况,差距是很明显的

  • 映射:

    • 优点:映射对数据大小没有限制,如果想要存放与键相关的信息,就需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适
    • 缺点:内存开销大。由于维护树结构或哈希表的开销,映射在某些操作上(如遍历、批量插入)比数组和集合慢

除此之外,还复习了迭代器、范围for循环、vector容器的操作,std::find函数 和 std::pair函数

第三、四道题一开始看不出要使用哈希法,我们将问题分析后转化,发现需要查找元素是否在集合中,适合哈希法的使用情况,因此使用哈希法,然后进一步分析使用哪种结构(数组、集合、映射)实现哈希表。这种分析问题,转化问题的能力很重要

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

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

相关文章

VINS-Fusion 回环检测pose_graph_node

VINS-Fusion回环检测,在节点pose_graph_node中启动。 pose_graph_node总体流程如下: 重点看process线程。 process线程中,将订阅的图像、点云、位姿时间戳对齐,对齐后分别存入image_msg、point_msg、pose_msg。pose_msg为VIO后端优化发布的位姿。 一、创建关键帧keyFram…

opencascade AIS_ManipulatorOwner AIS_MediaPlayer源码学习

前言 AIS_ManipulatorOwner是OpenCascade中的一个类&#xff0c;主要用于操纵对象的交互控制。AIS_ManipulatorOwner结合AIS_Manipulator类&#xff0c;允许用户通过可视化工具&#xff08;如旋转、平移、缩放等&#xff09;来操纵几何对象。 以下是AIS_ManipulatorOwner的基…

【Drone】drone编译web端 防墙策略 | 如何在被墙的状态drone顺利编译npm

一、drone编译防墙版本 1、web端drone kind: pipeline type: docker name: ui steps:- name: build_projectimage: node:20-slim depends_on: [clone]volumes:- name: node_modulespath: /drone/src/node_modulescommands:- pwd- du -sh *- npm config set registry https://…

免费【2024】springboot 毕业生学历证明系统

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

SQL labs-SQL注入(二)

环境搭建参考 SQL注入&#xff08;一&#xff09; 一&#xff0c;SQL labs-less2。 http://192.168.61.206:8001/Less-2/?id-1 union select 1,2,group_concat(username , password) from users-- 与第一关没什么太大的不同&#xff0c;唯一区别就是闭合方式为数字型。 二…

超火爆AI工具——Vozo:一键重写视频脚本、重新配音!

最近有一款短视频工具——Vozo AI非常火热&#xff0c;上线即登Product Hunt榜首&#xff0c;且已蝉联3天。 它的全名是Vozo Rewrite & Redub&#xff0c;Rewrite意味着重新编写&#xff0c;Redub代表重新配音&#xff0c;它能够根据提示词&#xff0c;重新生成视频脚本并能…

谷粒商城实战笔记-65-商品服务-API-品牌管理-表单校验自定义校验器

文章目录 1&#xff0c;el-form品牌logo图片自定义显示2&#xff0c;重新导入和注册element-ui组件3&#xff0c;修改brand-add-or-update.vue控件的表单校验规则firstLetter 校验规则sort 校验规则 1&#xff0c;el-form品牌logo图片自定义显示 为了在品牌列表中自定义显示品…

MySql 全文索引

MySql 全文索引 1.MySql 全文索引介绍2.ngram 简介3.数据库配置4.创建全文索引5.使用全文索引布尔模式校验 ngram 自然语言模式拓展查询 6.相关性排序7.注意事项 1.MySql 全文索引介绍 Mysql 的全文索引主要用于全文字段的检索场景&#xff0c;支持 char、varchar、text 几个字…

博客建站4 - ssh远程连接服务器

1. 什么是SSH?2. 下载shh客户端3. 配置ssh密钥4. 连接服务器5. 常见问题 5.1. IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! 1. 什么是SSH? SSH&#xff08;Secure Shell&#xff09;是一种加密的网络协议&#xff0c;用于在不安全的网络中安全地远程登录到其他…

浪潮自研交换机系列常见问题处理

CN61108PC-V-H 不能PING通任何地址&#xff0c;也不能被PING 输入ip traceroute enable既可。注意视图 交换机通过console口远程登录至其他交换机&#xff0c;掉线后console口无法使用 例如有2台交换机A和B&#xff0c;在A交换机上插上console线登录后&#xff0c;在A通过SSH…

linux、windows、macos,命令终端清屏

文章目录 LinuxWindowsmacOS 在Linux、Windows和macOS的命令终端中&#xff0c;清屏的命令或方法各不相同。以下是针对这三种系统的清屏方法&#xff1a; Linux clear命令&#xff1a;这是最常用的清空终端屏幕的命令之一。在终端中输入clear命令后&#xff0c;屏幕上的所有内容…

H5+CSS+JS工作性价比计算器

工作性价比&#xff1d;平均日新x综合环境系数/35 x(工作时长&#xff0b;通勤时长—0.5 x摸鱼时长) x学历系数 如果代码中的公式不对&#xff0c;请指正 效果图 源代码 <!DOCTYPE html> <html> <head> <style> .calculator { width: 300px; padd…

前端JS特效第56集:基于canvas的粒子文字动画特效

基于canvas的粒子文字动画特效&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下(全部代码在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compat…

【C语言】 约瑟夫环,循环链表实现

更新一下&#xff0c;昨天的代码有点问题&#xff0c;没有考虑到头结点的影响&#xff0c;我的方法是&#xff1a; 在进行步数位移的时候判断标记点&#xff0c;如果走到了头结点&#xff0c;就在循环里面立即往后再位移一次&#xff0c;把头结点跳过&#xff1b;同时在后面删除…

20分钟上手新版Skywalking 9.x APM监控系统

Skywalking https://skywalking.apache.org/ Skywalking是专为微服务、云原生和基于容器的&#xff08;Kubernetes&#xff09;架构设计的分布式系统性能监控工具。 Skywalking关键特性 ● 分布式跟踪 ○ 端到端分布式跟踪。服务拓扑分析、以服务为中心的可观察性和API仪表板。…

2024国际燃气轮机运维周线上分享第一期开启!共探燃机新生态

为促进国内重型燃气轮机运维技术发展&#xff0c;加快建立独立自主的燃气轮机运维技术体系&#xff0c;2024国际燃气轮机运维大会将于2024年10月17-18日在中国广州盛大召开&#xff01; 2024国际燃气轮机运维大会将通过线上直播会议、线下技术分享及颁奖典礼等形式展开&#xf…

spine to unity-2.利用边缘框实现实时碰撞检测

主要讲spine的边缘框&#xff0c;在unity中&#xff0c;实现实时碰撞检测。其中使用的素材&#xff0c;是我为独立游戏ink制作的动画。独立游戏ink的开发日志&#xff0c;在小红薯持续更新中。spine工具包的安装&#xff0c;下载请参考spine to unity-1spine BoundingBoxFollow…

Vue 实现电子签名并生成签名图片

目录 前言项目结构代码实现 安装依赖创建签名画布组件生成签名图片 总结相关阅读 1. 前言 电子签名在现代Web应用中越来越普遍&#xff0c;例如合同签署、确认表单等。本文将介绍如何使用Vue.js实现一个简单的电子签名功能&#xff0c;并将签名生成图片。 2. 项目结构 项…

科研绘图系列:R语言组合堆积图(stacked barplot with multiple groups)

介绍 通常堆积图的X轴表示样本,样本可能会存在较多的分组信息,通过组合堆积图和样本标签分组信息,我们可以得到一张能展示更多信息的可发表图形。 加载R包 knitr::opts_chunk$set(warning = F, message = F) library(tidyverse) library(cowplot) library(patchwork)导入…

hadoop完全分布模式搭建

本次搭建是基于伪分布式进行的&#xff0c;所以配置之前需要搭建好伪分布式 我使用的ubuntu版本见下 虚拟机之前安装过在此不在记录 伪分布式的搭建过程在之前的第一次实验报告上有详细的记录 修改主机名 设置 hosts 文件 ssh 无密码登录 过程不再演示 免密登录成功图 …