第三课 哈希表、集合、映射

文章目录

  • 第三课 哈希表、集合、映射
    • lc1.两数之和--简单
      • 题目描述
      • 代码展示
    • lc30.串联所有单词的子串--困难
      • 题目描述
      • 代码展示
    • lc49.字母异位分组--中等
      • 题目描述
      • 代码展示
    • lc874.模拟行走机器人--中等
      • 题目描述
      • 代码展示
    • lc146.LRU缓存--中等
      • 题目描述
      • 相关补充
      • 思路讲解
      • 代码展示
      • 图示理解

第三课 哈希表、集合、映射

lc1.两数之和–简单

题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

代码展示

class Solution {
public:      //HaspMap实现vector<int> twoSum(vector<int>& numbers, int target) {// j < i// for i = 0 ~ n - 1://      search if (target - numbers[i]) exists in numbers[0..i-1]unordered_map<int, int> value_to_index; // 值到下标的映射for (int i = 0; i < numbers.size(); i++) {// 不等于尾部,就是找到了,存在// Java: value_to_index.containsKey(target-numbers[i])// Pythong: target-numbers[i] in value_to_indexif (value_to_index.find(target - numbers[i]) != value_to_index.end()) {return {value_to_index[target - numbers[i]], i};}// 边循环i,边插入,维护的是对于numbers[0..i-1]的映射// 本质上是在i之前查找,防止查找i本身value_to_index[numbers[i]] = i;}return {};}
};

lc30.串联所有单词的子串–困难

题目描述

给定一个字符串 s 和一个字符串数组 words words 中所有字符串 长度相同

s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。

  • 例如,如果 words = ["ab","cd","ef"], 那么 "abcdef""abefcd""cdabef""cdefab""efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。

返回所有串联子串在 s 中的开始索引。你可以以 任意顺序 返回答案。

示例 1:

输入:s = "barfoothefoobarman", words = ["foo","bar"]
输出:[0,9]
解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。
子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。
输出顺序无关紧要。返回 [9,0] 也是可以的。

示例 2:

输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出:[]
解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。
s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。
所以我们返回一个空数组。

示例 3:

输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出:[6,9,12]
解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。
子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。
子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。

提示:

  • 1 <= s.length <= 104
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 30
  • words[i]s 由小写英文字母组成

代码展示

class Solution {
public:      //测试用例通过了,但耗时太长。vector<int> findSubstring(string s, vector<string>& words) {wordsMap = countWords(words);int tot = words.size() * words[0].size();vector<int> ans;// 枚举开始位置for (int start = 0; start + tot <= s.length(); start++) {if (isSame(s.substr(start, tot), words)) {ans.push_back(start);}}return ans;}private:unordered_map<string, int> wordsMap;// 想判断一个字符串t,是否由words拼成// 把t分解成若干个单词,然后看跟words数组是否相同(顺序无关)bool isSame(string t, vector<string>& words) {// cout << "isSame: " << t << " and words" << endl;int m = words[0].length(); // 每个单词的长度unordered_map<string, int> tMap; // 单词出现次数// 把t,每m个字符分解成一个单词// foothe 分解为 foo, thefor (int i = 0; i < t.length(); i += m) {// i开始的m个字符,组成一个单词tMap[t.substr(i, m)]++;}return equals(tMap, wordsMap);}// 判断两个map是否一样的方法// a.size() == b.size()// size: key的个数// a里面有的b里全有,且值一样bool equals(unordered_map<string, int>& a, unordered_map<string, int>& b) {if (a.size() != b.size()) return false;for (auto& key_value_pair : a) {auto& key = key_value_pair.first;auto& value = key_value_pair.second;// 如果b里面没有,或者value不相等(次数不一样)if (b.find(key) == b.end() || value != b[key]) return false;}return true;}unordered_map<string, int> countWords(vector<string>& words) {unordered_map<string, int> ans;for (string& word : words) {ans[word]++;}return ans;}
};//bar foo
//arf oot
//rfo oth
//...

优化方法:image-20231006134744326

class Solution {
public:      //优化解法vector<int> findSubstring(string s, vector<string>& words) {vector<int> ans;words_map = getMap(words);int n = s.size();int m = words[0].size();int tot = m * words.size();for (int first = 0; first < m; first++) {if (first + tot > n) break;unordered_map<string, int> s_map;int curr = first;for (int i = 0; i < words.size(); i++) {s_map[s.substr(curr, m)]++;curr += m;}for (int start = first, end = curr; start + tot <= n; start += m, end += m) {if (isSame(s_map, words_map)) ans.push_back(start);s_map[s.substr(end, m)]++;s_map[s.substr(start, m)]--;}}return ans;}private:unordered_map<string, int> getMap(vector<string>& words) {unordered_map<string, int> res;for (string& word : words) {res[word]++;}return res;}bool isSame(unordered_map<string, int>& a, unordered_map<string, int>& b) {for (auto& pr : a) {if (b[pr.first] != pr.second) return false;}for (auto& pr : b) {if (a[pr.first] != pr.second) return false;}return true;}unordered_map<string, int> words_map;
};

lc49.字母异位分组–中等

题目描述

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

示例 2:

输入: strs = [""]
输出: [[""]]

示例 3:

输入: strs = ["a"]
输出: [["a"]]

提示:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

代码展示

class Solution {
public:vector<vector<string>> groupAnagrams(vector<string>& strs) {// HashMap可用于分组// 从排序以后的字符串(aet)到一个数组(["ate","eat","tea"])的mapunordered_map<string, vector<string>> group;for (string& str : strs) {string copy = str;// 字符串里面的字符排序// Java: toCharArray()sort(copy.begin(), copy.end());// 分组group[copy].push_back(str);// cout << "Added " << str << " into group " << copy << endl;}vector<vector<string>> ans;// Java .keySet()// Python for .. in ...for (auto pr : group) {// pr.first == key// pr.second == valueans.push_back(pr.second);}return ans;}// 字符串长度分别是n1, n2, n3,....,总和是n// n1 log n1 + n2 log n2 + ....// <= n1 log n + n2 log n + ....// = (n1 + n2 + ...) log n// = n log n
};/*
["eat", "tea", "tan", "ate", "nat", "bat"]
["aet", "aet", "ant", "aet", "ant", "abt"]
*/

lc874.模拟行走机器人–中等

题目描述

机器人在一个无限大小的 XY 网格平面上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令 commands

  • -2 :向左转 90
  • -1 :向右转 90
  • 1 <= x <= 9 :向前移动 x 个单位长度

在网格上有一些格子被视为障碍物 obstacles 。第 i 个障碍物位于网格点 obstacles[i] = (xi, yi)

机器人无法走到障碍物上,它将会停留在障碍物的前一个网格方块上,并继续执行下一个命令。

返回机器人距离原点的 最大欧式距离平方 。(即,如果距离为 5 ,则返回 25

注意:

  • 北方表示 +Y 方向。
  • 东方表示 +X 方向。
  • 南方表示 -Y 方向。
  • 西方表示 -X 方向。
  • 原点 [0,0] 可能会有障碍物。

示例 1:

输入:commands = [4,-1,3], obstacles = []
输出:25
解释:
机器人开始位于 (0, 0):
1. 向北移动 4 个单位,到达 (0, 4)
2. 右转
3. 向东移动 3 个单位,到达 (3, 4)
距离原点最远的是 (3, 4) ,距离为 32 + 42 = 25

示例 2:

输入:commands = [4,-1,4,-2,4], obstacles = [[2,4]]
输出:65
解释:机器人开始位于 (0, 0):
1. 向北移动 4 个单位,到达 (0, 4)
2. 右转
3. 向东移动 1 个单位,然后被位于 (2, 4) 的障碍物阻挡,机器人停在 (1, 4)
4. 左转
5. 向北走 4 个单位,到达 (1, 8)
距离原点最远的是 (1, 8) ,距离为 12 + 82 = 65

示例 3:

输入:commands = [6,-1,-1,6], obstacles = []
输出:36
解释:机器人开始位于 (0, 0):
1. 向北移动 6 个单位,到达 (0, 6).
2. 右转
3. 右转
4. 向南移动 6 个单位,到达 (0, 0).
机器人距离原点最远的点是 (0, 6),其距离的平方是 62 = 36 个单位。

提示:

  • 1 <= commands.length <= 104
  • commands[i] 的值可以取 -2-1 或者是范围 [1, 9] 内的一个整数。
  • 0 <= obstacles.length <= 104
  • -3 * 104 <= xi, yi <= 3 * 104
  • 答案保证小于 231

代码展示

class Solution {
public:int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {// {(x1,y1), (x2,y2), ...}// (-200, 30000)// string: "-200,30000"// long long: (-200, 300) -->  (-200+30000, 300+30000) --> (-200+30000)*60000 + 300 + 30000unordered_set<long long> blockers;for (auto& obstacle : obstacles) {blockers.insert(calcHash(obstacle[0], obstacle[1]));}// 方向数组技巧//           N, E, S,  Wint dx[4] = {0, 1, 0, -1}; // 偏移量(单位向量)int dy[4] = {1, 0, -1, 0};int x = 0, y = 0;int dir = 0; // Nint ans = 0;for (int cmd : commands) {if (cmd > 0) {for (int i = 0; i < cmd; i++) {// 尝试走到nextx, nexty// 想向dir走一步,就加dir方向的偏移量int nextx = x + dx[dir];int nexty = y + dy[dir];// 有障碍物// calcHash(nextx, nexty) in blockersif (blockers.find(calcHash(nextx, nexty)) != blockers.end()) {break;}// 走一步x = nextx;y = nexty;ans = max(ans, x * x + y * y);}} else if (cmd == -1) {// 0->1->2->3->0 // N->E->S->W->N// 右转(顺时针)dir = (dir + 1) % 4;} else {// 左转,避免负数,加一个mod数dir = (dir - 1 + 4) % 4;}}return ans;}private:/*string calcHash(int x, int y) {return to_string(x) + "," + to_string(y);}*/long long calcHash(int x, int y) {return (x + 30000) * 60000ll + y + 30000; }
};

lc146.LRU缓存–中等

题目描述

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 getput 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 * 105getput

相关补充

image-20231006135422553

image-20231006135431503

image-20231006135443864

思路讲解

image-20231006135851757

代码展示

public class LRUCache {class DLinkedNode {int key;int value;DLinkedNode prev;DLinkedNode next;public DLinkedNode() {}public DLinkedNode(int _key, int _value) {key = _key; value = _value;}}private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();private int size;private int capacity;private DLinkedNode head, tail;public LRUCache(int capacity) {this.size = 0;this.capacity = capacity;// 使用伪头部和伪尾部节点head = new DLinkedNode();tail = new DLinkedNode();head.next = tail;tail.prev = head;}public int get(int key) {DLinkedNode node = cache.get(key);if (node == null) {return -1;}// 如果 key 存在,先通过哈希表定位,再移到头部moveToHead(node);return node.value;}public void put(int key, int value) {DLinkedNode node = cache.get(key);if (node == null) {// 如果 key 不存在,创建一个新的节点DLinkedNode newNode = new DLinkedNode(key, value);// 添加进哈希表cache.put(key, newNode);// 添加至双向链表的头部addToHead(newNode);++size;if (size > capacity) {// 如果超出容量,删除双向链表的尾部节点DLinkedNode tail = removeTail();// 删除哈希表中对应的项cache.remove(tail.key);--size;}}else {// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部node.value = value;moveToHead(node);}}private void addToHead(DLinkedNode node) {node.prev = head;node.next = head.next;head.next.prev = node;head.next = node;}private void removeNode(DLinkedNode node) {node.prev.next = node.next;node.next.prev = node.prev;}private void moveToHead(DLinkedNode node) {removeNode(node);addToHead(node);}private DLinkedNode removeTail() {DLinkedNode res = tail.prev;removeNode(res);return res;}
}/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/

图示理解

img

img

img

img

img

img

img

img

img

img

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

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

相关文章

正点原子嵌入式linux驱动开发——U-boot启动流程详解

在上一篇笔记中详细分析了uboot的顶层Makefile&#xff0c;理清了uboot的编译流程。本章来详细的分析一下uboot的启动流程&#xff0c;理清uboot是如何启动的。通过对uboot启动流程的梳理&#xff0c;可以掌握一些外设是在哪里被初始化的&#xff0c;这样当需要修改这些外设驱动…

java的内存模型(概念)

在java中&#xff0c;设计之初就有了&#xff1a;主内存、线程工作内存&#xff0c;所以其实每一个线程执行时&#xff0c;都是将主线程copy一份到工作线程&#xff0c;执行修改后&#xff0c;再同步回去。 所以&#xff0c;就有四组内存操作方式&#xff1a; 1、读主内存&…

postgresql-物化视图

postgresql-物化视图 物化视图创建物化视图刷新物化视图修改物化视图删除物化视图 物化视图 创建物化视图 postgresql使用create materialized view 语句创建视图 create materialized view if not exists name as query [with [NO] data];-- 创建一个包含员工统计信息的物化…

自学SLAM(2)---保姆教程教你如何使用自己的视频运行ORB-SLAM2

前言 如果你是新手入门&#xff0c;仅仅只会Linux的基本操作&#xff0c;并看了高翔老师视觉SLAM视屏的第一讲&#xff0c;那么你需要准备一整天的时间&#xff0c;可能还不一定能运行出来&#xff01;运行ORB-SLAM2将会安装很多很多东西。那么&#xff0c;我们准备开始&#x…

CRMEB商城源码开源标准版v5.2.0+后端+前端uni-app开源包安装教程

CRMEB打通版是一款全开源支持商用的PHP多语言商城系统,历经年时间匠心之作&#xff01;系统采用前后端分离技术&#xff0c;基于TP6Uui-app框架开发&#xff1b;客户移动端采用uni-app开发&#xff0c;管理后台前端使用iviewUI开发。系统支持微信公众号端、微信小程序端、H5端、…

C语言之自定义类型_结构体篇(1)

目录 什么是结构&#xff1f; 结构体类型的声明 常规声明 特殊声明-匿名结构体 结构体变量的定义和初始化和访问 定义 初始化 访问 嵌套结构体 结构体的自引用 什么是结构体的自引用 NO1. NO2. 热门考点&#xff1a;结构体内存对齐 产生内存对齐 NO1 NO2 …

二十九、高级IO与多路转接之epollreactor(收官!)

文章目录 一、Poll&#xff08;一&#xff09;定义&#xff08;二&#xff09;实现原理&#xff08;三&#xff09;优点&#xff08;四&#xff09;缺点 二、I/O多路转接之epoll&#xff08;一&#xff09;从网卡接收数据说起&#xff08;二&#xff09;如何知道接收了数据&…

蓝桥杯每日一题2023.9.28

AcWing 4409. 砍竹子 - AcWing 题目描述 题目分析 注&#xff1a;sqrtl的范围为long double&#xff0c;比sqrt更加精确 使用优先队列维护一段区间&#xff0c;如果连续一段相同就合并为一个区间&#xff0c;从大到小去枚举&#xff0c;每次先取出最大的一段&#xff0c;双…

专业综合课程设计 - 优阅书城项目(第一版)

此项目是《专业综合课程设计》带练项目 实现的功能有&#xff1a; 登录、注销、添加图书、删除图书、编辑图书 包含资源&#xff1a; 优阅书城&#xff08;bookstore&#xff09;源码 数据库数据 课程笔记 下载链接&#xff1a;https://wwpv.lanzoue.com/i79nx1av4doj 登录功…

windows系统服务管理命令sc

sc可以用于管理系统服务、计划任务、系统日志等方面&#xff0c;是不可或缺的神器。 基本用法 在命令提示符下输入sc命令&#xff0c;然后按回车键。 上图展示的是sc命令的使用方法&#xff0c;支持哪些参数实现哪些功能 要查看系统所有服务列表&#xff0c;包括它们是否正在…

逻辑回归评分卡

文章目录 一、基础知识点(1)逻辑回归表达式(2)sigmoid函数的导数损失函数(Cross-entropy, 交叉熵损失函数)交叉熵求导准确率计算评估指标 二、导入库和数据集导入库读取数据 三、分析与训练四、模型评价ROC曲线KS值再做特征筛选生成报告 五、行为评分卡模型表现总结 一、基础知…

Go-Python-Java-C-LeetCode高分解法-第八周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 我搜集到了50道精选题&#xff0c;适合速成概览大部分常用算法 突…

2023年-华为机试题库B卷(Python)【满分】

1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ &#x1f51f; 华为机试题库B卷 已于5月10号 更新为2023 B卷 &#xff08;2023-10-04 更新本文&#xff09; 华为机试有三道题目&#xff0c;前两道属于简单或中等题&#xff0c;分值为100分&#xff0c;第三道为中等或…

互动营销类游戏开发小程序游戏开发

互动营销类游戏开发是一种创意和有趣的方式&#xff0c;可以用于推广产品、品牌或服务。这些游戏旨在吸引玩家并与他们互动&#xff0c;以促使他们与您的品牌建立更紧密的联系。 当今数字时代的市场竞争激烈&#xff0c;品牌和企业需要采用创新的方法来吸引并保持用户的兴趣。…

MySQL基础-事务

目录 1.事务简介 2.事务的操作 2.1 实验需要用到的数据 2.2 完成转账操作 修改事务执行方式 手动开启事务的方式 3.事务的四大特性 4.并发事务问题 5.事务隔离级别 5.1 事务隔离级别分类 5.2 查看事务隔离级别 5.3 设置事务隔离级别 1.事务简介 事务是一组操作的集合…

实时人脸五观检测:基于libfacedetection(CNN模型)

一、前言 随着人工智能技术的不断发展,人脸检测已成为计算机视觉领域的重要应用之一。人脸检测是一种将输入图像中的人脸位置和轮廓提取出来的技术,广泛应用于人脸识别、智能监控、人机交互等领域。利用libfacedetection开源的人脸检测库,实现人脸检测。 libfacedetection…

第一课数组、链表、栈、队列

第一课数组、链表、栈、队列 acwing136 邻值查找---中等题目描述代码展示 lc20.有效的括号--简单题目描述代码展示 lc25.K 个一组翻转链表--困难题目描述代码展示 lc26.删除有序数组中的重复项--简单题目描述代码展示 lc88.合并两个有序数组--简单题目描述代码展示 lc141.环形链…

mysql-binlog

1. 常用的binlog日志操作命令 1. 查看bin-log是否开启 show variables like log_%;2. 查看所有binlog日志列表 show master logs;3.查看master状态 show master status;4. 重置&#xff08;清空&#xff09;所有binlog日志 reset master;2. 查看binlog日志内容 1、使用mysqlb…

目前制造企业生产计划现状是什么?有没有自动化排产系统?

大家都知道&#xff0c;人的指挥中心是大脑&#xff0c;大脑对我们的发出各种各样的指令&#xff0c;告诉我们&#xff1a;“手”做什么事情&#xff0c;“眼睛”看什么地方&#xff0c;“耳朵”听什么声音&#xff0c;然后再将摸到的、看到的、听到的信息传递给大脑&#xff0…

《视觉 SLAM 十四讲》V2 第 4 讲 李群与李代数 【什么样的相机位姿 最符合 当前观测数据】

P71 文章目录 4.1 李群与李代数基础4.1.3 李代数的定义4.1.4 李代数 so(3)4.1.5 李代数 se(3) 4.2 指数与对数映射4.2.1 SO(3)上的指数映射罗德里格斯公式推导 4.2.2 SE(3) 上的指数映射SO(3),SE(3),so(3),se(3)的对应关系 4.3 李代数求导与扰动模型4.3.2 SO(3)上的李代数求导…