diff --git a/.gitignore b/.gitignore index e615a4d..e55653b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -**.local.** \ No newline at end of file +**.local.** +.vscode \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/README.md b/README.md index 6a6598e..0e42ff3 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,29 @@ -# LeetCode 题解 - -- [LeetCode 题解](#leetcode-题解) - - [基础篇](#基础篇) - - [数组,栈,队列](#数组栈队列) - - [每日一题](#每日一题) - - [数组拓展题目](#数组拓展题目) - - [栈拓展题目](#栈拓展题目) - - [队列拓展题目](#队列拓展题目) - - [相关专题](#相关专题) - - [链表](#链表) - - [每日一题](#每日一题-1) - - [链表拓展题目](#链表拓展题目) - - [树](#树) - - [每日一题](#每日一题-2) - - [树拓展题目](#树拓展题目) - - [哈希表](#哈希表) - - [每日一题](#每日一题-3) - - [哈希表拓展题目](#哈希表拓展题目) - - [双指针](#双指针) - - [每日一题](#每日一题-4) - - [双指针拓展题目](#双指针拓展题目) - - [进阶篇](#进阶篇) - - [高频面试题](#高频面试题) - - [前缀树](#前缀树) - - [并查集](#并查集) - - [跳表](#跳表) - - [剪枝](#剪枝) - - [专题篇](#专题篇) - - [二分法](#二分法) - - [滑动窗口](#滑动窗口) - - [每日一题](#每日一题-5) - - [拓展题目](#拓展题目) - - [位运算](#位运算) - - [搜索(BFS, DFS, 回溯)](#搜索bfs-dfs-回溯) - - [背包问题](#背包问题) - - [动态规划](#动态规划) - - [分治](#分治) - - [贪心](#贪心) - - [每日一题](#每日一题-6) - - [贪心拓展题目](#贪心拓展题目) - - [其他](#其他) +# Leetcode 题解 -> [在线电子书](https://app.gitbook.com/@suki/s/91-days-algorithm/) -> -> [DSA 讲义 - private repo](https://github.com/leetcode-pp/91alg-2#%E8%AE%B2%E4%B9%89) -> -> [参考题解 - private repo](https://github.com/leetcode-pp/91alg-2#%E9%A2%98%E8%A7%A3) -> -> [笔记](https://github.com/suukii/Articles#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AE%97%E6%B3%95) +## 路西法的91天学算法第6期题目列表 + +[戳这里🔗](https://suukii.notion.site/91-days-algorithm-problem-list-db9d0cf2f33249a2af7bdb41aaa92930) + +## 更新说明 + +转到 Notion 上记录啦,更方便些,[戳这里🔗](https://suukii.notion.site/ca5e6d9d43704a9d82e44758636642d6?v=e7bdde0a51e9424fa96b876e78b03958) + +这个仓库可能不更新啦,内容也会逐步搬到 Notion 上的。 + +不过还是不要脸地说句,如果我的题解有帮到你的话,还是欢迎右上角 Star 🌟 这个仓库的。(拜托拜托ớ ₃ờ) + +## TOC + +| 基础篇 | 进阶篇 | 专题篇 | +| --------------------------- | ------------------------- | --------------------------------------- | +| [数组/栈/队列](#数组栈队列) | [高频面试题](#高频面试题) | [二分法](#二分法) | +| [链表](#链表) | [前缀树](#前缀树) | [滑动窗口](#滑动窗口) | +| [树](#树) | [并查集](#并查集) | [位运算](#位运算) | +| [哈希表](#哈希表) | [跳表](#跳表) | [搜索(BFS/DFS/回溯)](#搜索bfs-dfs-回溯) | +| [双指针](#双指针) | [剪枝](#剪枝) | [背包问题](#背包问题) | +| - | [字符串匹配](#字符串匹配) | [动态规划](#动态规划) | +| - | [堆](#堆) | [分治](#分治) | +| - | - | [贪心](#贪心) | ## 基础篇 @@ -67,6 +43,7 @@ - [x] [75.颜色分类](./basic/array-stack-queue/ext-sort-colors.md) - [x] [28.实现 strStr()](./basic/array-stack-queue/ext-implement-strstr.md) - [x] [380.常数时间插入、删除和获取随机元素](./basic/array-stack-queue/ext-insert-delete-getrandom-o1.md) +- [x] [189.旋转数组](./basic/array-stack-queue/ext-rotate-array.md) - [ ] [59. 螺旋矩阵 II](https://leetcode-cn.com/problems/spiral-matrix-ii/) - [ ] [859. 亲密字符串](https://leetcode-cn.com/problems/buddy-strings/) @@ -100,7 +77,9 @@ #### 链表拓展题目 -- [x] [21.合并两个有序链表](./basic/linked-list/ext-merge-two-sorted-lists.md) +- [x] [2.两数相加](./problems/2.add-two-numbers.md) +- [x] [19.删除链表的倒数第 N 个结点](./problems/0019.remove-nth-node-from-end-of-list.md) +- [x] [21.合并两个有序链表](./problems/0021.merge-two-sorted-lists.md) - [x] [83.删除排序链表中的重复元素](./basic/linked-list/ext-remove-duplicates-from-sorted-list.md) - [x] [206.反转链表](./basic/linked-list/ext-reverse-linked-list.md) @@ -121,6 +100,8 @@ - [x] [404.左叶子之和](./basic/binary-tree/ext-sum-of-left-leaves.md) - [x] [257.二叉树的所有路径](./basic/binary-tree/ext-binary-tree-paths.md) - [x] [112.路径总和](./basic/binary-tree/ext-path-sum.md) +- [x] [543.二叉树的直径](./basic/binary-tree/ext-diameter-of-binary-tree.md) +- [x] [98.验证二叉搜索树](./basic/binary-tree/ext-validate-binary-search-tree.md) ### 哈希表 @@ -135,11 +116,10 @@ #### 哈希表拓展题目 -- [x] [215.数组中的第 K 个最大元素](./basic/hashmap/ext-kth-largest-element-in-an-array.md) - [x] [645.错误的集合](./basic/hashmap/ext-set-mismatch.md) - [x] [面试题 04.01.节点间通路](./basic/hashmap/ext-route-between-nodes-lcci.md) - [ ] [36.有效的数独](https://leetcode-cn.com/problems/valid-sudoku) -- [ ] [149.直线上最多的点数](https://leetcode-cn.com/problems/max-points-on-a-line) +- [x] [149.直线上最多的点数](./basic/hashmap/ext-max-points-on-a-line.md) ### 双指针 @@ -181,6 +161,7 @@ **动态规划系列** - [x] [【day-37】62.不同路径](./medium/hot/37.unique-paths.md) +- [x] [673. 最长递增子序列的个数](./medium/dp/number-of-longest-increasing-subsequence.md) - [ ] [70. 爬楼梯](./) - [ ] [121. 买卖股票的最佳时机](./) - [ ] [122. 买卖股票的最佳时机 II](./) @@ -209,54 +190,87 @@ ### 前缀树 -- [x] [【day-41】208.实现 Trie](./medium/day-41.md) -- [x] [【day-42】677.键值映射](./medium/day-42.md) -- [x] [【day-43】面试题 17.17.多次搜索](./medium/day-43.md) +- [x] [【day-41】208.实现 Trie](./medium/trie/41.implement-trie-prefix-tree.md) +- [x] [【day-42】677.键值映射](./medium/trie/42.map-sum-pairs.md) +- [x] [【day-43】面试题 17.17.多次搜索](./medium/trie/43.multi-search-lcci.md) ### 并查集 -- [x] [【day-44】547.朋友圈](./medium/day-44.md) -- [x] [【day-45】924.尽量减少恶意软件的传播](./medium/day-45.md) -- [x] [【day-46】1319.连通网络的操作次数](./medium/day-46.md) +#### 每日一题 + +- [x] [【day-44】547.朋友圈](./medium/union-find/44.friend-circles.md) +- [x] [【day-45】924.尽量减少恶意软件的传播](./medium/union-find/45.minimize-malware-spread.md) +- [x] [【day-46】1319.连通网络的操作次数](./medium/union-find/46.number-of-operations-to-make-network-connected.md) + +#### 拓展 + +- [x] [1202.交换字符串中的元素](./medium/union-find/ext-smallest-string-with-swaps.md) ### 跳表 -- [ ] [【day-47】1206.设计跳表](./medium/day-47.md) +- [ ] [【day-47】1206.设计跳表](./) ### 剪枝 -- [x] [【day-48】814.二叉树剪枝](./medium/day-48.md) -- [x] [【day-49】39.组合总和](./medium/day-49.md) -- [x] [【day-49】39.组合总和](./medium/day-49.md) -- [x] [【day-50】40.组合总和 II](./medium/day-50.md) -- [ ] [【day-51】47.全排列 II](./medium/day-51.md) -- [ ] [【day-52】1371.每个元音包含偶数次的最长子字符串](./medium/day-52.md) -- [ ] [【day-53】面试题 17.13.恢复空格](./medium/day-53.md) -- [ ] [【day-54】1316.不同的循环子字符串](./) -- [ ] [【day-55】28.实现 strStr()](./) -- [ ] [【day-56】215.数组中的第 K 个最大元素](./) -- [ ] [【day-57】451.根据字符出现频率排序](./) -- [ ] [【day-58】295.数据流的中位数](./) -- [ ] [【day-59】378.有序矩阵中第 K 小的元素](./) -- [ ] [【day-60】1054.距离相等的条形码](./) -- [ ] [【day-61】面试题 17.09.第 k 个数](./) +#### 每日一题 + +- [x] [【day-48】814.二叉树剪枝](./medium/prune/48.binary-tree-pruning.md) +- [x] [【day-49】39.组合总和](./medium/prune/49.combination-sum.md) +- [x] [【day-50】40.组合总和 II](./medium/prune/50.combination-sum-ii.md) +- [ ] [【day-51】47.全排列 II](./medium/prune/51.permutations-ii.md) + +### 字符串匹配 + +#### 每日一题 + +- [ ] [【day-52】28.实现 strStr()](./medium/rk-kpm/52.implement-strstr.md) + +#### 拓展题目 + +- [ ] [1371.每个元音包含偶数次的最长子字符串](./medium/day-52.md) +- [ ] [面试题 17.13.恢复空格](./medium/day-53.md) +- [ ] [1316.不同的循环子字符串](./) +- [ ] [215.数组中的第 K 个最大元素](./) +- [ ] [451.根据字符出现频率排序](./) +- [ ] [295.数据流的中位数](./) +- [ ] [378.有序矩阵中第 K 小的元素](./) +- [ ] [1054.距离相等的条形码](./) +- [ ] [面试题 17.09.第 k 个数](./) + +### 堆 + +#### 每日一题 + +- [x] [【day-54】215.数组中的第 K 个最大元素](./medium/heap/54.kth-largest-element-in-an-array.md) +- [x] [【day-55】1046.最后一块石头的重量](./medium/heap/55.last-stone-weight.md) +- [x] [【day-56】23.合并 K 个升序链表](./medium/heap/56.merge-k-sorted-lists.md) +- [x] [【day-57】451.根据字符出现频率排序](./medium/heap/57.sort-characters-by-frequency.md) +- [x] [【day-58】378.有序矩阵中第 K 小的元素](./medium/heap/58.kth-smallest-element-in-a-sorted-matrix.md) +- [x] [【day-59】1054.距离相等的条形码](./medium/heap/59.distant-barcodes.md) ## 专题篇 ### 二分法 -- [x] [【day-62】69.x 的平方根](./topics/day-62.md) -- [x] [【day-63】278.第一个错误的版本](./topics/day-63.md) -- [x] [【day-64】162.寻找峰值](./topics/day-64.md) -- [ ] [【day-65】34.在排序数组中查找元素的第一个和最后一个位置](./) -- [ ] [【day-66】4.寻找两个正序数组的中位数](./) -- [ ] [【day-67】222.完全二叉树的节点个数](./) +#### 每日一题 + +- [x] [【day-61】69.x 的平方根](./topics/binary-search/61.sqrtx.md) +- [x] [【day-62】278.第一个错误的版本](./topics/binary-search/62.first-bad-version.md) +- [x] [【day-63】162.寻找峰值](./topics/binary-search/63.find-peak-element.md) + +#### 拓展题目 + +- [x] [33.搜索旋转排序数组](./topics/binary-search/ext-search-in-rotated-sorted-array.md) +- [x] [81.搜索旋转排序数组 II](./topics/binary-search/ext-search-in-rotated-sorted-array-ii.md) +- [ ] [34.在排序数组中查找元素的第一个和最后一个位置](./) +- [ ] [4.寻找两个正序数组的中位数](./) +- [ ] [222.完全二叉树的节点个数](./) ### 滑动窗口 #### 每日一题 -- [x] [【day-68】1456.定长子串中元音的最大数目](./topics/day-68.md) +- [x] [【day-67】1456.定长子串中元音的最大数目](./topics/sliding-window/67.maximum-number-of-vowels-in-a-substring-of-given-length.md) - [ ] [【day-70】76.最小覆盖子串](./topics/day-70.md) - [ ] [【day-71】30.串联所有单词的子串](./topics/day-71.md) @@ -278,6 +292,8 @@ - [ ] [【day-78】 89.格雷编码](./topics/day-78.md) - [x] [【day-79】980.不同路径 III](./topics/day-79.md) +- [x] [5210.球会落何处](./topics/searching/ext-where-will-the-ball-fall.md) + ### 背包问题 - [x] [【day-80】322.零钱兑换](./topics/day-80.md) @@ -315,4 +331,9 @@ ## 其他 - [x] [77.组合](./extensions/77.combination.md) +- [x] [5.最长回文子串](./extensions/5.longest-palindromic-substring.md) - [ ] [面试题 04.09. 二叉搜索树序列](./extensions/04.09.bst-sequences-lcci.md) + +> [在线电子书](https://app.gitbook.com/@suki/s/91-days-algorithm/) +> +> [笔记](https://github.com/suukii/Articles#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AE%97%E6%B3%95) diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..1885487 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight \ No newline at end of file diff --git a/algorithms/greedy.md b/algorithms/greedy.md index fdaae02..3aaa7de 100644 --- a/algorithms/greedy.md +++ b/algorithms/greedy.md @@ -19,12 +19,12 @@ ### 分配问题 -- [455.分发饼干](https://github.com/suukii/91-days-algorithm/blob/master/topics/greedy/ext-assign-cookies.md) -- [135.分发糖果](https://github.com/suukii/91-days-algorithm/blob/master/topics/greedy/ext-candy.md) +- [455.分发饼干](../topics/greedy/ext-assign-cookies.md) +- [135.分发糖果](../topics/greedy/ext-candy.md) ### 区间问题 -- [435.无重叠区间](https://github.com/suukii/91-days-algorithm/blob/master/topics/greedy/ext-non-overlapping-intervals.md) +- [435.无重叠区间](../topics/greedy/ext-non-overlapping-intervals.md) TODO diff --git a/algorithms/string-searching.md b/algorithms/string-searching.md new file mode 100644 index 0000000..3b8d70c --- /dev/null +++ b/algorithms/string-searching.md @@ -0,0 +1,82 @@ +# 字符串匹配算法 + +在一个长字符串或文章中,找出它是否包含一个或多个模式字符串及其位置。可以应用于生物基因匹配、信息检索等。 + +## Brute Force + +数据量不大的情况下,可以使用固定长度的滑动窗口枚举长串的所有子串,逐一与模式串进行比较。 + +- 防御性编程(如模式串长度大于长串长度) +- 初始化长度为模式串长度的滑动窗口 +- 将当前窗口的子串与模式串进行比较,若匹配成功,则记录相关信息如下标等 +- 将滑动窗口后移一格 + +## Rabin-Karp (RK) + +Rabin-Karp 是用于字符串匹配的算法 + +JavaScript Code + +TODO + +```js +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +var strStr = function (haystack, needle) { + if (!haystack || !needle || haystack.length < needle.length) return -1; + + const n = haystack.length, + m = needle.length; + + let hash1 = initHash(haystack, 0, m); + const hash2 = initHash(needle, 0, m); + + for (let i = 0; i <= n - m; i++) { + if (i > 0 && i <= n - m) { + hash1 = rehash(haystack, hash1, i - 1, i + m - 1, m); + } + + if (hash1 === hash2 && compare(haystack, needle, i)) { + return i; + } + } + + return -1; + + // ******************************************** + function initHash(string, start, end) { + let hashVal = 0; + for (let i = start; i < end; i++) { + const c = string[i]; + hashVal += + (c.charCodeAt(0) - 'a'.charCodeAt(0)) * + Math.pow(26, end - start); + } + return hashVal; + } + + function rehash(string, hashVal, oldIdx, newIdx, patLen) { + return ( + (hashVal - + (string.charCodeAt(oldIdx) - 'a'.charCodeAt(0) + 1) * + Math.pow(26, patLen - 1)) * + 26 + + (string.charCodeAt(newIdx) - 'a'.charCodeAt(0) + 1) + ); + } + + function compare(string, pattern, start) { + for (let i = 0; i < pattern.length; i++) { + if (string[i + start] !== pattern[i]) return false; + } + return true; + } +}; + +var a = strStr('lcode', 'code'); + +console.log(a); +``` diff --git a/assets/821_1.excalidraw b/assets/1202_0.excalidraw similarity index 50% rename from assets/821_1.excalidraw rename to assets/1202_0.excalidraw index 22afc6f..ecf5ead 100644 --- a/assets/821_1.excalidraw +++ b/assets/1202_0.excalidraw @@ -5,3331 +5,2845 @@ "elements": [ { "type": "rectangle", - "version": 54, - "versionNonce": 1075938326, + "version": 317, + "versionNonce": 80328852, "isDeleted": false, - "id": "KKdqwy_VPgyTkz34zBEGo", + "id": "FPXtphg22Iggb3MJhmi4G", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 182.62500000000026, - "y": 714.875, - "strokeColor": "#495057", + "x": 270, + "y": 61, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1770538122, + "width": 42, + "height": 34, + "seed": 398717484, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] + "boundElementIds": [] }, { - "type": "text", - "version": 21, - "versionNonce": 667618902, + "type": "rectangle", + "version": 354, + "versionNonce": 1346030252, "isDeleted": false, - "id": "EwqYu_GPDNVAlhmYrLvzT", + "id": "14-uYjVIrDPAeScE_o9-3", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 199.12500000000026, - "y": 717.875, - "strokeColor": "#495057", + "x": 314, + "y": 60, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 1977819978, + "width": 42, + "height": 34, + "seed": 2103233708, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { - "type": "rectangle", - "version": 70, - "versionNonce": 2135085974, + "type": "text", + "version": 269, + "versionNonce": 2108524052, "isDeleted": false, - "id": "IaDXhKlbNNtaQ1rKX5C5T", + "id": "SZs1xZjtPff6tkVimes97", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 223.62500000000026, - "y": 713.875, - "strokeColor": "#495057", + "x": 284, + "y": 66, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1492396554, + "width": 12, + "height": 24, + "seed": 536237868, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "a", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { "type": "text", - "version": 43, - "versionNonce": 907014358, + "version": 265, + "versionNonce": 577017132, "isDeleted": false, - "id": "qKO5U44OQlQ54t6CUQlzW", + "id": "qmqqbowKl4xsNc5ekZyZ_", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 237.12500000000026, - "y": 716.875, - "strokeColor": "#495057", + "x": 330, + "y": 65, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 699816138, + "width": 12, + "height": 24, + "seed": 2080018860, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "b", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 87, - "versionNonce": 1741121046, + "version": 332, + "versionNonce": 331064212, "isDeleted": false, - "id": "DjuhuUWv-QjRXTfO_VS4a", + "id": "athHOz8Gvm10WC_oCHXrD", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 264.6250000000002, - "y": 714.875, - "strokeColor": "#495057", + "x": 183, + "y": 62, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1740943242, + "width": 42, + "height": 34, + "seed": 1888713772, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { - "type": "text", - "version": 60, - "versionNonce": 1969107798, + "type": "rectangle", + "version": 369, + "versionNonce": 1374752684, "isDeleted": false, - "id": "NmqJVTLIoW956-00f71Ld", + "id": "WmQRCbb_ne001SNTJSqBL", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 278.6250000000002, - "y": 717.875, - "strokeColor": "#495057", + "x": 227, + "y": 61, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 1733963338, + "width": 42, + "height": 34, + "seed": 1739265708, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "v", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { - "type": "rectangle", - "version": 115, - "versionNonce": 1495881878, + "type": "text", + "version": 275, + "versionNonce": 1294602516, "isDeleted": false, - "id": "GNkaf5bm60rpvBI61hY_7", + "id": "EF1_1Fi46lzWqFJZMfMVu", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 305.6250000000002, - "y": 713.875, - "strokeColor": "#d9480f", + "x": 198, + "y": 67, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1028773130, + "width": 12, + "height": 24, + "seed": 2112577836, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "d", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { "type": "text", - "version": 93, - "versionNonce": 1874391114, + "version": 275, + "versionNonce": 2131376684, "isDeleted": false, - "id": "WsaXEICx6kmfHyzIdGx10", + "id": "9qMU5b6Ilrgl6Vh_fcoNK", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 319.1250000000002, - "y": 716.875, - "strokeColor": "#d9480f", + "x": 242, + "y": 66, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 723952586, + "width": 12, + "height": 24, + "seed": 717118380, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], + "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "c", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 91, - "versionNonce": 59812630, - "isDeleted": false, - "id": "r7L9sq-4Yrgu_yBHVsPnS", + "id": "dyIaT7S0jxoXeZDCivC1-", + "type": "text", + "x": 147, + "y": 64.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1749943852, + "version": 51, + "versionNonce": 2037304980, + "isDeleted": false, + "boundElementIds": null, + "text": "s", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 + }, + { + "id": "nVUJPlGmSQUM326mbz504", + "type": "text", + "x": 99, + "y": 111.5, + "width": 59, + "height": 24, "angle": 0, - "x": 346.6250000000002, - "y": 713.875, - "strokeColor": "#495057", + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 183736970, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "seed": 1535402156, + "version": 84, + "versionNonce": 882513068, + "isDeleted": false, + "boundElementIds": null, + "text": "pairs", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 }, { + "id": "cq2xpUs5diaZs-3doSDWv", "type": "text", - "version": 60, - "versionNonce": 834066518, + "x": 175, + "y": 113.5, + "width": 82, + "height": 48, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2081123116, + "version": 106, + "versionNonce": 155180052, + "isDeleted": false, + "boundElementIds": null, + "text": "[[0,3],\n [1,2]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 43 + }, + { + "type": "rectangle", + "version": 473, + "versionNonce": 273325868, "isDeleted": false, - "id": "KWYP6qv_nGx66lwLUiuBI", + "id": "hCoZ9d3wBvVXg2j16yeEG", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 363.1250000000002, - "y": 717.875, - "strokeColor": "#495057", + "x": 472, + "y": 116, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 997439818, + "width": 42, + "height": 34, + "seed": 1011688876, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { "type": "rectangle", - "version": 118, - "versionNonce": 757423510, + "version": 507, + "versionNonce": 1720924564, "isDeleted": false, - "id": "BRt2-bSED06H22BKVgAsN", + "id": "aqYPE8sA0e3FhVVr1nzCr", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 387.6250000000002, - "y": 713.875, + "x": 516, + "y": 115, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 201457674, + "width": 42, + "height": 34, + "seed": 829657132, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 91, - "versionNonce": 1527855830, + "version": 425, + "versionNonce": 1787156908, "isDeleted": false, - "id": "F0Dvm919YPjVsL11AKYjH", + "id": "TqAgem0GBbT3F90wl50z-", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 401.1250000000002, - "y": 716.875, - "strokeColor": "#d9480f", + "x": 486, + "y": 121, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 681144010, + "width": 12, + "height": 24, + "seed": 996715180, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 135, - "versionNonce": 839872534, + "type": "text", + "version": 418, + "versionNonce": 1285482260, "isDeleted": false, - "id": "mXV62LF6tpn-k_D1Tmegn", + "id": "CQpQEq89JGpTjA5kiTAqR", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 428.6250000000002, - "y": 714.875, + "x": 532, + "y": 120, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 97846666, + "width": 12, + "height": 24, + "seed": 752252204, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 109, - "versionNonce": 236256598, + "type": "rectangle", + "version": 490, + "versionNonce": 1982042516, "isDeleted": false, - "id": "__nUIT-TeqhwspXyzyeQa", + "id": "bco4OUO4o6gx8hO2nf90Z", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 443.1250000000002, - "y": 717.875, + "x": 385, + "y": 117, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1290781770, + "width": 42, + "height": 34, + "seed": 1931931564, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "uwZsAvqxgd9fe3J7b0XZK" + ] }, { "type": "rectangle", - "version": 157, - "versionNonce": 74900118, + "version": 519, + "versionNonce": 302276268, "isDeleted": false, - "id": "duJM8ScoT44M1MO5BOfj8", + "id": "-aX6VFzEu-QteNE56x6D4", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 469.6250000000002, - "y": 713.875, - "strokeColor": "#495057", + "x": 429, + "y": 116, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1204071178, + "width": 42, + "height": 34, + "seed": 1048844844, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 130, - "versionNonce": 938090454, + "version": 428, + "versionNonce": 1173828116, "isDeleted": false, - "id": "0txb_TgKH-d52qyOIiO9Z", + "id": "jhq8_p_I3rnTx7JQ1eW3e", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 483.1250000000002, - "y": 716.875, - "strokeColor": "#495057", + "x": 400, + "y": 122, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1288616394, + "width": 12, + "height": 24, + "seed": 702018732, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "t", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 119, - "versionNonce": 746829078, + "type": "text", + "version": 425, + "versionNonce": 500934956, "isDeleted": false, - "id": "3xx_JCaQXvgwepEEFv35-", + "id": "xKMtOy0hNDu9sZg8sFrSi", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 509.6250000000002, - "y": 713.875, - "strokeColor": "#495057", + "x": 444, + "y": 121, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 724103306, + "width": 12, + "height": 24, + "seed": 1657569068, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 92, - "versionNonce": 465085014, + "type": "rectangle", + "version": 487, + "versionNonce": 2112868244, "isDeleted": false, - "id": "njKXiOyi7Unc3jC4jh8Vn", + "id": "TAjdDZlLAlJLTNTO5awiY", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 523.6250000000002, - "y": 716.875, - "strokeColor": "#495057", + "x": 472, + "y": 185, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 378425162, + "width": 42, + "height": 34, + "seed": 1372305836, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "c", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { "type": "rectangle", - "version": 144, - "versionNonce": 1214113686, + "version": 516, + "versionNonce": 1969595308, "isDeleted": false, - "id": "kTee0vEf2NmC58ex0Gb_p", + "id": "D8ivz0p49JhmNIPvfh6gy", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 550.6250000000002, - "y": 712.875, - "strokeColor": "#495057", + "x": 516, + "y": 184, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 324654602, + "width": 42, + "height": 34, + "seed": 1107272748, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 120, - "versionNonce": 1386775766, + "version": 439, + "versionNonce": 939048212, "isDeleted": false, - "id": "ZrGYrMAKAmQYlUXAnRBsR", + "id": "WEDyzImTDBX083XJzsATI", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 564.1250000000002, - "y": 715.875, - "strokeColor": "#495057", + "x": 486, + "y": 190, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1652982986, + "width": 12, + "height": 24, + "seed": 156384940, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 161, - "versionNonce": 204306966, + "type": "text", + "version": 427, + "versionNonce": 1858883116, "isDeleted": false, - "id": "KZewDCBq0uyplpOPkghum", + "id": "Jn7gR8hpe7JOBIq0bByZT", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 591.6250000000002, - "y": 713.875, - "strokeColor": "#495057", + "x": 532, + "y": 189, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1840208778, + "width": 12, + "height": 24, + "seed": 812484908, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 138, - "versionNonce": 1273087830, + "type": "rectangle", + "version": 501, + "versionNonce": 946093844, "isDeleted": false, - "id": "5AH3WttF1AIsmjonIgU3d", + "id": "yfKJKeSmlUjpA2Erz61nr", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 606.1250000000002, - "y": 716.875, - "strokeColor": "#495057", + "x": 385, + "y": 186, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 856644170, + "width": 42, + "height": 34, + "seed": 448496556, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "d", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "vsoMef5d6NAwUc11snhDc" + ] }, { "type": "rectangle", - "version": 189, - "versionNonce": 1109027990, + "version": 536, + "versionNonce": 2035517460, "isDeleted": false, - "id": "elCnmUAVJlKIxbMq3bkSJ", + "id": "YbdMfwgXorwGvQq8mVVK9", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 632.6250000000002, - "y": 712.875, - "strokeColor": "#d9480f", + "x": 429, + "y": 185, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 830570762, + "width": 42, + "height": 34, + "seed": 778448428, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 165, - "versionNonce": 1284270550, + "version": 440, + "versionNonce": 496481068, "isDeleted": false, - "id": "FXA_8pdwNM9I94dJ-xZgK", + "id": "Tz30bYsdWXV4SgabX_dxN", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 646.1250000000002, - "y": 715.875, - "strokeColor": "#d9480f", + "x": 400, + "y": 191, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1417727946, + "width": 12, + "height": 24, + "seed": 2086111404, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "draw", - "version": 129, - "versionNonce": 1246543638, + "type": "text", + "version": 442, + "versionNonce": 1867605396, "isDeleted": false, - "id": "IVOsfFSVFzUZZHOQ0ZwOc", + "id": "HZJG8jhErMWE3xah10udN", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 173.62500000000026, - "y": 699.875, + "x": 444, + "y": 190, + "strokeColor": "#5c940d", + "backgroundColor": "transparent", + "width": 12, + "height": 24, + "seed": 1748603692, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "id": "uwZsAvqxgd9fe3J7b0XZK", + "type": "arrow", + "x": 249, + "y": 124, + "width": 127, + "height": 10.72240187735818, + "angle": 0, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 41, - "height": 75, - "seed": 1613252234, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, + "seed": 1349930412, + "version": 164, + "versionNonce": 2106640172, + "isDeleted": false, + "boundElementIds": null, "points": [ [ 0, 0 ], [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 + 127, + 10.72240187735818 ] ], - "lastCommittedPoint": null + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "bco4OUO4o6gx8hO2nf90Z", + "focus": -0.17340081393049345, + "gap": 9 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "draw", - "version": 163, - "versionNonce": 1875930198, - "isDeleted": false, - "id": "omtMrHReH8O_odiKk5gub", + "id": "vsoMef5d6NAwUc11snhDc", + "type": "arrow", + "x": 244, + "y": 153, + "width": 130, + "height": 44.280847306561384, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 320.6250000000002, - "y": 695.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 37, - "height": 80, - "seed": 1563616586, "groupIds": [], "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, + "seed": 909621292, + "version": 143, + "versionNonce": 482804140, + "isDeleted": false, + "boundElementIds": null, "points": [ [ 0, 0 ], [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 + 130, + 44.280847306561384 ] ], - "lastCommittedPoint": null + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "yfKJKeSmlUjpA2Erz61nr", + "focus": -0.2144965562479505, + "gap": 11 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "text", - "version": 75, - "versionNonce": 451703190, + "type": "rectangle", + "version": 669, + "versionNonce": 957330732, "isDeleted": false, - "id": "PteQr8wSU7Cy-mqz0VqrG", + "id": "Jw_rJqHQlwchqA04yc101", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 238.62500000000026, - "y": 669.375, + "x": 146, + "y": 391, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 40, - "height": 32, - "seed": 83602442, + "width": 42, + "height": 34, + "seed": 1701302956, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "窗口", - "baseline": 23, - "textAlign": "left", - "verticalAlign": "top" + "boundElementIds": [] }, { - "type": "rectangle", - "version": 80, - "versionNonce": 2011035926, + "type": "text", + "version": 580, + "versionNonce": 1758626708, "isDeleted": false, - "id": "PxaqcV7b7MJX1czfR5_mZ", + "id": "2AVTQUUER9V7YHnZS5o08", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 183.62500000000023, - "y": 862.875, - "strokeColor": "#495057", + "x": 162, + "y": 396, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 243236746, + "width": 12, + "height": 24, + "seed": 481336620, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 47, - "versionNonce": 1169318742, + "type": "rectangle", + "version": 719, + "versionNonce": 641216428, "isDeleted": false, - "id": "_WzEpmBHISv7yj965EEYD", + "id": "8zZkLBUTAWWFtgp-A2K6R", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 200.12500000000023, - "y": 865.875, - "strokeColor": "#495057", + "x": 278, + "y": 393, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 42, + "height": 34, + "seed": 897324972, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "uwZsAvqxgd9fe3J7b0XZK" + ] + }, + { + "type": "text", + "version": 659, + "versionNonce": 476377364, + "isDeleted": false, + "id": "18MDlXf4vbYud0PYRnhc9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 293, + "y": 398, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 238747210, + "width": 12, + "height": 24, + "seed": 1274298924, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 96, - "versionNonce": 1870104726, + "version": 676, + "versionNonce": 2104318508, "isDeleted": false, - "id": "kZEiySGQX840ua_GheJ39", + "id": "DzcOICMTQkffY22Se6dGf", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 224.62500000000023, - "y": 861.875, - "strokeColor": "#495057", + "x": 190, + "y": 392, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1872274698, + "width": 42, + "height": 34, + "seed": 1728257196, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 69, - "versionNonce": 132515286, + "version": 628, + "versionNonce": 1582149268, "isDeleted": false, - "id": "qtR4sSsFesijwGj3J81Up", + "id": "piCQGFxfEJFgpDeVz9ZqV", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 238.12500000000023, - "y": 864.875, - "strokeColor": "#495057", + "x": 204, + "y": 397, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 202601418, + "width": 12, + "height": 24, + "seed": 542287660, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 113, - "versionNonce": 538106646, + "version": 696, + "versionNonce": 966341804, "isDeleted": false, - "id": "OUG8XjO4qwwMtXewT6v4d", + "id": "qBmuTxrmqM9geIHJK_ATs", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 265.6250000000002, - "y": 862.875, - "strokeColor": "#495057", + "x": 234, + "y": 393, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1439066762, + "width": 42, + "height": 34, + "seed": 1280106924, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 86, - "versionNonce": 1584597078, + "version": 602, + "versionNonce": 792902676, "isDeleted": false, - "id": "69JCI3PLMLWoxoTyx8BZg", + "id": "27TuhfHvzbBvw4teKraIL", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 279.6250000000002, - "y": 865.875, - "strokeColor": "#495057", + "x": 249, + "y": 398, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 1131186506, + "width": 12, + "height": 24, + "seed": 572247084, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "v", - "baseline": 23, + "fontFamily": 3, + "text": "c", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 141, - "versionNonce": 1390120342, + "id": "y5xN2boxo49omRQVQKbHs", + "type": "arrow", + "x": 266.5867597073317, + "y": 297.8778326064348, + "width": 32.58675970733168, + "height": 74.12216739356518, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1672046252, + "version": 188, + "versionNonce": 1675265172, "isDeleted": false, - "id": "N0hkKlHGFeUF6rp-5Yr-W", + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + -32.58675970733168, + 74.12216739356518 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "rx0XE-wHwShzWuOV6s7Mv", + "type": "text", + "x": 273, + "y": 322.5, + "width": 300, + "height": 52, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 94351660, + "version": 336, + "versionNonce": 1703300140, + "isDeleted": false, + "boundElementIds": null, + "text": "因此,对相同色块进行分别排序后\n就能得到结果", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 47 + }, + { + "id": "TncKu8wLm5y3IiBR7k16k", + "type": "rectangle", + "x": 70, + "y": -3, + "width": 517, + "height": 464, "angle": 0, - "x": 306.6250000000002, - "y": 861.875, - "strokeColor": "#d9480f", + "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1012977674, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "seed": 1466477484, + "version": 172, + "versionNonce": 1134881556, + "isDeleted": false, + "boundElementIds": null }, { - "type": "text", - "version": 119, - "versionNonce": 2011843402, + "type": "rectangle", + "version": 353, + "versionNonce": 196029332, "isDeleted": false, - "id": "Ci0r2SUeU0F1PqUxUQoBD", + "id": "A11OZWeOrQfLDFXkSV0wC", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 320.1250000000002, - "y": 864.875, - "strokeColor": "#d9480f", + "x": 270, + "y": 567, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 77479626, + "width": 42, + "height": 34, + "seed": 327548972, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { "type": "rectangle", - "version": 117, - "versionNonce": 603562006, + "version": 390, + "versionNonce": 718931884, "isDeleted": false, - "id": "2EyKM9FOLjIFowbQjk4Vh", + "id": "ssTYdjs-oX9FRKzdHDFZl", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 347.6250000000002, - "y": 861.875, - "strokeColor": "#495057", + "x": 314, + "y": 566, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 683660682, + "width": 42, + "height": 34, + "seed": 296557228, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 86, - "versionNonce": 590949718, + "version": 305, + "versionNonce": 225220884, "isDeleted": false, - "id": "powVOvUZbWZ2P4vnpneql", + "id": "PhJswkwiYlFBZLpzxDwfp", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 364.1250000000002, - "y": 865.875, - "strokeColor": "#495057", + "x": 284, + "y": 572, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 1778422858, + "width": 12, + "height": 24, + "seed": 554493228, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 144, - "versionNonce": 1167397526, + "type": "text", + "version": 301, + "versionNonce": 1075065388, "isDeleted": false, - "id": "X8SEqiW2zGkRh-6j58f6x", + "id": "gcHRhxTtu0XcMMkzQsT5I", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 388.6250000000002, - "y": 861.875, - "strokeColor": "#d9480f", + "x": 330, + "y": 571, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 708541194, + "width": 12, + "height": 24, + "seed": 1997496236, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 117, - "versionNonce": 365055958, + "type": "rectangle", + "version": 368, + "versionNonce": 538990228, "isDeleted": false, - "id": "h8OxOyXNYX6jtZp8YcxBt", + "id": "PZ2YA1xAk5wKjXeS7Hlwa", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 402.1250000000002, - "y": 864.875, - "strokeColor": "#d9480f", + "x": 183, + "y": 568, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1475054026, + "width": 42, + "height": 34, + "seed": 199133740, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { "type": "rectangle", - "version": 161, - "versionNonce": 2144724246, + "version": 405, + "versionNonce": 832900268, "isDeleted": false, - "id": "GYTj4i2kfeZLBsEfwTBBz", + "id": "WntVtf-n8-AOVN0tMrYG6", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 429.6250000000002, - "y": 862.875, - "strokeColor": "#d9480f", + "x": 227, + "y": 567, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1512816778, + "width": 42, + "height": 34, + "seed": 1113875628, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 135, - "versionNonce": 625267286, + "version": 311, + "versionNonce": 1887462420, "isDeleted": false, - "id": "DaWA6SJ4p7Fjsv5wVrr5h", + "id": "y4v_Y4zYqKgYo7HkEJVId", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 444.1250000000002, - "y": 865.875, - "strokeColor": "#d9480f", + "x": 198, + "y": 573, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 2092375882, + "width": 12, + "height": 24, + "seed": 273346348, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 183, - "versionNonce": 820254614, + "type": "text", + "version": 311, + "versionNonce": 557225772, "isDeleted": false, - "id": "i3er1CWXJNFbQ-2qtpJiX", + "id": "rEjJIwHWSn979Ahfl9sT3", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 470.6250000000002, - "y": 861.875, - "strokeColor": "#495057", + "x": 242, + "y": 572, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1541973514, + "width": 12, + "height": 24, + "seed": 637282732, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { + "id": "KL_JxBwrnL3B1YmaZAjNl", "type": "text", - "version": 156, - "versionNonce": 719893718, + "x": 147, + "y": 570.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1627379500, + "version": 87, + "versionNonce": 612549012, "isDeleted": false, - "id": "IC7tIWlRv9Ru0B8LiYzWM", + "boundElementIds": null, + "text": "s", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 + }, + { + "id": "VL_BMVfhO9dPLclyCK4u4", + "type": "text", + "x": 99, + "y": 617.5, + "width": 59, + "height": 24, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 366468012, + "version": 120, + "versionNonce": 1798492588, + "isDeleted": false, + "boundElementIds": null, + "text": "pairs", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 + }, + { + "id": "glbn25lcgRmrND997YT9M", + "type": "text", + "x": 175, + "y": 619.5, + "width": 82, + "height": 72, "angle": 0, - "x": 484.1250000000002, - "y": 864.875, - "strokeColor": "#495057", + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1354454218, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], + "seed": 1700932268, + "version": 154, + "versionNonce": 861761300, + "isDeleted": false, + "boundElementIds": null, + "text": "[[0,3],\n [1,2],\n [0,2]]", "fontSize": 20, - "fontFamily": 1, - "text": "t", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 }, { "type": "rectangle", - "version": 145, - "versionNonce": 1290250774, + "version": 521, + "versionNonce": 1145813036, "isDeleted": false, - "id": "EJPaI1t8NQZcG-LePl2cG", + "id": "0zFfxtPCC_zfzA4At9duG", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 510.6250000000002, - "y": 861.875, - "strokeColor": "#495057", + "x": 474, + "y": 605, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1556753290, + "width": 42, + "height": 34, + "seed": 1292915372, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { - "type": "text", - "version": 118, - "versionNonce": 1440085846, + "type": "rectangle", + "version": 555, + "versionNonce": 1099706516, "isDeleted": false, - "id": "omYqp6IfJz9_PBYgGADI0", + "id": "7n3_8k4Jx59iWgh96MRI2", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 524.6250000000002, - "y": 864.875, - "strokeColor": "#495057", + "x": 518, + "y": 604, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 374352458, + "width": 42, + "height": 34, + "seed": 2068389164, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "c", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { - "type": "rectangle", - "version": 170, - "versionNonce": 1577622678, + "type": "text", + "version": 473, + "versionNonce": 284938924, "isDeleted": false, - "id": "_0rPCyKPyLuC-AJ_nHrD_", + "id": "XgEwmRuV8UDNdIGnAWNuo", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 551.6250000000002, - "y": 860.875, - "strokeColor": "#495057", + "x": 488, + "y": 610, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 338186506, + "width": 12, + "height": 24, + "seed": 755275692, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "a", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { "type": "text", - "version": 146, - "versionNonce": 724867542, + "version": 466, + "versionNonce": 1801518612, "isDeleted": false, - "id": "X_duYtwo4rpv-KH5N20cq", + "id": "O7dmHgQfs-hTuzmC0fPah", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 565.1250000000002, - "y": 863.875, - "strokeColor": "#495057", + "x": 534, + "y": 609, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1506648010, + "width": 12, + "height": 24, + "seed": 1047314988, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "b", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 187, - "versionNonce": 74379030, + "version": 537, + "versionNonce": 902077740, "isDeleted": false, - "id": "NcP5xCCjSLtZvQ5gvSWr8", + "id": "6gf-xtIniwtuE1L5vYoZv", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 592.6250000000002, - "y": 861.875, - "strokeColor": "#495057", + "x": 387, + "y": 606, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 42, + "height": 34, + "seed": 1986763948, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [ + "ooPrTE-XjlMtiz-5fLd3-" + ] + }, + { + "type": "rectangle", + "version": 567, + "versionNonce": 202381228, + "isDeleted": false, + "id": "fW0my0cI5z0e69tAhGzUz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 431, + "y": 605, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1130043018, + "width": 42, + "height": 34, + "seed": 782968620, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 164, - "versionNonce": 103586902, + "version": 476, + "versionNonce": 241142036, "isDeleted": false, - "id": "c4DfNNBQYMGvKfxcoXTm9", + "id": "sKNxQHXwQsCsuHBh3X7_n", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 607.1250000000002, - "y": 864.875, - "strokeColor": "#495057", + "x": 402, + "y": 611, + "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1904981322, + "width": 12, + "height": 24, + "seed": 2073387436, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, + "fontFamily": 3, "text": "d", - "baseline": 23, + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" + }, + { + "type": "text", + "version": 473, + "versionNonce": 805847596, + "isDeleted": false, + "id": "eTRE_NjHmBHNuspTgQlsX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 446, + "y": 610, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "width": 12, + "height": 24, + "seed": 1414810668, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 215, - "versionNonce": 1984078230, + "version": 546, + "versionNonce": 269303084, "isDeleted": false, - "id": "Qp93ae_rbQTIiRnNQpv6n", + "id": "zsZqcH5sQo6nHeUpHdS-_", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 633.6250000000002, - "y": 860.875, - "strokeColor": "#d9480f", + "x": 476, + "y": 656, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 901413898, + "width": 42, + "height": 34, + "seed": 773742100, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { - "type": "text", - "version": 191, - "versionNonce": 400948950, + "type": "rectangle", + "version": 575, + "versionNonce": 1413789612, "isDeleted": false, - "id": "Bv09KHW8A5R3Ge-ND_6Bs", + "id": "EZNvlvbxWDKbrhBchxjIb", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 647.1250000000002, - "y": 863.875, - "strokeColor": "#d9480f", + "x": 520, + "y": 655, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 2111990474, + "width": 42, + "height": 34, + "seed": 810646420, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [] }, { - "type": "draw", - "version": 188, - "versionNonce": 2141959190, + "type": "text", + "version": 498, + "versionNonce": 1219027500, "isDeleted": false, - "id": "k8pMsvosX8vmeh6Jv0_bL", + "id": "2fTXHMkwZUYhjwb7TG6SP", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 336.6250000000002, - "y": 848.875, - "strokeColor": "#d9480f", + "x": 490, + "y": 661, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 41, - "height": 75, - "seed": 1084129674, + "width": 12, + "height": 24, + "seed": 155511060, "groupIds": [], - "strokeSharpness": "round", + "strokeSharpness": "sharp", "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null + "fontSize": 20, + "fontFamily": 3, + "text": "a", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "draw", - "version": 209, - "versionNonce": 1737015638, + "type": "text", + "version": 486, + "versionNonce": 606321836, "isDeleted": false, - "id": "IonV8V0i_NJdX7LW3S-l1", + "id": "HLEs8_50Ii6MQRfHmCE8v", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 409.6250000000002, - "y": 846.875, - "strokeColor": "#d9480f", + "x": 536, + "y": 660, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 37, - "height": 80, - "seed": 1764343882, + "width": 12, + "height": 24, + "seed": 477013652, "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null - }, - { - "type": "text", - "version": 139, - "versionNonce": 47326870, - "isDeleted": false, - "id": "9Ifc1xJmmqGjli-3KbH39", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 347.6250000000002, - "y": 822.375, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 40, - "height": 32, - "seed": 1130309386, - "groupIds": [], - "strokeSharpness": "sharp", + "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "窗口", - "baseline": 23, - "textAlign": "left", - "verticalAlign": "top" + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { "type": "rectangle", - "version": 134, - "versionNonce": 948181194, + "version": 562, + "versionNonce": 222286228, "isDeleted": false, - "id": "5BrQt0l74VbilKH-h2d99", + "id": "eKMJyyrsDHbCRepZPt2D0", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 179.62500000000023, - "y": 1026.875, - "strokeColor": "#495057", + "x": 389, + "y": 657, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 635793558, + "width": 42, + "height": 34, + "seed": 1854190612, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" + "VebfbGhpd8488QIk0ozA-" ] }, - { - "type": "text", - "version": 101, - "versionNonce": 2134377098, - "isDeleted": false, - "id": "wUkHZ0ZNjtHT3X_GRlzmJ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 196.12500000000023, - "y": 1029.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 139914710, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, { "type": "rectangle", - "version": 150, - "versionNonce": 2062229834, + "version": 595, + "versionNonce": 1908769196, "isDeleted": false, - "id": "X_J8VnDAXG03-RkMpCz4U", + "id": "DHWTECqTxNilwiIJQzkdg", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 220.62500000000023, - "y": 1025.875, - "strokeColor": "#495057", + "x": 433, + "y": 656, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 841401110, + "width": 42, + "height": 34, + "seed": 2105348500, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 123, - "versionNonce": 944531466, + "version": 499, + "versionNonce": 1333816364, "isDeleted": false, - "id": "Fi10FSm59UzXA6MVKhl-6", + "id": "xdPnGvxGnagB2qecxwtUh", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 234.12500000000023, - "y": 1028.875, - "strokeColor": "#495057", + "x": 404, + "y": 662, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1439297622, + "width": 12, + "height": 24, + "seed": 411942676, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, - { - "type": "rectangle", - "version": 167, - "versionNonce": 794220234, - "isDeleted": false, - "id": "eWLHvdIz0qIckz6uJ1z-N", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 261.6250000000002, - "y": 1026.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 253064598, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, { "type": "text", - "version": 140, - "versionNonce": 547712394, + "version": 501, + "versionNonce": 997852844, "isDeleted": false, - "id": "w6lfuAbqssM5k5_bsddsF", + "id": "KXifC1TtlSjPH9yxC9nc6", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 275.6250000000002, - "y": 1029.875, - "strokeColor": "#495057", + "x": 448, + "y": 661, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 926831318, + "width": 12, + "height": 24, + "seed": 942455956, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "v", - "baseline": 23, + "fontFamily": 3, + "text": "c", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 195, - "versionNonce": 24325194, - "isDeleted": false, - "id": "1ENSsBld9kz-J3TVZ7q09", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, + "id": "ooPrTE-XjlMtiz-5fLd3-", + "type": "arrow", + "x": 249, + "y": 630, + "width": 129, + "height": 3.2140153744048803, "angle": 0, - "x": 302.6250000000002, - "y": 1025.875, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 953780246, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 173, - "versionNonce": 335425750, - "isDeleted": false, - "id": "y8auOFbLmCWyYQYvmNjtI", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 316.1250000000002, - "y": 1028.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1675367766, "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 171, - "versionNonce": 1972904394, + "strokeSharpness": "round", + "seed": 1123067308, + "version": 249, + "versionNonce": 1221590676, "isDeleted": false, - "id": "GzY58Lm2PMYp2Ad1UrP6M", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 343.6250000000002, - "y": 1025.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1100675734, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 129, + -3.2140153744048803 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "6gf-xtIniwtuE1L5vYoZv", + "focus": -0.17340081393049164, + "gap": 9 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "text", - "version": 140, - "versionNonce": 1183144074, - "isDeleted": false, - "id": "NR8xV9LO2XllrLIW68J_Y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, + "id": "VebfbGhpd8488QIk0ozA-", + "type": "arrow", + "x": 249, + "y": 656, + "width": 134, + "height": 16.301519090170586, "angle": 0, - "x": 360.1250000000002, - "y": 1029.875, - "strokeColor": "#495057", + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 1758148566, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 198, - "versionNonce": 1511896906, - "isDeleted": false, - "id": "P2XAqHsrVCxRA_89dXZks", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 384.6250000000002, - "y": 1025.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1367461142, "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 171, - "versionNonce": 12336650, + "strokeSharpness": "round", + "seed": 1010629804, + "version": 248, + "versionNonce": 1934657324, "isDeleted": false, - "id": "CDDOvZ6BNPGtfgqXYcjAN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 398.1250000000002, - "y": 1028.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 691255894, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 134, + 16.301519090170586 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "focus": -0.08111360757199602, + "gap": 6, + "elementId": "eKMJyyrsDHbCRepZPt2D0" + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "rectangle", - "version": 215, - "versionNonce": 1197206730, - "isDeleted": false, - "id": "PenDHhw0GOKt6U1DUoO7L", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, + "id": "ar_zxBYV8uh7OL7opKAHg", + "type": "arrow", + "x": 239.68644306510686, + "y": 889.0931957736611, + "width": 0.17079434472600497, + "height": 75.25602504555775, "angle": 0, - "x": 425.6250000000002, - "y": 1026.875, - "strokeColor": "#d9480f", + "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 649461654, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 189, - "versionNonce": 1670890378, - "isDeleted": false, - "id": "kHQF6lPA5tc1ulktoXzCo", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 440.1250000000002, - "y": 1029.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1581096150, "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 237, - "versionNonce": 531284554, + "strokeSharpness": "round", + "seed": 572694316, + "version": 304, + "versionNonce": 1703760660, "isDeleted": false, - "id": "r71Kekji56tvMi7DTjY3H", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 466.6250000000002, - "y": 1025.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 358584854, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + -0.17079434472600497, + 75.25602504555775 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "6kytkpqiES_5EcjfgH1xo", + "focus": 1.1916156552217554, + "gap": 15.313556934893143 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" }, { + "id": "6kytkpqiES_5EcjfgH1xo", "type": "text", - "version": 210, - "versionNonce": 1181739274, - "isDeleted": false, - "id": "B25Og6URYQqb2z5HI7gML", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, + "x": 255, + "y": 898.5, + "width": 160, + "height": 26, "angle": 0, - "x": 480.1250000000002, - "y": 1028.875, "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 386981718, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "t", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, - { - "type": "rectangle", - "version": 199, - "versionNonce": 258095050, - "isDeleted": false, - "id": "I49X3tmFfTtDLLqQE6rew", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 506.6250000000002, - "y": 1025.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 128353430, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 172, - "versionNonce": 178040458, + "seed": 1186053524, + "version": 302, + "versionNonce": 49551404, "isDeleted": false, - "id": "cAB7ANluullrSk0qxKP7S", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 520.6250000000002, - "y": 1028.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 953516502, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], + "boundElementIds": [ + "ar_zxBYV8uh7OL7opKAHg" + ], + "text": "在相同色块内排序", "fontSize": 20, - "fontFamily": 1, - "text": "c", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 21 }, { + "id": "01yzKwIenpELkyQuxeVzv", "type": "rectangle", - "version": 224, - "versionNonce": 215633226, - "isDeleted": false, - "id": "2M54jA3OIEbjR0BYZHjhP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, + "x": 69, + "y": 490, + "width": 517, + "height": 546, "angle": 0, - "x": 547.6250000000002, - "y": 1024.875, "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 2108872470, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 200, - "versionNonce": 460723210, - "isDeleted": false, - "id": "5946oIgqdIWH0bWjA8VkL", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 561.1250000000002, - "y": 1027.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 2125694038, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "seed": 414391700, + "version": 237, + "versionNonce": 1461669524, + "isDeleted": false, + "boundElementIds": null }, { "type": "rectangle", - "version": 241, - "versionNonce": 1483408074, + "version": 576, + "versionNonce": 850937260, "isDeleted": false, - "id": "FLW-PRwBBADaDQo-shAuz", + "id": "tafKsubJXQ6tbVjQEZVUq", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 588.6250000000002, - "y": 1025.875, - "strokeColor": "#495057", + "x": 479, + "y": 711, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 229411222, + "width": 42, + "height": 34, + "seed": 398986644, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, - { - "type": "text", - "version": 218, - "versionNonce": 1851005322, - "isDeleted": false, - "id": "KTnxzs0BB7AgoC3ljNwFD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 603.1250000000002, - "y": 1028.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 2043864790, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "d", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" - }, { "type": "rectangle", - "version": 269, - "versionNonce": 2087475274, + "version": 605, + "versionNonce": 1836757036, "isDeleted": false, - "id": "YmN4NwkIKiaqFVjFJxMP4", + "id": "0GU8-yEjZ3CvRsI1eqIY8", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 629.6250000000002, - "y": 1024.875, - "strokeColor": "#d9480f", + "x": 523, + "y": 710, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1673239574, + "width": 42, + "height": 34, + "seed": 672742164, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 245, - "versionNonce": 42909450, + "version": 528, + "versionNonce": 697027244, "isDeleted": false, - "id": "Aqd17lHIxsI_pmputge_v", + "id": "qx4wdEv_kmqvEj5pvknUz", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 643.1250000000002, - "y": 1027.875, - "strokeColor": "#d9480f", + "x": 493, + "y": 716, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 291219798, + "width": 12, + "height": 24, + "seed": 1088993428, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, - { - "type": "draw", - "version": 261, - "versionNonce": 1295404490, - "isDeleted": false, - "id": "hNrCwdD-5X4e5Dw_wZmxE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 409.6250000000002, - "y": 1013.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 41, - "height": 75, - "seed": 1107824278, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null - }, - { - "type": "draw", - "version": 275, - "versionNonce": 1635648650, - "isDeleted": false, - "id": "N-SGOmgK7H2LFihV59gdl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 449.6250000000002, - "y": 1009.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 37, - "height": 80, - "seed": 41274326, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null - }, - { - "type": "text", - "version": 225, - "versionNonce": 1763763018, - "isDeleted": false, - "id": "dGvVRC38vjx6XWDmWIlaH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 411.6250000000002, - "y": 987.375, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 40, - "height": 32, - "seed": 12181782, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "窗口", - "baseline": 23, - "textAlign": "left", - "verticalAlign": "top" - }, - { - "type": "rectangle", - "version": 156, - "versionNonce": 866785686, - "isDeleted": false, - "id": "mB34gwGrk5rM53yuxzLyr", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 182.62500000000023, - "y": 1194.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 2053776714, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] - }, { "type": "text", - "version": 124, - "versionNonce": 1187934922, + "version": 516, + "versionNonce": 697668908, "isDeleted": false, - "id": "LG-ZdXxURd96qKkv7ro1m", + "id": "6qxcrIRdBkS2px5Rq3enq", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 199.12500000000023, - "y": 1197.875, - "strokeColor": "#495057", + "x": 539, + "y": 715, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 2034953226, + "width": 12, + "height": 24, + "seed": 1575781908, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, + "fontFamily": 3, + "text": "b", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { "type": "rectangle", - "version": 173, - "versionNonce": 698250966, + "version": 595, + "versionNonce": 1394006444, "isDeleted": false, - "id": "a8S8Yqepbwv7usYDldXnu", + "id": "5gQRK9FNJlZkZBjGT-zNk", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 223.62500000000023, - "y": 1193.875, - "strokeColor": "#495057", + "x": 392, + "y": 712, + "strokeColor": "#5c940d", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1441061578, + "width": 42, + "height": 34, + "seed": 337290132, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 146, - "versionNonce": 516524426, - "isDeleted": false, - "id": "Xdsf09lmuT-_Qnx9P9CrH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 237.12500000000023, - "y": 1196.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1322447242, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "-LejJd3ozilHYLnOUl-ix" + ] }, { "type": "rectangle", - "version": 190, - "versionNonce": 865414166, - "isDeleted": false, - "id": "J26-pyIX0HYD1xlQ4hd8r", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 264.6250000000002, - "y": 1194.875, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 391131210, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElementIds": [] - }, - { - "type": "text", - "version": 163, - "versionNonce": 1555286090, + "version": 629, + "versionNonce": 1492874924, "isDeleted": false, - "id": "UP_Qb11FM_d-lzIG0n7O7", + "id": "OZ937vPy1GUFaFKF9avZ7", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 278.6250000000002, - "y": 1197.875, - "strokeColor": "#495057", + "x": 436, + "y": 711, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 1127716618, + "width": 42, + "height": 34, + "seed": 1772687636, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "v", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "Td7q8p2xs3wQt1angQ1WM" + ] }, { - "type": "rectangle", - "version": 218, - "versionNonce": 1333999958, + "type": "text", + "version": 535, + "versionNonce": 1567298732, "isDeleted": false, - "id": "9zYhWDCiNhUz_C3zoCqsE", + "id": "7IAIliFGIlKYbosM9Q4_g", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 305.6250000000002, - "y": 1193.875, + "x": 407, + "y": 717, "strokeColor": "#d9480f", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 855909834, + "width": 12, + "height": 24, + "seed": 772656788, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "d", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { "type": "text", - "version": 195, - "versionNonce": 1214787338, + "version": 534, + "versionNonce": 1996201772, "isDeleted": false, - "id": "z7d16FA6ZJqa3KkRp0f88", + "id": "gFtemXRbRc_ony2x-2uPw", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 319.1250000000002, - "y": 1196.875, - "strokeColor": "#d9480f", + "x": 451, + "y": 716, + "strokeColor": "#0b7285", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 2144394378, + "width": 12, + "height": 24, + "seed": 1375656980, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], + "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "c", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 194, - "versionNonce": 1958583958, + "id": "-LejJd3ozilHYLnOUl-ix", + "type": "arrow", + "x": 254, + "y": 682, + "width": 124.15870390087366, + "height": 41.90341134632956, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 448519316, + "version": 287, + "versionNonce": 288457620, "isDeleted": false, - "id": "_m4FN3vn-YdVY3CPtQMeq", + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 124.15870390087366, + 41.90341134632956 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "focus": -0.23507264585362692, + "gap": 13.841296099126339, + "elementId": "5gQRK9FNJlZkZBjGT-zNk" + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "Td7q8p2xs3wQt1angQ1WM", + "type": "arrow", + "x": 428, + "y": 760, + "width": 73.12124352691376, + "height": 68.95993873924021, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1789822100, + "version": 64, + "versionNonce": 1604164116, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + -73.12124352691376, + 68.95993873924021 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "OZ937vPy1GUFaFKF9avZ7", + "focus": -0.12635220752528603, + "gap": 15 + }, + "endBinding": { + "elementId": "H0Y1RZgpOBE9HkdZwHtvm", + "focus": 0.14579429633323204, + "gap": 4.878756473086241 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "ENuAn9xubxzZlkcXtZzsp", + "type": "text", + "x": 94, + "y": 761.5, + "width": 300, + "height": 52, "angle": 0, - "x": 346.6250000000002, - "y": 1193.875, "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1733868362, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "seed": 1475676436, + "version": 252, + "versionNonce": 161085204, + "isDeleted": false, + "boundElementIds": [ + "Td7q8p2xs3wQt1angQ1WM" + ], + "text": "两种色块有交集,所以可以组合,\n变成一种色块", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 47 }, { - "type": "text", - "version": 163, - "versionNonce": 1986117066, + "type": "rectangle", + "version": 638, + "versionNonce": 1562364588, "isDeleted": false, - "id": "1hBVeHWJhGznyM8Duucw8", + "id": "Sc7i2pXREIVMbroZSJpFJ", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 363.1250000000002, - "y": 1197.875, - "strokeColor": "#495057", + "x": 264, + "y": 832, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 5, - "height": 32, - "seed": 938918410, + "width": 42, + "height": 34, + "seed": 1056003988, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "l", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "Td7q8p2xs3wQt1angQ1WM" + ] }, { "type": "rectangle", - "version": 221, - "versionNonce": 1744395222, + "version": 666, + "versionNonce": 640663852, "isDeleted": false, - "id": "_ouZYDv1oIs1ezbkXIu0c", + "id": "H0Y1RZgpOBE9HkdZwHtvm", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 387.6250000000002, - "y": 1193.875, - "strokeColor": "#d9480f", + "x": 308, + "y": 831, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1017508042, + "width": 42, + "height": 34, + "seed": 1871267092, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [ + "Td7q8p2xs3wQt1angQ1WM" + ] }, { "type": "text", - "version": 194, - "versionNonce": 867923082, + "version": 587, + "versionNonce": 307667116, "isDeleted": false, - "id": "pjbMZuUAOsReXBQXJ51CQ", + "id": "0SYH-nCzx625BOoFOBwcm", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 401.1250000000002, - "y": 1196.875, - "strokeColor": "#d9480f", + "x": 278, + "y": 837, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 687949706, + "width": 12, + "height": 24, + "seed": 1908900500, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 238, - "versionNonce": 256602390, + "type": "text", + "version": 575, + "versionNonce": 513125164, "isDeleted": false, - "id": "C1Wbh43UuIwNVotcMD2Qy", + "id": "aHGglBSzsRB3J9p_tOnMj", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 428.6250000000002, - "y": 1194.875, - "strokeColor": "#d9480f", + "x": 324, + "y": 836, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 88327754, + "width": 12, + "height": 24, + "seed": 1549930516, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 212, - "versionNonce": 1915769674, + "type": "rectangle", + "version": 654, + "versionNonce": 73292332, "isDeleted": false, - "id": "eStnVMVHRNKhYnPZW7Evl", + "id": "uB5qW3e4rj4XtHwUMwMc-", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 443.1250000000002, - "y": 1197.875, - "strokeColor": "#d9480f", + "x": 177, + "y": 833, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 440954122, + "width": 42, + "height": 34, + "seed": 2135879060, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "-LejJd3ozilHYLnOUl-ix" + ] }, { "type": "rectangle", - "version": 260, - "versionNonce": 1177083478, + "version": 687, + "versionNonce": 1718472748, "isDeleted": false, - "id": "-pFAL7h_UuUk5aVlE4-uK", + "id": "viZASm3cM_0F1sQ9mryTf", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 469.6250000000002, - "y": 1193.875, - "strokeColor": "#495057", + "x": 221, + "y": 832, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 1569340362, + "width": 42, + "height": 34, + "seed": 1002707732, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 233, - "versionNonce": 874207754, + "version": 594, + "versionNonce": 1461381804, "isDeleted": false, - "id": "9_64B12ZnI8EO3iYXf8Bx", + "id": "sSPhgscB9u1xAtz6hiuMw", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 483.1250000000002, - "y": 1196.875, - "strokeColor": "#495057", + "x": 192, + "y": 838, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1562653322, + "width": 12, + "height": 24, + "seed": 1547147412, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "t", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 222, - "versionNonce": 828810134, + "type": "text", + "version": 593, + "versionNonce": 406893868, "isDeleted": false, - "id": "3-2OIeE_yvNx5PgSs9V_K", + "id": "UQc3rfEW3Ctzl0csBJfQ7", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 509.6250000000002, - "y": 1193.875, - "strokeColor": "#495057", + "x": 236, + "y": 837, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 735138122, + "width": 12, + "height": 24, + "seed": 1818191380, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 195, - "versionNonce": 2021099722, + "type": "rectangle", + "version": 730, + "versionNonce": 319371540, "isDeleted": false, - "id": "sxkN7eXMrukZWq-dpujuG", + "id": "oP7A8AVdqCsBC9rhV2jg-", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 523.6250000000002, - "y": 1196.875, - "strokeColor": "#495057", + "x": 165, + "y": 985, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 10, - "height": 32, - "seed": 1290573834, + "width": 42, + "height": 34, + "seed": 875633300, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "c", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "Td7q8p2xs3wQt1angQ1WM" + ] }, { "type": "rectangle", - "version": 247, - "versionNonce": 322552022, + "version": 760, + "versionNonce": 1745981996, "isDeleted": false, - "id": "29efoE3a0_voNNFnzFTRY", + "id": "g0PbQl-gtNCYgfLXFjTh0", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 550.6250000000002, - "y": 1192.875, - "strokeColor": "#495057", + "x": 209, + "y": 984, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 544278218, + "width": 42, + "height": 34, + "seed": 1943960880, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 223, - "versionNonce": 652205962, + "version": 681, + "versionNonce": 153679508, "isDeleted": false, - "id": "MaRFg_HR-zFsR5S-Jb0-7", + "id": "XcBZofbNxs4UOxrMPof_T", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 564.1250000000002, - "y": 1195.875, - "strokeColor": "#495057", + "x": 179, + "y": 990, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1324981642, + "width": 12, + "height": 24, + "seed": 1306044436, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "o", - "baseline": 23, + "fontFamily": 3, + "text": "a", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "rectangle", - "version": 264, - "versionNonce": 523712022, + "type": "text", + "version": 669, + "versionNonce": 855010476, "isDeleted": false, - "id": "cQmURMAhzrOwDVXXJZiVJ", + "id": "s7l87EuDrHMhpl_wscIAu", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 591.6250000000002, - "y": 1193.875, - "strokeColor": "#495057", + "x": 225, + "y": 989, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 901864522, + "width": 12, + "height": 24, + "seed": 1770998576, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [] + "boundElementIds": [], + "fontSize": 20, + "fontFamily": 3, + "text": "b", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "text", - "version": 241, - "versionNonce": 2072993354, + "type": "rectangle", + "version": 785, + "versionNonce": 1869939732, "isDeleted": false, - "id": "EAwofWRpxWFTJ9Ezg478k", + "id": "CD_bXrD5oqrDPKJNjyMXv", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 606.1250000000002, - "y": 1196.875, - "strokeColor": "#495057", + "x": 296, + "y": 984, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1386431242, + "width": 42, + "height": 34, + "seed": 970876208, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "d", - "baseline": 23, - "textAlign": "center", - "verticalAlign": "middle" + "boundElementIds": [ + "-LejJd3ozilHYLnOUl-ix" + ] }, { "type": "rectangle", - "version": 292, - "versionNonce": 1314128726, + "version": 810, + "versionNonce": 828110636, "isDeleted": false, - "id": "TGxyeiD3s5STS25IlUVNZ", + "id": "gOLdMpXAAA33R5kahieIB", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 632.6250000000002, - "y": 1192.875, - "strokeColor": "#d9480f", + "x": 253, + "y": 985, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 38, - "height": 38, - "seed": 807031242, + "width": 42, + "height": 34, + "seed": 909280660, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [] }, { "type": "text", - "version": 268, - "versionNonce": 1935738122, + "version": 726, + "versionNonce": 467886484, "isDeleted": false, - "id": "2nWFMobCGXXZMiH-nCAYK", + "id": "LKK05ZGye2oT6AfcQbW66", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 646.1250000000002, - "y": 1195.875, - "strokeColor": "#d9480f", + "x": 311, + "y": 989, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 11, - "height": 32, - "seed": 1363249290, + "width": 12, + "height": 24, + "seed": 738908464, "groupIds": [], "strokeSharpness": "sharp", "boundElementIds": [], "fontSize": 20, - "fontFamily": 1, - "text": "e", - "baseline": 23, + "fontFamily": 3, + "text": "d", + "baseline": 19, "textAlign": "center", "verticalAlign": "middle" }, { - "type": "draw", - "version": 310, - "versionNonce": 1549907530, + "type": "text", + "version": 714, + "versionNonce": 262943148, "isDeleted": false, - "id": "C7QzwoUaGbMLwOc1v2L3J", + "id": "9329oeTC0U9ynoHJ8gpkw", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 463.6250000000002, - "y": 1181.875, - "strokeColor": "#d9480f", + "x": 268, + "y": 990, + "strokeColor": "#364fc7", "backgroundColor": "transparent", - "width": 41, - "height": 75, - "seed": 1080606806, + "width": 12, + "height": 24, + "seed": 41202452, "groupIds": [], - "strokeSharpness": "round", + "strokeSharpness": "sharp", "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null + "fontSize": 20, + "fontFamily": 3, + "text": "c", + "baseline": 19, + "textAlign": "center", + "verticalAlign": "middle" }, { - "type": "draw", - "version": 327, - "versionNonce": 1355415498, - "isDeleted": false, - "id": "NQG7gnYv4L9HYUiXON78R", + "id": "8JvPbBSOQ1P_EAGU5usts", + "type": "text", + "x": 94, + "y": 4.5, + "width": 59, + "height": 24, + "angle": 0, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 650.6250000000003, - "y": 1176.875, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 37, - "height": 80, - "seed": 1984397718, "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "startBinding": null, - "endBinding": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null + "strokeSharpness": "sharp", + "seed": 1619911572, + "version": 51, + "versionNonce": 435893268, + "isDeleted": false, + "boundElementIds": null, + "text": "e.g.1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 }, { + "id": "2bRLAtYgw4FbSeQZfhMIx", "type": "text", - "version": 268, - "versionNonce": 1202264022, - "isDeleted": false, - "id": "Q6kM0jYeyu6m05lDS30pa", + "x": 87, + "y": 507.5, + "width": 59, + "height": 24, + "angle": 0, + "strokeColor": "#364fc7", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, - "strokeStyle": "solid", + "strokeStyle": "dashed", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 114654356, + "version": 20, + "versionNonce": 2084380588, + "isDeleted": false, + "boundElementIds": null, + "text": "e.g.2", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 + }, + { + "id": "OvR4R63bV_1xK4bZZV7P2", + "type": "text", + "x": 184, + "y": 253.5, + "width": 300, + "height": 26, "angle": 0, - "x": 533.6250000000002, - "y": 1151.375, - "strokeColor": "#d9480f", + "strokeColor": "#495057", "backgroundColor": "transparent", - "width": 40, - "height": 32, - "seed": 1266656650, + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, "groupIds": [], "strokeSharpness": "sharp", - "boundElementIds": [], + "seed": 1569118868, + "version": 130, + "versionNonce": 1502933932, + "isDeleted": false, + "boundElementIds": null, + "text": "由于色块相同的格子可以自由交换", "fontSize": 20, - "fontFamily": 1, - "text": "窗口", - "baseline": 23, + "fontFamily": 3, "textAlign": "left", - "verticalAlign": "top" + "verticalAlign": "top", + "baseline": 21 } ], "appState": { - "viewBackgroundColor": "#ffffff", - "gridSize": null + "gridSize": null, + "viewBackgroundColor": "#ffffff" } } \ No newline at end of file diff --git a/assets/1202_0.png b/assets/1202_0.png new file mode 100644 index 0000000..7e4ec47 Binary files /dev/null and b/assets/1202_0.png differ diff --git a/assets/1202_1.png b/assets/1202_1.png new file mode 100644 index 0000000..5624ad0 Binary files /dev/null and b/assets/1202_1.png differ diff --git a/assets/1456_0.png b/assets/1456_0.png new file mode 100644 index 0000000..3df9b88 Binary files /dev/null and b/assets/1456_0.png differ diff --git a/assets/189_0.png b/assets/189_0.png new file mode 100644 index 0000000..7629a23 Binary files /dev/null and b/assets/189_0.png differ diff --git a/assets/189_1.png b/assets/189_1.png new file mode 100644 index 0000000..a963476 Binary files /dev/null and b/assets/189_1.png differ diff --git a/assets/189_2.png b/assets/189_2.png new file mode 100644 index 0000000..1d15313 Binary files /dev/null and b/assets/189_2.png differ diff --git a/assets/33_0.png b/assets/33_0.png new file mode 100644 index 0000000..931d468 Binary files /dev/null and b/assets/33_0.png differ diff --git a/assets/378_0.excalidraw b/assets/378_0.excalidraw new file mode 100644 index 0000000..1ea4be8 --- /dev/null +++ b/assets/378_0.excalidraw @@ -0,0 +1,1454 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "DKNHh0BrpH__tl5r3M_AL", + "type": "text", + "x": 643, + "y": 240.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1705238440, + "version": 72, + "versionNonce": 426689240, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "COcAP70RvJjnh-EJFlWrY", + "type": "text", + "x": 569, + "y": 265.5, + "width": 35, + "height": 24, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 140094120, + "version": 103, + "versionNonce": 200636072, + "isDeleted": false, + "boundElementIds": null, + "text": "k=5", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 19 + }, + { + "id": "MQwjVigH5ZZtwFkCEC2ul", + "type": "text", + "x": 491, + "y": 366.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1793894360, + "version": 60, + "versionNonce": 91513256, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "rEBTz8OtS9Hxe7UHa2QSh", + "type": "ellipse", + "x": 519, + "y": 365, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 62516440, + "version": 63, + "versionNonce": 516549800, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "mEZP7ITY0rHdzQ5SmnCMr", + "type": "ellipse", + "x": 525, + "y": 392, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2090242520, + "version": 92, + "versionNonce": 724965288, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "KPj6WdhU5B-Ux_ZSLc7nW", + "type": "ellipse", + "x": 522, + "y": 416, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1553372888, + "version": 110, + "versionNonce": 1323623080, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "h7NvS8feyuuWXUAOzbciz", + "type": "rectangle", + "x": 741, + "y": 383, + "width": 189, + "height": 33, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 676199384, + "version": 112, + "versionNonce": 1216499112, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "p-SEbbCxcj8NUGlNgdrwm", + "type": "ellipse", + "x": 752, + "y": 386, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 835764440, + "version": 139, + "versionNonce": 557471912, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "0_9IvaPoM2TNndZGy7wN7", + "type": "text", + "x": 761, + "y": 386.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1756554712, + "version": 53, + "versionNonce": 1555628968, + "isDeleted": false, + "boundElementIds": null, + "text": "1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "TZ8CbNRWOAP2PdxIhFoPq", + "type": "text", + "x": 494, + "y": 482.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1163618728, + "version": 88, + "versionNonce": 1604805848, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "F9InYUQvwXyy5CPMzjhQa", + "type": "ellipse", + "x": 567, + "y": 480, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1552938152, + "version": 117, + "versionNonce": 1813318104, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "tqqp1-QFhoUZSrZsFNiAi", + "type": "ellipse", + "x": 528, + "y": 508, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1392189352, + "version": 120, + "versionNonce": 1166413528, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "cMkoKy-zgtOkEerjDWK4D", + "type": "ellipse", + "x": 525, + "y": 532, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1221126824, + "version": 138, + "versionNonce": 881751000, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "LWk9uiDNPa3RM_RaeS1-A", + "type": "rectangle", + "x": 744, + "y": 499, + "width": 189, + "height": 33, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2024101288, + "version": 140, + "versionNonce": 1329739992, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "nXFR9nLOKxL6Dc9XnXa1b", + "type": "ellipse", + "x": 755, + "y": 502, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1740398760, + "version": 169, + "versionNonce": 1228234200, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "CNjh6CzCHZEaHsmsHnC3W", + "type": "text", + "x": 764, + "y": 502.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 364514216, + "version": 83, + "versionNonce": 1132192472, + "isDeleted": false, + "boundElementIds": null, + "text": "1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "4jYXtLtG_9AjUgxcvgFFj", + "type": "ellipse", + "x": 793, + "y": 503, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 751457960, + "version": 175, + "versionNonce": 480888792, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "8tnW3ELsgx_4dba2iMfb5", + "type": "text", + "x": 802, + "y": 503.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 832127400, + "version": 92, + "versionNonce": 1087573208, + "isDeleted": false, + "boundElementIds": null, + "text": "5", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "kNCk6FNniArSr5d-ZzV4b", + "type": "text", + "x": 497, + "y": 597.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2007906472, + "version": 123, + "versionNonce": 1273824728, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "wWOu1oIjWUsRBgJ4srUPF", + "type": "ellipse", + "x": 570, + "y": 595, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2041635752, + "version": 152, + "versionNonce": 1627294424, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "2E5K6fqYws7FSoTZfK-U_", + "type": "ellipse", + "x": 530, + "y": 620, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 472264360, + "version": 211, + "versionNonce": 1133998040, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "jmMkfttBszZGAC9WNsXQq", + "type": "ellipse", + "x": 528, + "y": 647, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2008684968, + "version": 173, + "versionNonce": 197899480, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "QTPHt-r_kdF6LiLQ0wSAq", + "type": "rectangle", + "x": 747, + "y": 614, + "width": 189, + "height": 33, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 798532776, + "version": 175, + "versionNonce": 791632344, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "uR7_QPHJj2taDLr5li-9D", + "type": "ellipse", + "x": 758, + "y": 617, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 560844712, + "version": 204, + "versionNonce": 1356226264, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "aQgZBheZvHSLr7HjqaMPo", + "type": "text", + "x": 767, + "y": 617.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 358980264, + "version": 118, + "versionNonce": 290767832, + "isDeleted": false, + "boundElementIds": null, + "text": "1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "oAwX_utaMqkIcgVS9MvtK", + "type": "ellipse", + "x": 796, + "y": 618, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1848378792, + "version": 210, + "versionNonce": 1589545176, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "7IWNB6IHnSxNeonuFzVWv", + "type": "text", + "x": 805, + "y": 618.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1491931304, + "version": 127, + "versionNonce": 1151839704, + "isDeleted": false, + "boundElementIds": null, + "text": "5", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "M_9-2BgMkKHUVgi8bzO81", + "type": "ellipse", + "x": 834, + "y": 617, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2102705064, + "version": 231, + "versionNonce": 1009005272, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "tYs9PhohqnqAeU_-gL6FY", + "type": "text", + "x": 837.5, + "y": 617.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 764348072, + "version": 12, + "versionNonce": 2076710872, + "isDeleted": false, + "boundElementIds": null, + "text": "10", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "HV880PwNtT9UJ-DYJ_lmw", + "type": "text", + "x": 493, + "y": 703.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1172885416, + "version": 158, + "versionNonce": 93019864, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "IbXOpRHtTJYaC9khFUn48", + "type": "ellipse", + "x": 566, + "y": 701, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1921030824, + "version": 187, + "versionNonce": 1734984664, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "DAycPAICPcnQTHWV46hXR", + "type": "ellipse", + "x": 573, + "y": 727, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1877411240, + "version": 270, + "versionNonce": 708020440, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "nGrqkadrrdJPnsG156xIV", + "type": "ellipse", + "x": 524, + "y": 753, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1799884968, + "version": 208, + "versionNonce": 1501343192, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "1Mp0lHsdBUvjSGeM5thze", + "type": "rectangle", + "x": 743, + "y": 720, + "width": 189, + "height": 33, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 206551976, + "version": 210, + "versionNonce": 1851339480, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "5AjQeHgjCr4Dp28AhtZIc", + "type": "ellipse", + "x": 754, + "y": 723, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 623511208, + "version": 239, + "versionNonce": 526194648, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "0RiRSsPDYqdiWh64Rmuoo", + "type": "text", + "x": 763, + "y": 723.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1652748712, + "version": 153, + "versionNonce": 815553752, + "isDeleted": false, + "boundElementIds": null, + "text": "1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "I9OOfRS6CPND1w7h_hnPJ", + "type": "ellipse", + "x": 792, + "y": 724, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2072411304, + "version": 245, + "versionNonce": 1135280600, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "5eUqJ8cJGxyPmDqRW4bQK", + "type": "text", + "x": 801, + "y": 724.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1642112936, + "version": 162, + "versionNonce": 664602328, + "isDeleted": false, + "boundElementIds": null, + "text": "5", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "whh99jDR_ar1ptnxb-214", + "type": "ellipse", + "x": 830, + "y": 723, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1908241064, + "version": 268, + "versionNonce": 688286680, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "7q0XD60OQtwrHL8Xal2w1", + "type": "text", + "x": 833.5, + "y": 723.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 566812072, + "version": 49, + "versionNonce": 1643851992, + "isDeleted": false, + "boundElementIds": null, + "text": "10", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "uoU45fUW_Kf-65PLe-i3a", + "type": "ellipse", + "x": 867, + "y": 724, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 858712232, + "version": 288, + "versionNonce": 168777176, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "R_aJ4hnbz8eeYdbhPAi1-", + "type": "text", + "x": 870.5, + "y": 724.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1637585832, + "version": 73, + "versionNonce": 1180097240, + "isDeleted": false, + "boundElementIds": null, + "text": "12", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "A689gkWJlvbjY_TBPMU8r", + "type": "text", + "x": 493, + "y": 804.5, + "width": 176, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 427738328, + "version": 179, + "versionNonce": 856745944, + "isDeleted": false, + "boundElementIds": null, + "text": " [[1, 5, 11],\n [10, 12, 13],\n [12, 13, 15]]", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 67 + }, + { + "id": "cL0VyBx4O-hp_ODdekk_o", + "type": "ellipse", + "x": 566, + "y": 802, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 362021544, + "version": 208, + "versionNonce": 1890853288, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "xEwfh4LaErBv9nv7g8kAO", + "type": "ellipse", + "x": 573, + "y": 828, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 602309800, + "version": 291, + "versionNonce": 1029057752, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "c0CJdr527qm2gzH7otGv7", + "type": "ellipse", + "x": 524, + "y": 854, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1078562776, + "version": 231, + "versionNonce": 1857681832, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "4BpMBWGd0oZF90fiYh09k", + "type": "rectangle", + "x": 743, + "y": 821, + "width": 189, + "height": 33, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 816164008, + "version": 231, + "versionNonce": 950718936, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "XHE78VCYbjY3uwmbn7O_5", + "type": "ellipse", + "x": 750, + "y": 823, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 626235608, + "version": 275, + "versionNonce": 54491096, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "hbZqwIMEWm-PEMEldu1x4", + "type": "text", + "x": 759, + "y": 823.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 370851288, + "version": 189, + "versionNonce": 1819709864, + "isDeleted": false, + "boundElementIds": null, + "text": "1", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "bthDXQPTLG_ZkPlmsY3Ls", + "type": "ellipse", + "x": 788, + "y": 824, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "#15aabf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 751332824, + "version": 281, + "versionNonce": 691191000, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "Gam-DIL2hUofnS61ZfZQm", + "type": "text", + "x": 797, + "y": 824.5, + "width": 12, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 98356904, + "version": 198, + "versionNonce": 1174805672, + "isDeleted": false, + "boundElementIds": null, + "text": "5", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "m5geP-WsX9mace09od74-", + "type": "ellipse", + "x": 823, + "y": 822, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1524705240, + "version": 296, + "versionNonce": 440426200, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "1SjW5wJQXxNkm4ks0c5G6", + "type": "text", + "x": 826.5, + "y": 822.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 18771160, + "version": 77, + "versionNonce": 1872468648, + "isDeleted": false, + "boundElementIds": null, + "text": "10", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "X_JSQpyiZI5_-hoZXwDCC", + "type": "ellipse", + "x": 860, + "y": 823, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#5c940d", + "backgroundColor": "#82c91e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1042301912, + "version": 316, + "versionNonce": 494846936, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "7pMU3mgIbMKIvzZ95nmle", + "type": "text", + "x": 863.5, + "y": 823.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1707793368, + "version": 101, + "versionNonce": 295830952, + "isDeleted": false, + "boundElementIds": null, + "text": "12", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + }, + { + "id": "zcV7bM2hpQcMwDOzniPz3", + "type": "ellipse", + "x": 895, + "y": 822, + "width": 30, + "height": 25, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 50, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 2019934936, + "version": 299, + "versionNonce": 147893464, + "isDeleted": false, + "boundElementIds": null + }, + { + "id": "YYBUwKSzbxVujiZgKIMma", + "type": "text", + "x": 898.5, + "y": 822.5, + "width": 23, + "height": 24, + "angle": 0, + "strokeColor": "#495057", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 200596440, + "version": 23, + "versionNonce": 729754792, + "isDeleted": false, + "boundElementIds": null, + "text": "12", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 19 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/assets/378_0.png b/assets/378_0.png new file mode 100644 index 0000000..b4619f1 Binary files /dev/null and b/assets/378_0.png differ diff --git a/assets/5210_0.excalidraw b/assets/5210_0.excalidraw new file mode 100644 index 0000000..d106560 --- /dev/null +++ b/assets/5210_0.excalidraw @@ -0,0 +1,428 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "rm3deO0uNVN_4d0C8BMXo", + "type": "rectangle", + "x": 566, + "y": 187.79127997160316, + "width": 135.19501164713662, + "height": 112.79126685989687, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1581409644, + "version": 101, + "versionNonce": 323840084, + "isDeleted": false, + "boundElementIds": [ + "_PahqQ3MPHbJZGP4o7EI4", + "Zdj9xJJR5iOOBBt8XX_31", + "O1eADCqD99jWoXEISG8az", + "oS5EoxpRcdxtQaPFqgb0C" + ] + }, + { + "id": "6xAmqFZEpWViR2LSa9Jdx", + "type": "line", + "x": 567.6797042146732, + "y": 188, + "width": 133.64992579974077, + "height": 111.24618101250095, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 707450860, + "version": 64, + "versionNonce": 75492564, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 133.64992579974077, + 111.24618101250095 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "UmD9_6oyxNSW6yuGZY8IB", + "type": "ellipse", + "x": 608, + "y": 122, + "width": 28, + "height": 30, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1969289836, + "version": 68, + "versionNonce": 925041772, + "isDeleted": false, + "boundElementIds": [ + "oS5EoxpRcdxtQaPFqgb0C", + "gzSh0gWqK9jTyhyJJwiE4" + ] + }, + { + "id": "gzSh0gWqK9jTyhyJJwiE4", + "type": "arrow", + "x": 627.0116330887658, + "y": 162.49345072070932, + "width": 121.98836691123415, + "height": 92.50654927929068, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1789840620, + "version": 245, + "versionNonce": 63883348, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 8.988366911234152, + 27.50654927929068 + ], + [ + 70.98836691123415, + 84.50654927929068 + ], + [ + 121.98836691123415, + 92.50654927929068 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "focus": 0.22374790285322452, + "gap": 11.020766037800525, + "elementId": "UmD9_6oyxNSW6yuGZY8IB" + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "VjksbJbEqvSaZ9W-D7hk_", + "type": "rectangle", + "x": 863, + "y": 184.79127997160316, + "width": 135.19501164713662, + "height": 112.79126685989687, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1805627476, + "version": 353, + "versionNonce": 886219372, + "isDeleted": false, + "boundElementIds": [ + "_PahqQ3MPHbJZGP4o7EI4", + "Zdj9xJJR5iOOBBt8XX_31", + "O1eADCqD99jWoXEISG8az", + "oS5EoxpRcdxtQaPFqgb0C" + ] + }, + { + "id": "3nMCmci-caTivXqYkNBXC", + "type": "line", + "x": 864.6797042146732, + "y": 185, + "width": 133.64992579974077, + "height": 111.24618101250095, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1315866068, + "version": 316, + "versionNonce": 821037652, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 133.64992579974077, + 111.24618101250095 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "IVIPKz7qs2jUwxj43QqBc", + "type": "ellipse", + "x": 1037, + "y": 220, + "width": 28, + "height": 30, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1808182100, + "version": 382, + "versionNonce": 448734420, + "isDeleted": false, + "boundElementIds": [ + "oS5EoxpRcdxtQaPFqgb0C", + "7qVCAzvjoHRuJ6dolYlZl", + "cMta3VYfFHdO_AJQPg8Z0" + ] + }, + { + "id": "cMta3VYfFHdO_AJQPg8Z0", + "type": "arrow", + "x": 1027.008433951235, + "y": 237.10583353481303, + "width": 57.00843395123502, + "height": 1.10583353481303, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1174282452, + "version": 98, + "versionNonce": 1339114092, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + -57.00843395123502, + -1.10583353481303 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "IVIPKz7qs2jUwxj43QqBc", + "focus": -0.17138625905684743, + "gap": 10.076610005187154 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "Yct9eVL6YJSR-t_WtPEl0", + "type": "rectangle", + "x": 1231, + "y": 176.79127997160316, + "width": 135.19501164713662, + "height": 112.79126685989687, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1729114732, + "version": 423, + "versionNonce": 211332332, + "isDeleted": false, + "boundElementIds": [ + "_PahqQ3MPHbJZGP4o7EI4", + "Zdj9xJJR5iOOBBt8XX_31", + "O1eADCqD99jWoXEISG8az", + "oS5EoxpRcdxtQaPFqgb0C" + ] + }, + { + "id": "QADKFk_tZI5W9pAoTNYJM", + "type": "line", + "x": 1232.6797042146732, + "y": 177, + "width": 133.64992579974077, + "height": 111.24618101250095, + "angle": 0, + "strokeColor": "#0b7285", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1226941780, + "version": 387, + "versionNonce": 675669972, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 133.64992579974077, + 111.24618101250095 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "a2dtgBfKdPQaTPZ20S4Bx", + "type": "ellipse", + "x": 1154, + "y": 216, + "width": 28, + "height": 30, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 1834151532, + "version": 531, + "versionNonce": 1476412524, + "isDeleted": false, + "boundElementIds": [ + "oS5EoxpRcdxtQaPFqgb0C", + "7qVCAzvjoHRuJ6dolYlZl", + "-z8K51ZOL-o_xH1dZWVUp", + "3dJJp-spOfCkGq9Y680IY" + ] + }, + { + "id": "3dJJp-spOfCkGq9Y680IY", + "type": "arrow", + "x": 1191.7718647013971, + "y": 235.5616527134353, + "width": 143.22813529860287, + "height": 88.43834728656469, + "angle": 0, + "strokeColor": "#d9480f", + "backgroundColor": "#fd7e14", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1086038380, + "version": 196, + "versionNonce": 920978132, + "isDeleted": false, + "boundElementIds": null, + "points": [ + [ + 0, + 0 + ], + [ + 70.22813529860287, + 15.438347286564692 + ], + [ + 143.22813529860287, + 88.43834728656469 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "a2dtgBfKdPQaTPZ20S4Bx", + "focus": -0.043373062899233546, + "gap": 10.171645790728416 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + } +} \ No newline at end of file diff --git a/assets/5210_0.png b/assets/5210_0.png new file mode 100644 index 0000000..10d0036 Binary files /dev/null and b/assets/5210_0.png differ diff --git a/assets/821_0.excalidraw b/assets/821_0.excalidraw deleted file mode 100644 index 80c203e..0000000 --- a/assets/821_0.excalidraw +++ /dev/null @@ -1,3335 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "id": "KKdqwy_VPgyTkz34zBEGo", - "type": "rectangle", - "x": 182.62500000000026, - "y": 714.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1770538122, - "version": 54, - "versionNonce": 1075938326, - "isDeleted": false, - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] - }, - { - "id": "EwqYu_GPDNVAlhmYrLvzT", - "type": "text", - "x": 199.12500000000026, - "y": 717.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1977819978, - "version": 21, - "versionNonce": 667618902, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "IaDXhKlbNNtaQ1rKX5C5T", - "type": "rectangle", - "x": 223.62500000000026, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1492396554, - "version": 70, - "versionNonce": 2135085974, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "qKO5U44OQlQ54t6CUQlzW", - "type": "text", - "x": 237.12500000000026, - "y": 716.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 699816138, - "version": 43, - "versionNonce": 907014358, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "DjuhuUWv-QjRXTfO_VS4a", - "type": "rectangle", - "x": 264.6250000000002, - "y": 714.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1740943242, - "version": 87, - "versionNonce": 1741121046, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "NmqJVTLIoW956-00f71Ld", - "type": "text", - "x": 278.6250000000002, - "y": 717.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1733963338, - "version": 60, - "versionNonce": 1969107798, - "isDeleted": false, - "boundElementIds": null, - "text": "v", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "GNkaf5bm60rpvBI61hY_7", - "type": "rectangle", - "x": 305.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1028773130, - "version": 115, - "versionNonce": 1495881878, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "WsaXEICx6kmfHyzIdGx10", - "type": "text", - "x": 319.1250000000002, - "y": 716.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 723952586, - "version": 93, - "versionNonce": 1874391114, - "isDeleted": false, - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "r7L9sq-4Yrgu_yBHVsPnS", - "type": "rectangle", - "x": 346.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 183736970, - "version": 91, - "versionNonce": 59812630, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "KWYP6qv_nGx66lwLUiuBI", - "type": "text", - "x": 363.1250000000002, - "y": 717.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 997439818, - "version": 60, - "versionNonce": 834066518, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "BRt2-bSED06H22BKVgAsN", - "type": "rectangle", - "x": 387.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 201457674, - "version": 118, - "versionNonce": 757423510, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "F0Dvm919YPjVsL11AKYjH", - "type": "text", - "x": 401.1250000000002, - "y": 716.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 681144010, - "version": 91, - "versionNonce": 1527855830, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "mXV62LF6tpn-k_D1Tmegn", - "type": "rectangle", - "x": 428.6250000000002, - "y": 714.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 97846666, - "version": 135, - "versionNonce": 839872534, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "__nUIT-TeqhwspXyzyeQa", - "type": "text", - "x": 443.1250000000002, - "y": 717.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1290781770, - "version": 109, - "versionNonce": 236256598, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "duJM8ScoT44M1MO5BOfj8", - "type": "rectangle", - "x": 469.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1204071178, - "version": 157, - "versionNonce": 74900118, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "0txb_TgKH-d52qyOIiO9Z", - "type": "text", - "x": 483.1250000000002, - "y": 716.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1288616394, - "version": 130, - "versionNonce": 938090454, - "isDeleted": false, - "boundElementIds": null, - "text": "t", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "3xx_JCaQXvgwepEEFv35-", - "type": "rectangle", - "x": 509.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 724103306, - "version": 119, - "versionNonce": 746829078, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "njKXiOyi7Unc3jC4jh8Vn", - "type": "text", - "x": 523.6250000000002, - "y": 716.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 378425162, - "version": 92, - "versionNonce": 465085014, - "isDeleted": false, - "boundElementIds": null, - "text": "c", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "kTee0vEf2NmC58ex0Gb_p", - "type": "rectangle", - "x": 550.6250000000002, - "y": 712.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 324654602, - "version": 144, - "versionNonce": 1214113686, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "ZrGYrMAKAmQYlUXAnRBsR", - "type": "text", - "x": 564.1250000000002, - "y": 715.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1652982986, - "version": 120, - "versionNonce": 1386775766, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "KZewDCBq0uyplpOPkghum", - "type": "rectangle", - "x": 591.6250000000002, - "y": 713.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1840208778, - "version": 161, - "versionNonce": 204306966, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "5AH3WttF1AIsmjonIgU3d", - "type": "text", - "x": 606.1250000000002, - "y": 716.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 856644170, - "version": 138, - "versionNonce": 1273087830, - "isDeleted": false, - "boundElementIds": null, - "text": "d", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "elCnmUAVJlKIxbMq3bkSJ", - "type": "rectangle", - "x": 632.6250000000002, - "y": 712.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 830570762, - "version": 189, - "versionNonce": 1109027990, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "FXA_8pdwNM9I94dJ-xZgK", - "type": "text", - "x": 646.1250000000002, - "y": 715.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1417727946, - "version": 165, - "versionNonce": 1284270550, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "IVOsfFSVFzUZZHOQ0ZwOc", - "type": "draw", - "x": 173.62500000000026, - "y": 699.875, - "width": 41, - "height": 75, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1613252234, - "version": 129, - "versionNonce": 1246543638, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "omtMrHReH8O_odiKk5gub", - "type": "draw", - "x": 320.6250000000002, - "y": 695.875, - "width": 37, - "height": 80, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1563616586, - "version": 163, - "versionNonce": 1875930198, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "PteQr8wSU7Cy-mqz0VqrG", - "type": "text", - "x": 238.62500000000026, - "y": 669.375, - "width": 40, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 83602442, - "version": 75, - "versionNonce": 451703190, - "isDeleted": false, - "boundElementIds": null, - "text": "窗口", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 23 - }, - { - "id": "PxaqcV7b7MJX1czfR5_mZ", - "type": "rectangle", - "x": 183.62500000000023, - "y": 862.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 243236746, - "version": 80, - "versionNonce": 2011035926, - "isDeleted": false, - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] - }, - { - "id": "_WzEpmBHISv7yj965EEYD", - "type": "text", - "x": 200.12500000000023, - "y": 865.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 238747210, - "version": 47, - "versionNonce": 1169318742, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "kZEiySGQX840ua_GheJ39", - "type": "rectangle", - "x": 224.62500000000023, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1872274698, - "version": 96, - "versionNonce": 1870104726, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "qtR4sSsFesijwGj3J81Up", - "type": "text", - "x": 238.12500000000023, - "y": 864.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 202601418, - "version": 69, - "versionNonce": 132515286, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "OUG8XjO4qwwMtXewT6v4d", - "type": "rectangle", - "x": 265.6250000000002, - "y": 862.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1439066762, - "version": 113, - "versionNonce": 538106646, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "69JCI3PLMLWoxoTyx8BZg", - "type": "text", - "x": 279.6250000000002, - "y": 865.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1131186506, - "version": 86, - "versionNonce": 1584597078, - "isDeleted": false, - "boundElementIds": null, - "text": "v", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "N0hkKlHGFeUF6rp-5Yr-W", - "type": "rectangle", - "x": 306.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1012977674, - "version": 141, - "versionNonce": 1390120342, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "Ci0r2SUeU0F1PqUxUQoBD", - "type": "text", - "x": 320.1250000000002, - "y": 864.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 77479626, - "version": 119, - "versionNonce": 2011843402, - "isDeleted": false, - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "2EyKM9FOLjIFowbQjk4Vh", - "type": "rectangle", - "x": 347.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 683660682, - "version": 117, - "versionNonce": 603562006, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "powVOvUZbWZ2P4vnpneql", - "type": "text", - "x": 364.1250000000002, - "y": 865.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1778422858, - "version": 86, - "versionNonce": 590949718, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "X8SEqiW2zGkRh-6j58f6x", - "type": "rectangle", - "x": 388.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 708541194, - "version": 144, - "versionNonce": 1167397526, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "h8OxOyXNYX6jtZp8YcxBt", - "type": "text", - "x": 402.1250000000002, - "y": 864.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1475054026, - "version": 117, - "versionNonce": 365055958, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "GYTj4i2kfeZLBsEfwTBBz", - "type": "rectangle", - "x": 429.6250000000002, - "y": 862.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1512816778, - "version": 161, - "versionNonce": 2144724246, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "DaWA6SJ4p7Fjsv5wVrr5h", - "type": "text", - "x": 444.1250000000002, - "y": 865.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2092375882, - "version": 135, - "versionNonce": 625267286, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "i3er1CWXJNFbQ-2qtpJiX", - "type": "rectangle", - "x": 470.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1541973514, - "version": 183, - "versionNonce": 820254614, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "IC7tIWlRv9Ru0B8LiYzWM", - "type": "text", - "x": 484.1250000000002, - "y": 864.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1354454218, - "version": 156, - "versionNonce": 719893718, - "isDeleted": false, - "boundElementIds": null, - "text": "t", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "EJPaI1t8NQZcG-LePl2cG", - "type": "rectangle", - "x": 510.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1556753290, - "version": 145, - "versionNonce": 1290250774, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "omYqp6IfJz9_PBYgGADI0", - "type": "text", - "x": 524.6250000000002, - "y": 864.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 374352458, - "version": 118, - "versionNonce": 1440085846, - "isDeleted": false, - "boundElementIds": null, - "text": "c", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "_0rPCyKPyLuC-AJ_nHrD_", - "type": "rectangle", - "x": 551.6250000000002, - "y": 860.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 338186506, - "version": 170, - "versionNonce": 1577622678, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "X_duYtwo4rpv-KH5N20cq", - "type": "text", - "x": 565.1250000000002, - "y": 863.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1506648010, - "version": 146, - "versionNonce": 724867542, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "NcP5xCCjSLtZvQ5gvSWr8", - "type": "rectangle", - "x": 592.6250000000002, - "y": 861.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1130043018, - "version": 187, - "versionNonce": 74379030, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "c4DfNNBQYMGvKfxcoXTm9", - "type": "text", - "x": 607.1250000000002, - "y": 864.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1904981322, - "version": 164, - "versionNonce": 103586902, - "isDeleted": false, - "boundElementIds": null, - "text": "d", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "Qp93ae_rbQTIiRnNQpv6n", - "type": "rectangle", - "x": 633.6250000000002, - "y": 860.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 901413898, - "version": 215, - "versionNonce": 1984078230, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "Bv09KHW8A5R3Ge-ND_6Bs", - "type": "text", - "x": 647.1250000000002, - "y": 863.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2111990474, - "version": 191, - "versionNonce": 400948950, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "k8pMsvosX8vmeh6Jv0_bL", - "type": "draw", - "x": 336.6250000000002, - "y": 848.875, - "width": 41, - "height": 75, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1084129674, - "version": 188, - "versionNonce": 2141959190, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "IonV8V0i_NJdX7LW3S-l1", - "type": "draw", - "x": 409.6250000000002, - "y": 846.875, - "width": 37, - "height": 80, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1764343882, - "version": 209, - "versionNonce": 1737015638, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "9Ifc1xJmmqGjli-3KbH39", - "type": "text", - "x": 347.6250000000002, - "y": 822.375, - "width": 40, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1130309386, - "version": 139, - "versionNonce": 47326870, - "isDeleted": false, - "boundElementIds": null, - "text": "窗口", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 23 - }, - { - "id": "5BrQt0l74VbilKH-h2d99", - "type": "rectangle", - "x": 179.62500000000023, - "y": 1026.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 635793558, - "version": 134, - "versionNonce": 948181194, - "isDeleted": false, - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] - }, - { - "id": "wUkHZ0ZNjtHT3X_GRlzmJ", - "type": "text", - "x": 196.12500000000023, - "y": 1029.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 139914710, - "version": 101, - "versionNonce": 2134377098, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "X_J8VnDAXG03-RkMpCz4U", - "type": "rectangle", - "x": 220.62500000000023, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 841401110, - "version": 150, - "versionNonce": 2062229834, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "Fi10FSm59UzXA6MVKhl-6", - "type": "text", - "x": 234.12500000000023, - "y": 1028.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1439297622, - "version": 123, - "versionNonce": 944531466, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "eWLHvdIz0qIckz6uJ1z-N", - "type": "rectangle", - "x": 261.6250000000002, - "y": 1026.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 253064598, - "version": 167, - "versionNonce": 794220234, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "w6lfuAbqssM5k5_bsddsF", - "type": "text", - "x": 275.6250000000002, - "y": 1029.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 926831318, - "version": 140, - "versionNonce": 547712394, - "isDeleted": false, - "boundElementIds": null, - "text": "v", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "1ENSsBld9kz-J3TVZ7q09", - "type": "rectangle", - "x": 302.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 953780246, - "version": 195, - "versionNonce": 24325194, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "y8auOFbLmCWyYQYvmNjtI", - "type": "text", - "x": 316.1250000000002, - "y": 1028.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1675367766, - "version": 173, - "versionNonce": 335425750, - "isDeleted": false, - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "GzY58Lm2PMYp2Ad1UrP6M", - "type": "rectangle", - "x": 343.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1100675734, - "version": 171, - "versionNonce": 1972904394, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "NR8xV9LO2XllrLIW68J_Y", - "type": "text", - "x": 360.1250000000002, - "y": 1029.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1758148566, - "version": 140, - "versionNonce": 1183144074, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "P2XAqHsrVCxRA_89dXZks", - "type": "rectangle", - "x": 384.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1367461142, - "version": 198, - "versionNonce": 1511896906, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "CDDOvZ6BNPGtfgqXYcjAN", - "type": "text", - "x": 398.1250000000002, - "y": 1028.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 691255894, - "version": 171, - "versionNonce": 12336650, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "PenDHhw0GOKt6U1DUoO7L", - "type": "rectangle", - "x": 425.6250000000002, - "y": 1026.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 649461654, - "version": 215, - "versionNonce": 1197206730, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "kHQF6lPA5tc1ulktoXzCo", - "type": "text", - "x": 440.1250000000002, - "y": 1029.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1581096150, - "version": 189, - "versionNonce": 1670890378, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "r71Kekji56tvMi7DTjY3H", - "type": "rectangle", - "x": 466.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 358584854, - "version": 237, - "versionNonce": 531284554, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "B25Og6URYQqb2z5HI7gML", - "type": "text", - "x": 480.1250000000002, - "y": 1028.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 386981718, - "version": 210, - "versionNonce": 1181739274, - "isDeleted": false, - "boundElementIds": null, - "text": "t", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "I49X3tmFfTtDLLqQE6rew", - "type": "rectangle", - "x": 506.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 128353430, - "version": 199, - "versionNonce": 258095050, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "cAB7ANluullrSk0qxKP7S", - "type": "text", - "x": 520.6250000000002, - "y": 1028.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 953516502, - "version": 172, - "versionNonce": 178040458, - "isDeleted": false, - "boundElementIds": null, - "text": "c", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "2M54jA3OIEbjR0BYZHjhP", - "type": "rectangle", - "x": 547.6250000000002, - "y": 1024.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2108872470, - "version": 224, - "versionNonce": 215633226, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "5946oIgqdIWH0bWjA8VkL", - "type": "text", - "x": 561.1250000000002, - "y": 1027.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2125694038, - "version": 200, - "versionNonce": 460723210, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "FLW-PRwBBADaDQo-shAuz", - "type": "rectangle", - "x": 588.6250000000002, - "y": 1025.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 229411222, - "version": 241, - "versionNonce": 1483408074, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "KTnxzs0BB7AgoC3ljNwFD", - "type": "text", - "x": 603.1250000000002, - "y": 1028.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2043864790, - "version": 218, - "versionNonce": 1851005322, - "isDeleted": false, - "boundElementIds": null, - "text": "d", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "YmN4NwkIKiaqFVjFJxMP4", - "type": "rectangle", - "x": 629.6250000000002, - "y": 1024.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1673239574, - "version": 269, - "versionNonce": 2087475274, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "Aqd17lHIxsI_pmputge_v", - "type": "text", - "x": 643.1250000000002, - "y": 1027.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 291219798, - "version": 245, - "versionNonce": 42909450, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "hNrCwdD-5X4e5Dw_wZmxE", - "type": "draw", - "x": 409.6250000000002, - "y": 1013.875, - "width": 41, - "height": 75, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1107824278, - "version": 261, - "versionNonce": 1295404490, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "N-SGOmgK7H2LFihV59gdl", - "type": "draw", - "x": 449.6250000000002, - "y": 1009.875, - "width": 37, - "height": 80, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 41274326, - "version": 275, - "versionNonce": 1635648650, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "dGvVRC38vjx6XWDmWIlaH", - "type": "text", - "x": 411.6250000000002, - "y": 987.375, - "width": 40, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 12181782, - "version": 225, - "versionNonce": 1763763018, - "isDeleted": false, - "boundElementIds": null, - "text": "窗口", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 23 - }, - { - "id": "mB34gwGrk5rM53yuxzLyr", - "type": "rectangle", - "x": 182.62500000000023, - "y": 1194.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2053776714, - "version": 156, - "versionNonce": 866785686, - "isDeleted": false, - "boundElementIds": [ - "pQskk0G98FkwYFPuCC7E2", - "560tUCAMIpUxHQwSV4S_Y" - ] - }, - { - "id": "LG-ZdXxURd96qKkv7ro1m", - "type": "text", - "x": 199.12500000000023, - "y": 1197.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2034953226, - "version": 124, - "versionNonce": 1187934922, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "a8S8Yqepbwv7usYDldXnu", - "type": "rectangle", - "x": 223.62500000000023, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1441061578, - "version": 173, - "versionNonce": 698250966, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "Xdsf09lmuT-_Qnx9P9CrH", - "type": "text", - "x": 237.12500000000023, - "y": 1196.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1322447242, - "version": 146, - "versionNonce": 516524426, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "J26-pyIX0HYD1xlQ4hd8r", - "type": "rectangle", - "x": 264.6250000000002, - "y": 1194.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 391131210, - "version": 190, - "versionNonce": 865414166, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "UP_Qb11FM_d-lzIG0n7O7", - "type": "text", - "x": 278.6250000000002, - "y": 1197.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1127716618, - "version": 163, - "versionNonce": 1555286090, - "isDeleted": false, - "boundElementIds": null, - "text": "v", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "9zYhWDCiNhUz_C3zoCqsE", - "type": "rectangle", - "x": 305.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 855909834, - "version": 218, - "versionNonce": 1333999958, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "z7d16FA6ZJqa3KkRp0f88", - "type": "text", - "x": 319.1250000000002, - "y": 1196.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2144394378, - "version": 195, - "versionNonce": 1214787338, - "isDeleted": false, - "boundElementIds": [ - "27jgu510GG5uU_6lzSgwX", - "560tUCAMIpUxHQwSV4S_Y" - ], - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "_m4FN3vn-YdVY3CPtQMeq", - "type": "rectangle", - "x": 346.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1733868362, - "version": 194, - "versionNonce": 1958583958, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "1hBVeHWJhGznyM8Duucw8", - "type": "text", - "x": 363.1250000000002, - "y": 1197.875, - "width": 5, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 938918410, - "version": 163, - "versionNonce": 1986117066, - "isDeleted": false, - "boundElementIds": null, - "text": "l", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "_ouZYDv1oIs1ezbkXIu0c", - "type": "rectangle", - "x": 387.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1017508042, - "version": 221, - "versionNonce": 1744395222, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "pjbMZuUAOsReXBQXJ51CQ", - "type": "text", - "x": 401.1250000000002, - "y": 1196.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 687949706, - "version": 194, - "versionNonce": 867923082, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "C1Wbh43UuIwNVotcMD2Qy", - "type": "rectangle", - "x": 428.6250000000002, - "y": 1194.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 88327754, - "version": 238, - "versionNonce": 256602390, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "eStnVMVHRNKhYnPZW7Evl", - "type": "text", - "x": 443.1250000000002, - "y": 1197.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 440954122, - "version": 212, - "versionNonce": 1915769674, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "-pFAL7h_UuUk5aVlE4-uK", - "type": "rectangle", - "x": 469.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1569340362, - "version": 260, - "versionNonce": 1177083478, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "9_64B12ZnI8EO3iYXf8Bx", - "type": "text", - "x": 483.1250000000002, - "y": 1196.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1562653322, - "version": 233, - "versionNonce": 874207754, - "isDeleted": false, - "boundElementIds": null, - "text": "t", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "3-2OIeE_yvNx5PgSs9V_K", - "type": "rectangle", - "x": 509.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 735138122, - "version": 222, - "versionNonce": 828810134, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "sxkN7eXMrukZWq-dpujuG", - "type": "text", - "x": 523.6250000000002, - "y": 1196.875, - "width": 10, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1290573834, - "version": 195, - "versionNonce": 2021099722, - "isDeleted": false, - "boundElementIds": null, - "text": "c", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "29efoE3a0_voNNFnzFTRY", - "type": "rectangle", - "x": 550.6250000000002, - "y": 1192.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 544278218, - "version": 247, - "versionNonce": 322552022, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "MaRFg_HR-zFsR5S-Jb0-7", - "type": "text", - "x": 564.1250000000002, - "y": 1195.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1324981642, - "version": 223, - "versionNonce": 652205962, - "isDeleted": false, - "boundElementIds": null, - "text": "o", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "cQmURMAhzrOwDVXXJZiVJ", - "type": "rectangle", - "x": 591.6250000000002, - "y": 1193.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 901864522, - "version": 264, - "versionNonce": 523712022, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "EAwofWRpxWFTJ9Ezg478k", - "type": "text", - "x": 606.1250000000002, - "y": 1196.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#495057", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1386431242, - "version": 241, - "versionNonce": 2072993354, - "isDeleted": false, - "boundElementIds": null, - "text": "d", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "TGxyeiD3s5STS25IlUVNZ", - "type": "rectangle", - "x": 632.6250000000002, - "y": 1192.875, - "width": 38, - "height": 38, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 807031242, - "version": 292, - "versionNonce": 1314128726, - "isDeleted": false, - "boundElementIds": null - }, - { - "id": "2nWFMobCGXXZMiH-nCAYK", - "type": "text", - "x": 646.1250000000002, - "y": 1195.875, - "width": 11, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1363249290, - "version": 268, - "versionNonce": 1935738122, - "isDeleted": false, - "boundElementIds": null, - "text": "e", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 23 - }, - { - "id": "C7QzwoUaGbMLwOc1v2L3J", - "type": "draw", - "x": 463.6250000000002, - "y": 1181.875, - "width": 41, - "height": 75, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1080606806, - "version": 310, - "versionNonce": 1549907530, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - -8, - -2 - ], - [ - -12, - 1 - ], - [ - -14, - 19 - ], - [ - -10, - 30 - ], - [ - -13, - 33 - ], - [ - -30, - 35 - ], - [ - -8, - 43 - ], - [ - -8, - 73 - ], - [ - 8, - 73 - ], - [ - 11, - 69 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "NQG7gnYv4L9HYUiXON78R", - "type": "draw", - "x": 650.6250000000003, - "y": 1176.875, - "width": 37, - "height": 80, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "round", - "seed": 1984397718, - "version": 327, - "versionNonce": 1355415498, - "isDeleted": false, - "boundElementIds": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - -1 - ], - [ - 6, - -1 - ], - [ - 13, - 5 - ], - [ - 13, - 21 - ], - [ - 9, - 27 - ], - [ - 8, - 32 - ], - [ - 14, - 33 - ], - [ - 15, - 35 - ], - [ - 18, - 35 - ], - [ - 17, - 37 - ], - [ - 7, - 43 - ], - [ - 10, - 72 - ], - [ - 9, - 72 - ], - [ - 7, - 76 - ], - [ - -16, - 79 - ], - [ - -16, - 78 - ], - [ - -19, - 76 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null - }, - { - "id": "Q6kM0jYeyu6m05lDS30pa", - "type": "text", - "x": 533.6250000000002, - "y": 1151.375, - "width": 40, - "height": 32, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1266656650, - "version": 268, - "versionNonce": 1202264022, - "isDeleted": false, - "boundElementIds": null, - "text": "窗口", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 23 - } - ], - "appState": { - "viewBackgroundColor": "#ffffff", - "gridSize": null - } -} \ No newline at end of file diff --git a/basic/array-stack-queue/01.plus-one.md b/basic/array-stack-queue/01.plus-one.md index 1200a5d..f0c341e 100644 --- a/basic/array-stack-queue/01.plus-one.md +++ b/basic/array-stack-queue/01.plus-one.md @@ -2,6 +2,13 @@ https://leetcode-cn.com/problems/plus-one +- [66.加一](#66加一) + - [题目描述](#题目描述) + - [方法 1](#方法-1) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码 (JS/C++)](#代码-jsc) + ## 题目描述 ``` @@ -27,7 +34,9 @@ https://leetcode-cn.com/problems/plus-one 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 思路 +## 方法 1 + +### 思路 在数组上做竖式加法,用 `carry` 来表示进位,反向遍历数组即可。 @@ -40,12 +49,14 @@ https://leetcode-cn.com/problems/plus-one 如果遍历结束后 `carry` 大于 0,还需要在数组前面补一位。 -## 复杂度 +### 复杂度 + +- 时间复杂度:$O(N)$, N 为数组长度。 +- 空间复杂度:$O(1)$。 -- 时间复杂度:$O(N)$, N 为数组长度。 -- 空间复杂度:$O(1)$。 +### 代码 (JS/C++) -## 代码 +JavaScript Code ```js /** @@ -53,19 +64,41 @@ https://leetcode-cn.com/problems/plus-one * @return {number[]} */ var plusOne = function (digits) { - let carry = 1, - sum = 0, - index = digits.length - 1; - - while (carry > 0 && index > -1) { - sum = digits[index] + 1; - carry = Math.floor(sum / 10); - digits[index] = sum % 10; - index--; - } + let carry = 1, + sum = 0, + index = digits.length - 1; + + while (carry > 0 && index > -1) { + sum = digits[index] + 1; + carry = Math.floor(sum / 10); + digits[index] = sum % 10; + index--; + } + + carry && digits.unshift(carry); - carry && digits.unshift(carry); + return digits; +}; +``` + +C++ Code - return digits; +```cpp +class Solution { +public: + vector plusOne(vector& digits) { + vector res(digits.size()); + + int carry = 1; + for (int i = digits.size() - 1; i >= 0; i--) { + res[i] = (digits[i] + carry) % 10; + carry = ((digits[i] + carry) / 10) >> 0; + } + if (carry > 0) { + res.insert(res.begin(), carry); + } + + return res; + } }; ``` diff --git a/basic/array-stack-queue/02.shortest-distance-to-a-character.md b/basic/array-stack-queue/02.shortest-distance-to-a-character.md index 4360363..528f1ed 100644 --- a/basic/array-stack-queue/02.shortest-distance-to-a-character.md +++ b/basic/array-stack-queue/02.shortest-distance-to-a-character.md @@ -1,25 +1,25 @@ # 821.字符的最短距离 -https://leetcode-cn.com/problems/shortest-distance-to-a-character +https://leetcode-cn.com/problems/shortest-distance-to-a-character/ - [821.字符的最短距离](#821字符的最短距离) - [题目描述](#题目描述) - [解法 1:中心扩展法](#解法-1中心扩展法) - [思路](#思路) - [复杂度分析](#复杂度分析) - - [代码](#代码) + - [代码 (JS/C++)](#代码-jsc) - [解法 2:空间换时间](#解法-2空间换时间) - [思路](#思路-1) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码 (JS/C++)](#代码-jsc-1) - [解法 3:贪心](#解法-3贪心) - [思路](#思路-2) - [复杂度分析](#复杂度分析-2) - - [代码](#代码-2) + - [代码 (JS/C++/Python)](#代码-jscpython) - [解法 4:窗口](#解法-4窗口) - [思路](#思路-3) - [复杂度分析](#复杂度分析-3) - - [代码](#代码-3) + - [代码 (JS/C++/Python)](#代码-jscpython-1) ## 题目描述 @@ -47,18 +47,18 @@ S 和 C 中的所有字母均为小写字母。 这是最符合直觉的思路,对每个字符分别进行如下处理: -- 从当前下标出发,分别向左、右两个方向去寻找目标字符 `C`。 -- 只在一个方向找到的话,直接计算字符距离。 -- 两个方向都找到的话,取两个距离的最小值。 +- 从当前下标出发,分别向左、右两个方向去寻找目标字符 `C`。 +- 只在一个方向找到的话,直接计算字符距离。 +- 两个方向都找到的话,取两个距离的最小值。 -![](https://pic.leetcode-cn.com/1606962060-CnDiHj-file_1606962060610) +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/821_0.png) ### 复杂度分析 -- 时间复杂度:$O(N^2)$,N 为 S 的长度,两层循环。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(N^2)$,N 为 S 的长度,两层循环。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码 (JS/C++) JavaScript Code @@ -69,37 +69,74 @@ JavaScript Code * @return {number[]} */ var shortestToChar = function (S, C) { - // 结果数组 res - var res = Array(S.length).fill(0); - - for (let i = 0; i < S.length; i++) { - // 如果当前是目标字符,就什么都不用做 - if (S[i] === C) continue; - - // 定义两个指针 l, r 分别向左、右两个方向寻找目标字符 C,取最短距离 - let l = i, - r = i, - shortest = Infinity; - - while (l >= 0) { - if (S[l] === C) { - shortest = Math.min(shortest, i - l); - break; - } - l--; - } + // 结果数组 res + var res = Array(S.length).fill(0); + + for (let i = 0; i < S.length; i++) { + // 如果当前是目标字符,就什么都不用做 + if (S[i] === C) continue; + + // 定义两个指针 l, r 分别向左、右两个方向寻找目标字符 C,取最短距离 + let l = i, + r = i, + shortest = Infinity; + + while (l >= 0) { + if (S[l] === C) { + shortest = Math.min(shortest, i - l); + break; + } + l--; + } + + while (r < S.length) { + if (S[r] === C) { + shortest = Math.min(shortest, r - i); + break; + } + r++; + } + + res[i] = shortest; + } + return res; +}; +``` - while (r < S.length) { - if (S[r] === C) { - shortest = Math.min(shortest, r - i); - break; +C++ Code + +```cpp +class Solution { +public: + vector shortestToChar(string S, char C) { + vector res(S.length()); + + for (int i = 0; i < S.length(); i++) { + if (S[i] == C) continue; + + int left = i; + int right = i; + int dist = 0; + + while (left >= 0 || right <= S.length() - 1) { + if (S[left] == C) { + dist = i - left; + break; + } + if (S[right] == C) { + dist = right - i; + break; + } + + if (left > 0) left--; + if (right < S.length() - 1) right++; } - r++; + + res[i] = dist; } - res[i] = shortest; + return res; } - return res; }; ``` @@ -115,10 +152,10 @@ var shortestToChar = function (S, C) { ### 复杂度分析 -- 时间复杂度:$O(N*K)$,N 是 S 的长度,K 是字符 `C` 在字符串中出现的次数,$K <= N$。 -- 空间复杂度:$O(K)$,K 为字符 `C` 出现的次数,这是记录字符 `C` 出现下标的辅助数组消耗的空间。 +- 时间复杂度:$O(N*K)$,N 是 S 的长度,K 是字符 `C` 在字符串中出现的次数,$K <= N$。 +- 空间复杂度:$O(K)$,K 为字符 `C` 出现的次数,这是记录字符 `C` 出现下标的辅助数组消耗的空间。 -### 代码 +### 代码 (JS/C++) JavaScript Code @@ -129,34 +166,67 @@ JavaScript Code * @return {number[]} */ var shortestToChar = function (S, C) { - // 记录 C 字符在 S 字符串中出现的所有下标 - var cIndices = []; - for (let i = 0; i < S.length; i++) { - if (S[i] === C) cIndices.push(i); + // 记录 C 字符在 S 字符串中出现的所有下标 + var cIndices = []; + for (let i = 0; i < S.length; i++) { + if (S[i] === C) cIndices.push(i); + } + + // 结果数组 res + var res = Array(S.length).fill(Infinity); + + for (let i = 0; i < S.length; i++) { + // 目标字符,距离是 0 + if (S[i] === C) { + res[i] = 0; + continue; } - // 结果数组 res - var res = Array(S.length).fill(Infinity); + // 非目标字符,到下标数组中找最近的下标 + for (const cIndex of cIndices) { + const dist = Math.abs(cIndex - i); - for (let i = 0; i < S.length; i++) { - // 目标字符,距离是 0 - if (S[i] === C) { - res[i] = 0; - continue; - } + // 小小剪枝一下 + // 注:因为 cIndices 中的下标是递增的,后面的 dist 也会越来越大,可以排除 + if (dist >= res[i]) break; + + res[i] = dist; + } + } + return res; +}; +``` - // 非目标字符,到下标数组中找最近的下标 - for (const cIndex of cIndices) { - const dist = Math.abs(cIndex - i); +C++ Code - // 小小剪枝一下 - // 注:因为 cIndices 中的下标是递增的,后面的 dist 也会越来越大,可以排除 - if (dist >= res[i]) break; +```cpp +class Solution { +public: + vector shortestToChar(string S, char C) { + int n = S.length(); + vector c_indices; + // Initialize a vector of size n with default value n. + vector res(n, n); - res[i] = dist; + for (int i = 0; i < n; i++) { + if (S[i] == C) c_indices.push_back(i); + } + + for (int i = 0; i < n; i++) { + if (S[i] == C) { + res[i] = 0; + continue; + } + + for (int j = 0; j < c_indices.size(); j++) { + int dist = abs(c_indices[j] - i); + if (dist > res[i]) break; + res[i] = dist; + } } + + return res; } - return res; }; ``` @@ -185,10 +255,10 @@ var shortestToChar = function (S, C) { ### 复杂度分析 -- 时间复杂度:$O(N)$,N 是 S 的长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(N)$,N 是 S 的长度。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码 (JS/C++/Python) JavaScript Code @@ -199,29 +269,28 @@ JavaScript Code * @return {number[]} */ var shortestToChar = function (S, C) { - var res = Array(S.length); - - // 第一次遍历:从左往右 - // 找到出现在左侧的 C 字符的最后下标 - for (let i = 0; i < S.length; i++) { - if (S[i] === C) res[i] = i; - // 如果左侧没有出现 C 字符的话,用 Infinity 进行标记 - else res[i] = res[i - 1] === void 0 ? Infinity : res[i - 1]; - } - - // 第二次遍历:从右往左 - // 找出现在右侧的 C 字符的最后下标 - // 如果左侧没有出现过 C 字符,或者右侧出现的 C 字符距离更近,就更新 res[i] - for (let i = S.length - 1; i >= 0; i--) { - if (res[i] === Infinity || res[i + 1] - i < i - res[i]) - res[i] = res[i + 1]; - } - - // 计算距离 - for (let i = 0; i < res.length; i++) { - res[i] = Math.abs(res[i] - i); - } - return res; + var res = Array(S.length); + + // 第一次遍历:从左往右 + // 找到出现在左侧的 C 字符的最后下标 + for (let i = 0; i < S.length; i++) { + if (S[i] === C) res[i] = i; + // 如果左侧没有出现 C 字符的话,用 Infinity 进行标记 + else res[i] = res[i - 1] === void 0 ? Infinity : res[i - 1]; + } + + // 第二次遍历:从右往左 + // 找出现在右侧的 C 字符的最后下标 + // 如果左侧没有出现过 C 字符,或者右侧出现的 C 字符距离更近,就更新 res[i] + for (let i = S.length - 1; i >= 0; i--) { + if (res[i] === Infinity || res[i + 1] - i < i - res[i]) res[i] = res[i + 1]; + } + + // 计算距离 + for (let i = 0; i < res.length; i++) { + res[i] = Math.abs(res[i] - i); + } + return res; }; ``` @@ -236,38 +305,85 @@ JavaScript Code * @return {number[]} */ var shortestToChar = function (S, C) { - var res = Array(S.length); + var res = Array(S.length); - for (let i = 0; i < S.length; i++) { - if (S[i] === C) res[i] = 0; - // 记录距离:res[i - 1] + 1 - else res[i] = res[i - 1] === void 0 ? Infinity : res[i - 1] + 1; - } + for (let i = 0; i < S.length; i++) { + if (S[i] === C) res[i] = 0; + // 记录距离:res[i - 1] + 1 + else res[i] = res[i - 1] === void 0 ? Infinity : res[i - 1] + 1; + } - for (let i = S.length - 1; i >= 0; i--) { - // 更新距离:res[i + 1] + 1 - if (res[i] === Infinity || res[i + 1] + 1 < res[i]) - res[i] = res[i + 1] + 1; - } + for (let i = S.length - 1; i >= 0; i--) { + // 更新距离:res[i + 1] + 1 + if (res[i] === Infinity || res[i + 1] + 1 < res[i]) res[i] = res[i + 1] + 1; + } + + return res; +}; +``` + +C++ Code + +```cpp +class Solution { +public: + vector shortestToChar(string S, char C) { + int n = S.length(); + vector dist(n, n); + + for (int i = 0; i < n; i++) { + if (S[i] == C) dist[i] = 0; + else if (i > 0) dist[i] = dist[i - 1] + 1; + } + + for (int i = n - 1; i >= 0; i--) { + if (dist[i] == n + || (i < n - 1 && dist[i + 1] + 1 < dist[i])) + dist[i] = dist[i + 1] + 1; + } - return res; + return dist; + } }; ``` +Python Code + +```py +class Solution(object): + def shortestToChar(self, s, c): + """ + :type s: str + :type c: str + :rtype: List[int] + """ + n = len(s) + res = [0 if s[i] == c else None for i in range(n)] + + for i in range(1, n): + if res[i] != 0 and res[i - 1] is not None: + res[i] = res[i - 1] + 1 + + for i in range(n - 2, -1, -1): + if res[i] is None or res[i + 1] + 1 < res[i]: + res[i] = res[i + 1] + 1 + return res +``` + ## 解法 4:窗口 ### 思路 把 `C` 看成分界线,将 `S` 划分成一个个窗口。然后对每个窗口进行遍历,分别计算每个字符到窗口边界的距离最小值。 -![](https://pic.leetcode-cn.com/1606962060-WhqxbZ-file_1606962060746) +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/821_1.png) ### 复杂度分析 -- 时间复杂度:$O(N)$,N 是 S 的长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(N)$,N 是 S 的长度。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码 (JS/C++/Python) JavaScript Code @@ -278,24 +394,76 @@ JavaScript Code * @return {number[]} */ var shortestToChar = function (S, C) { - // 窗口左边界,如果没有就初始化为 Infinity - let l = S[0] === C ? 0 : Infinity, - // 窗口右边界 - r = S.indexOf(C, 1); + // 窗口左边界,如果没有就初始化为 Infinity,初始化为 S.length 也可以 + let l = S[0] === C ? 0 : Infinity, + // 窗口右边界 + r = S.indexOf(C, 1); - const res = Array(S.length); + const res = Array(S.length); - for (let i = 0; i < S.length; i++) { - // 计算字符到当前窗口左右边界的最小距离 - res[i] = Math.min(Math.abs(i - l), Math.abs(r - i)); + for (let i = 0; i < S.length; i++) { + // 计算字符到当前窗口左右边界的最小距离 + res[i] = Math.min(Math.abs(i - l), Math.abs(r - i)); - // 遍历完了当前窗口的字符后,将整个窗口右移 - if (i === r) { - l = r; - r = S.indexOf(C, l + 1); - } + // 遍历完了当前窗口的字符后,将整个窗口右移 + if (i === r) { + l = r; + r = S.indexOf(C, l + 1); } + } - return res; + return res; }; ``` + +C++ Code + +```cpp +class Solution { +public: + vector shortestToChar(string S, char C) { + int n = S.length(); + + int l = S[0] == C ? 0 : n; + int r = S.find(C, 1); + + vector dist(n); + + for (int i = 0; i < n; i++) { + dist[i] = min(abs(i - l), abs(r - i)); + if (i == r) { + l = r; + r = S.find(C, r + 1); + } + } + + return dist; + } +}; +``` + +Python Code + +```py +class Solution(object): + def shortestToChar(self, s, c): + """ + :type s: str + :type c: str + :rtype: List[int] + """ + n = len(s) + res = [0 for _ in range(n)] + + l = 0 if s[0] == c else n + r = s.find(c, 1) + + for i in range(n): + res[i] = min(abs(i - l), abs(r - i)) + if i == r: + l = r + r = s.find(c, l + 1) + return res +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/array-stack-queue/04.decode-string.md b/basic/array-stack-queue/04.decode-string.md index 263ded5..176a241 100644 --- a/basic/array-stack-queue/04.decode-string.md +++ b/basic/array-stack-queue/04.decode-string.md @@ -2,7 +2,7 @@ https://leetcode-cn.com/problems/decode-string/ -- [394.字符串解码](#394dot字符串解码) +- [394.字符串解码](#394字符串解码) - [题目描述](#题目描述) - [方法 1: 递归](#方法-1-递归) - [思路](#思路) @@ -104,6 +104,44 @@ var decodeString = function (s, i = 0) { }; ``` +C++ Code +```cpp +class Solution { +private: + int ptr_ = 0; +public: + string decodeString(string s) { + string decoded_str = ""; + string repeat_times = ""; + + int i = ptr_; + while (i < s.length()) { + if (isalpha(s[i])) { + decoded_str += s[i]; + i++; + } else if (isdigit(s[i])) { + repeat_times += s[i]; + i++; + } else if (s.compare(i, 1, "[") == 0) { + ptr_ = i + 1; + string pattern = decodeString(s); + i = ptr_; + + int times = stoi(repeat_times); + for (int t = 0; t < times; t++) { + decoded_str += pattern; + } + repeat_times = ""; + } else if (s.compare(i, 1, "]") == 0) { + ptr_ = i + 1; + return decoded_str; + } + } + return decoded_str; + } +}; +``` + ## 方法 2: 循环 + 栈 可以用递归解决的问题,也可以用循环来解决。 diff --git a/basic/array-stack-queue/05.implement-queue-using-stacks.md b/basic/array-stack-queue/05.implement-queue-using-stacks.md index bde7560..887880b 100644 --- a/basic/array-stack-queue/05.implement-queue-using-stacks.md +++ b/basic/array-stack-queue/05.implement-queue-using-stacks.md @@ -2,7 +2,7 @@ https://leetcode-cn.com/problems/implement-queue-using-stacks/ -- [232.用栈实现队列](#232dot用栈实现队列) +- [232.用栈实现队列](#232用栈实现队列) - [题目描述](#题目描述) - [方法 1](#方法-1) - [思路](#思路) @@ -11,7 +11,7 @@ https://leetcode-cn.com/problems/implement-queue-using-stacks/ - [方法 2](#方法-2) - [思路](#思路-1) - [复杂度](#复杂度-1) - - [代码](#代码-1) + - [代码(JavaScript/C++)](#代码javascriptc) ## 题目描述 @@ -47,9 +47,15 @@ queue.empty(); // 返回 false ### 思路 -由于队列是 FIFI (先进先出),而栈是 FILO (先进后出),如果要用栈来模拟队列,那么每次往队列尾端增加元素的时候,这个元素需要放在栈底,因为它是最后才会出列。 +由于队列是 FIFI (先进先出),而栈是 FILO (先进后出)。如果要用栈来模拟队列,则每次往模拟队列增加元素的时候,这个元素需要放在栈底,因为它是最后才会出列。 -方法之一是,每次往队列尾端 `push` 一个新元素时,我们都先把栈中的元素尽数清空,然后把新元素入栈,再把刚刚清出来的元素放回栈中,所以还需要一个辅助栈来暂存清出来的元素。 +方法之一是,每次需要往模拟队列尾端 `push` 一个新元素时: + +- 先把栈中的全部元素暂时取出 +- 将新元素入栈到栈底 +- 再将刚刚取出来元素重新入栈 + +因此我们还需要一个辅助栈来存暂时取出来的元素。 ### 复杂度 @@ -95,9 +101,9 @@ class MyQueue { ### 思路 -方法 1 是在元素入列的时候,就考虑好了它出列的顺序,但我们还可以在元素需要出列的时候再来考虑这个问题。这样的话: +方法 1 是在元素入列的时候,就考虑好了它出列的顺序,但我们还可以转换一下思路,在元素需要出列的时候再来考虑这个问题,这样的话: -1. 入列时直接 `push` 到模拟栈中; +1. 入列时,直接 `push` 到栈中; 2. 出列时,由于先入列的元素在栈底,需要先把其他元素弹出,依次压入辅助栈; 3. 栈底元素弹出,出列; 4. 刚才出栈的其他元素依次从辅助栈弹出,重新压入模拟栈。 @@ -116,7 +122,7 @@ class MyQueue { - 时间复杂度:入列是 $O(1)$,出列最差的情况就是每个元素都要从模拟栈中弹出,压入辅助栈,再从辅助栈中弹出,所以是 $O(n)$。 - 空间复杂度:$O(n)$,n 为队列大小。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -172,3 +178,66 @@ class MyStack { } } ``` + +C++ Code +```cpp +#include +using namespace std; + +class MyQueue { +private: + stack stack_in_; + stack stack_out_; + void pour_to_stack_out_() { + while (!stack_in_.empty()) { + int top = stack_in_.top(); + stack_in_.pop(); + stack_out_.push(top); + } + }; +public: + /** Initialize your data structure here. */ + MyQueue() { + + } + + /** Push element x to the back of queue. */ + void push(int x) { + stack_in_.push(x); + } + + /** Removes the element from in front of queue and returns that element. */ + int pop() { + if (stack_out_.empty()) { + pour_to_stack_out_(); + } + int top = stack_out_.top(); + stack_out_.pop(); + return top; + } + + /** Get the front element. */ + int peek() { + if (stack_out_.empty()) { + pour_to_stack_out_(); + } + return stack_out_.top(); + } + + /** Returns whether the queue is empty. */ + bool empty() { + return stack_in_.empty() && stack_out_.empty(); + } +}; + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue* obj = new MyQueue(); + * obj->push(x); + * int param_2 = obj->pop(); + * int param_3 = obj->peek(); + * bool param_4 = obj->empty(); + */ +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/array-stack-queue/06.max-chunks-to-make-sorted-ii.md b/basic/array-stack-queue/06.max-chunks-to-make-sorted-ii.md index 31f02d1..738ebaa 100644 --- a/basic/array-stack-queue/06.max-chunks-to-make-sorted-ii.md +++ b/basic/array-stack-queue/06.max-chunks-to-make-sorted-ii.md @@ -2,17 +2,17 @@ https://leetcode-cn.com/problems/max-chunks-to-make-sorted-ii/ -- [768. 最多能完成排序的块 II](#768dot-最多能完成排序的块-ii) +- [768. 最多能完成排序的块 II](#768-最多能完成排序的块-ii) - [题目描述](#题目描述) - [方法 1: 滑动窗口](#方法-1-滑动窗口) - [思路](#思路) - [复杂度分析](#复杂度分析) - - [代码](#代码) - - [方法 2: 单调递增栈](#方法-2-单调递增栈) + - [代码 (JS/C++)](#代码-jsc) + - [方法 2: 单调栈](#方法-2-单调栈) - [思路](#思路-1) - [图解](#图解) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码(JS/C++)](#代码jsc) ## 题目描述 @@ -65,10 +65,10 @@ Each k for which some permutation of arr[:k] is equal to sorted(arr)[:k] is wher ### 复杂度分析 -- 时间复杂度:$O(NlogN)$,N 为数组长度,数组排序时间认为是 $NlogN$,滑动窗口遍历数组时间为 $N$。 -- 空间复杂度:$O(N)$,N 为数组长度。 +- 时间复杂度:$O(NlogN)$,N 为数组长度,数组排序时间认为是 $NlogN$,滑动窗口遍历数组时间为 $N$。 +- 空间复杂度:$O(N)$,N 为数组长度。 -### 代码 +### 代码 (JS/C++) JavaScript Code @@ -78,28 +78,53 @@ JavaScript Code * @return {number} */ var maxChunksToSorted = function (arr) { - const sorted = [...arr]; - sorted.sort((a, b) => a - b); + const sorted = [...arr]; + sorted.sort((a, b) => a - b); - let count = 0, - sum1 = 0, - sum2 = 0; + let count = 0, + sum1 = 0, + sum2 = 0; - for (let i = 0; i < arr.length; i++) { - sum1 += arr[i]; - sum2 += sorted[i]; + for (let i = 0; i < arr.length; i++) { + sum1 += arr[i]; + sum2 += sorted[i]; - if (sum1 === sum2) { - count++; - sum1 = sum2 = 0; // 这行不要也可以啦 - } + if (sum1 === sum2) { + count++; + sum1 = sum2 = 0; // 这行不要也可以啦 } + } - return count; + return count; }; ``` -## 方法 2: 单调递增栈 +C++ Code + +```cpp +class Solution { +public: + int maxChunksToSorted(vector& arr) { + int n = arr.size(); + vector sorted = arr; + sort(sorted.begin(), sorted.end()); + + long int arrSum = 0; + long int sortedSum = 0; + int chunkCount = 0; + + for (int i = 0; i < n; i++) { + arrSum += arr[i]; + sortedSum += sorted[i]; + if (arrSum == sortedSum) chunkCount++; + } + + return chunkCount; + } +}; +``` + +## 方法 2: 单调栈 ### 思路 @@ -107,11 +132,11 @@ var maxChunksToSorted = function (arr) { 可以得到的一个结论是,每个分块中的数字相对于前一个分块都是递增的(因为有重复数字,所以也可能是相同),下一个分块中的所有数字都会大于等于上一个分块中的所有数字。 -- 因为题目要求能分的最多的块数,所以我们在分块的时候要尽量把块分小,这样就能分得比较多。 +- 因为题目要求能分的最多的块数,所以我们在分块的时候要尽量把块分小,这样就能分得比较多。 -- 在遍历数组的过程中,如果一个数字比之前所有分块的最大值都要大,我们就把它作为一个新的分块。 +- 在遍历数组的过程中,如果一个数字比之前所有分块的最大值都要大,我们就把它作为一个新的分块。 -- 如果数字小于之前某些分块的最大值,那这些分块都要被合成一个分块(保持栈的单调递增)。 +- 如果数字小于之前某些分块的最大值,那这些分块都要被合成一个分块(保持栈的单调递增)。 ### 图解 @@ -123,33 +148,33 @@ var maxChunksToSorted = function (arr) { ### 复杂度分析 -- 时间复杂度:$O(N)$,N 为数组长度。 -- 空间复杂度:$O(N)$,N 为数组长度,单调栈消耗的空间。 +- 时间复杂度:$O(N)$,N 为数组长度。 +- 空间复杂度:$O(N)$,N 为数组长度,单调栈消耗的空间。 -### 代码 +### 代码(JS/C++) JavaScript Code ```js class Stack { - constructor() { - this.list = []; - } - push(val) { - this.list.push(val); - } - pop() { - return this.list.pop(); - } - empty() { - return this.list.length === 0; - } - peek() { - return this.list[this.list.length - 1]; - } - size() { - return this.list.length; - } + constructor() { + this.list = []; + } + push(val) { + this.list.push(val); + } + pop() { + return this.list.pop(); + } + empty() { + return this.list.length === 0; + } + peek() { + return this.list[this.list.length - 1]; + } + size() { + return this.list.length; + } } /** @@ -157,21 +182,51 @@ class Stack { * @return {number} */ var maxChunksToSorted = function (arr) { - const stack = new Stack(); + const stack = new Stack(); - for (let i = 0; i < arr.length; i++) { - if (stack.empty() || stack.peek() <= arr[i]) { - stack.push(arr[i]); - } else { - const temp = stack.pop(); + for (let i = 0; i < arr.length; i++) { + if (stack.empty() || stack.peek() <= arr[i]) { + stack.push(arr[i]); + } else { + const temp = stack.pop(); - while (stack.peek() > arr[i]) { - stack.pop(); - } + while (stack.peek() > arr[i]) { + stack.pop(); + } - stack.push(temp); + stack.push(temp); + } + } + return stack.size(); +}; +``` + +C++ Code + +```cpp +class Solution { +public: + int maxChunksToSorted(vector& arr) { + stack blocks; + + for (int i = 0; i < arr.size(); i++) { + if (blocks.empty() || blocks.top() <= arr[i]) { + // a new chunk + blocks.push(arr[i]); + } + else { + int topNum = blocks.top(); + blocks.pop(); + + // combine chunks + while (!blocks.empty() && blocks.top() > arr[i]) { + blocks.pop(); + } + blocks.push(topNum); + } } + + return blocks.size(); } - return stack.size(); }; ``` diff --git a/basic/array-stack-queue/ext-insert-delete-getrandom-o1.md b/basic/array-stack-queue/ext-insert-delete-getrandom-o1.md index a067d17..4245e2b 100644 --- a/basic/array-stack-queue/ext-insert-delete-getrandom-o1.md +++ b/basic/array-stack-queue/ext-insert-delete-getrandom-o1.md @@ -1,6 +1,6 @@ # 380.常数时间插入、删除和获取随机元素 -https://leetcode-cn.com/problems/insert-delete-getrandom-o1/description/ +https://leetcode-cn.com/problems/insert-delete-getrandom-o1/ ## 题目描述 @@ -41,23 +41,23 @@ randomSet.getRandom(); 首先得考虑的是,用数组还是用链表来存,先来复习一下数组和链表常见操作的时间复杂度吧。 -### 数组常见操作时间复杂度分析 - -- 随机访问 -> O(1) -- 插入数值到数组 -> O(N) -- 插入数值到数组最后 -> O(1) -- 从数组删除数值 -> O(N) -- 从数组最后删除数值 -> O(1) - -### 链表常见操作时间复杂度分析 - -- 访问 -> O(N) -- 插入数值到链表 -> O(N) -- 插入数值到链表开头 -> O(1) -- 从链表删除数值 -> O(N) -- 从链表开头删除数值 -> O(1) - -很显然,链表时间复杂度为 O(N) 的访问操作并不符合我们的需求,所以我们还是选择数组来作为存储数据的容器。 +| 数组操作 | 时间复杂度 | +| ------------------ | ---------- | +| 随机访问 | $O(1)$ | +| 插入数值到数组 | $O(N)$ | +| 插入数值到数组最后 | $O(1)$ | +| 从数组删除数值 | $O(N)$ | +| 从数组最后删除数值 | $O(1)$ | + +| 链表操作 | 时间复杂度 | +| ------------------ | ---------- | +| 访问 | $O(N)$ | +| 插入数值到链表 | $O(N)$ | +| 插入数值到链表开头 | $O(1)$ | +| 从链表删除数值 | $O(N)$ | +| 从链表开头删除数值 | $O(1)$ | + +很显然,链表时间复杂度为 $O(N)$ 的访问操作并不符合我们的需求,所以我们还是选择数组来作为存储数据的容器。 ### 插入 diff --git a/basic/array-stack-queue/ext-rotate-array.md b/basic/array-stack-queue/ext-rotate-array.md new file mode 100644 index 0000000..589fde1 --- /dev/null +++ b/basic/array-stack-queue/ext-rotate-array.md @@ -0,0 +1,183 @@ +# 189. 旋转数组 + +https://leetcode-cn.com/problems/rotate-array/ + +- [189. 旋转数组](#189-旋转数组) + - [题目描述](#题目描述) + - [方法 1:使用额外空间](#方法-1使用额外空间) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法 2: 巴黎铁塔翻转再翻转](#方法-2-巴黎铁塔翻转再翻转) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) + - [方法 3: 循环移位](#方法-3-循环移位) + - [思路](#思路-2) + - [复杂度分析](#复杂度分析-2) + - [代码](#代码-2) + +## 题目描述 + +``` +给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 + +示例 1: + +输入: [1,2,3,4,5,6,7] 和 k = 3 +输出: [5,6,7,1,2,3,4] +解释: +向右旋转 1 步: [7,1,2,3,4,5,6] +向右旋转 2 步: [6,7,1,2,3,4,5] +向右旋转 3 步: [5,6,7,1,2,3,4] +示例 2: + +输入: [-1,-100,3,99] 和 k = 2 +输出: [3,99,-1,-100] +解释: +向右旋转 1 步: [99,-1,-100,3] +向右旋转 2 步: [3,99,-1,-100] +说明: + +尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +要求使用空间复杂度为 O(1) 的 原地 算法。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/rotate-array +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:使用额外空间 + +### 思路 + +先用一个额外的数组将最后的 k 位保存起来,然后将前面的元素右移 k 位,再用事先保存的 k 位元素填充数组开头。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/189_0.png) + +### 复杂度分析 + +- 时间复杂度:$O(N)$。 +- 空间复杂度:$O(k)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +var rotate = function (nums, k) { + const n = nums.length; + k %= n; + if (k === 0) return; + + const reserved = nums.slice(n - k); + + // 前 n-k 个元素右移 k 位 + for (let i = n - k - 1; i >= 0; i--) { + nums[i + k] = nums[i]; + } + + // 用原本的后 k 位填充数组开头 + for (let i = 0; i < reserved.length; i++) { + nums[i] = reserved[i]; + } +}; +``` + +## 方法 2: 巴黎铁塔翻转再翻转 + +### 思路 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/189_1.png) + +### 复杂度分析 + +- 时间复杂度:$O(N)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +var rotate = function (nums, k) { + const n = nums.length; + k %= n; + if (k === 0) return; + + reverse(nums, 0, n - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, n - 1); + + // ******************************** + // 反转某一段数组 + function reverse(arr, l, r) { + while (l < r) { + [arr[l], arr[r]] = [arr[r], arr[l]]; + l++; + r--; + } + } +}; +``` + +## 方法 3: 循环移位 + +### 思路 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/189_2.png) + +代码中 count 的来源可以去看[官方题解](https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/)的证明。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +var rotate = function (nums, k) { + const n = nums.length; + k %= n; + + const count = gcd(k, n); + for (let start = 0; start < count; start++) { + let p = start; + let prev = nums[p]; + + // 从 start 开始跳,再跳回到 start 的时候停止 + // 由于此时不一定遍历到了所有元素,所以 start++ 后再重复步骤 + do { + const next = (p + k) % n; + [prev, nums[next]] = [nums[next], prev]; + p = next; + } while (p !== start); + } + + // ********************************* + // 最大公约数 + function gcd(x, y) { + return y ? gcd(y, x % y) : x; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/binary-tree/15.sum-root-to-leaf-numbers.md b/basic/binary-tree/15.sum-root-to-leaf-numbers.md index c7d97e5..bb0b44f 100644 --- a/basic/binary-tree/15.sum-root-to-leaf-numbers.md +++ b/basic/binary-tree/15.sum-root-to-leaf-numbers.md @@ -7,11 +7,11 @@ https://leetcode-cn.com/problems/sum-root-to-leaf-numbers - [方法 1:递归](#方法-1递归) - [思路](#思路) - [复杂度](#复杂度) - - [代码](#代码) + - [代码(JavaScript/Python/C++)](#代码javascriptpythonc) - [方法 2:BFS](#方法-2bfs) - [思路](#思路-1) - [复杂度](#复杂度-1) - - [代码](#代码-1) + - [代码(JavaScript/C++)](#代码javascriptc) ## 题目描述 @@ -58,11 +58,11 @@ https://leetcode-cn.com/problems/sum-root-to-leaf-numbers ### 思路 -lucifer 的[递归小技巧](https://github.com/leetcode-pp/91alg-1/issues/32#issuecomment-643620727)练习课堂。 +lucifer 的**递归小技巧**练习课堂。 1. 定义函数功能,先不用管其具体实现。 - 我们需要一个函数,给定一个二叉树的根节点,返回根节点到各个叶子节点连成的数字的和。假设我们已经有这个函数 `F`,那问题就转化为 `F(root)` 了。 + 首先我们需要一个函数,给定一个二叉树的根节点,返回根节点到各个叶子节点连成的数字的和。假设我们已经有这个函数 `F`,那问题转化成 `F(root)`。 唔...其实问题还要复杂一丢丢,因为我们得要遍历到叶子节点的时候才能确定连成的数字,而要知道这个数字是什么,还要知道这个叶子节点的父节点,以及它父节点的父节点,...,一直到根节点,也就是说我们需要在遍历开始的时候就用一个变量来记录走过的节点。那现在我们的问题就转化成了 `F(root, num)`。 @@ -83,7 +83,7 @@ lucifer 的[递归小技巧](https://github.com/leetcode-pp/91alg-1/issues/32#is - 时间复杂度: $O(N)$,N 为二叉树节点数。 - 空间复杂度: $O(h)$,h 为二叉树高度。 -### 代码 +### 代码(JavaScript/Python/C++) JavaScript Code @@ -129,19 +129,48 @@ class Solution(object): return self.sumNumbers(root.left, num) + self.sumNumbers(root.right, num) ``` +C++ Code + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + return sumNumbers(root, 0); + } + int sumNumbers(TreeNode* root, int num) { + if (root == nullptr) return 0; + num = num * 10 + root->val; + if (root->left == nullptr && root->right == nullptr) return num; + return sumNumbers(root->left, num) + sumNumbers(root->right, num); + } + +}; +``` + ## 方法 2:BFS ### 思路 -- 层级遍历,将每一层节点的数字传给下一层,存在 `node.val` 中。 -- 如果当前节点没有子节点了,就把它的值加到结果中。 +- 对二叉树进行层级遍历,将每一层节点的数字传给下一层,存在 `node.val` 中。 +- 如果当前节点没有子节点了,就可以把它的值加到结果中去了。 ### 复杂度 - 时间复杂度: $O(N)$,N 为二叉树节点数。 - 空间复杂度: $O(q)$,q 为队列长度。最坏情况是满二叉树,此时 q 为 $2/N$,即为 $O(N)$,N 为二叉树节点数。 -## 代码 +## 代码(JavaScript/C++) JavaScript Code @@ -184,3 +213,52 @@ var sumNumbers = function (root) { return sum; }; ``` + +C++ Code + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + if (!root) return 0; + + int total = 0; + queue level; + level.push(root); + + while (!level.empty()) { + int size = level.size(); + while (size--) { + TreeNode* node = level.front(); + level.pop(); + + if (node->left) { + node->left->val += node->val * 10; + level.push(node->left); + } + if (node->right) { + node->right->val += node->val * 10; + level.push(node->right); + } + if (!node->left && !node->right) { + total += node->val; + } + } + } + return total; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/binary-tree/16.find-bottom-left-tree-value.md b/basic/binary-tree/16.find-bottom-left-tree-value.md index 6aab767..391e33b 100644 --- a/basic/binary-tree/16.find-bottom-left-tree-value.md +++ b/basic/binary-tree/16.find-bottom-left-tree-value.md @@ -4,16 +4,16 @@ https://leetcode-cn.com/problems/find-bottom-left-tree-value/ - [513.找树左下角的值](#513找树左下角的值) - [题目描述](#题目描述) - - [方法 1:BFS](#方法-1bfs) + - [方法 1:层次遍历](#方法-1层次遍历) - [思路](#思路) - [伪代码](#伪代码) - - [代码](#代码) + - [代码(JavaScript/Python/C++)](#代码javascriptpythonc) - [复杂度分析](#复杂度分析) - [方法 2:DFS](#方法-2dfs) - [思路](#思路-1) - [伪代码](#伪代码-1) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码(JavaScript/Python/C++)](#代码javascriptpythonc-1) ## 题目描述 @@ -55,13 +55,13 @@ https://leetcode-cn.com/problems/find-bottom-left-tree-value/ 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 方法 1:BFS +## 方法 1:层次遍历 ### 思路 -按照题目意思来做,找到最后一层,返回最左边的节点。 +按照题目意思我们只需要找到最后一层,返回最左边的节点即可。 -所以只要,对二叉树进行层次遍历,遍历到最后一层的时候,返回第一个节点就行了。 +所以只要对二叉树进行层次遍历,等遍历到最后一层的时候,返回第一个节点。 ![bfs](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/513_0.png) @@ -104,7 +104,7 @@ while (queue.length) { } ``` -### 代码 +### 代码(JavaScript/Python/C++) JavaScript Code @@ -199,6 +199,45 @@ var findBottomLeftValue = function (root) { }; ``` +C++ Code + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + TreeNode* bottom_left = nullptr; + queue level; + level.push(root); + + while (!level.empty()) { + int size = level.size(); + bottom_left = level.front(); + + while (size--) { + TreeNode* node = level.front(); + level.pop(); + if (node->left) level.push(node->left); + if (node->right) level.push(node->right); + } + } + + return bottom_left->val; + + } +}; +``` + ### 复杂度分析 - 时间复杂度:$O(N)$,其中 N 为节点数。 @@ -246,7 +285,7 @@ var findBottomLeftValue = function (root) { - 时间复杂度:$O(N)$,其中 N 为节点数。 - 空间复杂度:$O(h)$,其中 $h$ 为树的深度,最坏的情况 $h$ 等于 $N$,其中 N 为节点数,此时树退化到链表。 -### 代码 +### 代码(JavaScript/Python/C++) JavaScript Code @@ -317,3 +356,40 @@ class Solution(object): return self._ans ``` + +C++ Code + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + findBottomLeftValue(root, 1); + return ans_; + } + void findBottomLeftValue(TreeNode* root, int depth) { + if (depth > max_depth_) { + max_depth_ = depth; + ans_ = root->val; + } + + if (root->left) findBottomLeftValue(root->left, depth + 1); + if (root->right) findBottomLeftValue(root->right, depth + 1); + } +private: + int max_depth_ = 0; + int ans_; +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/binary-tree/18.vertical-order-traversal-of-a-binary-tree.md b/basic/binary-tree/18.vertical-order-traversal-of-a-binary-tree.md index 9b94910..6aef18f 100644 --- a/basic/binary-tree/18.vertical-order-traversal-of-a-binary-tree.md +++ b/basic/binary-tree/18.vertical-order-traversal-of-a-binary-tree.md @@ -209,3 +209,5 @@ var verticalTraversal = function (root) { } }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/binary-tree/ext-diameter-of-binary-tree.md b/basic/binary-tree/ext-diameter-of-binary-tree.md new file mode 100644 index 0000000..ebdc77b --- /dev/null +++ b/basic/binary-tree/ext-diameter-of-binary-tree.md @@ -0,0 +1,79 @@ +# 543. 二叉树的直径 + +https://leetcode-cn.com/problems/diameter-of-binary-tree/ + +## 题目描述 + +``` +给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。 + +  + +示例 : +给定二叉树 + + 1 + / \ + 2 3 + / \ + 4 5 +返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。 + +  + +注意:两结点之间的路径长度是以它们之间边的数目表示。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/diameter-of-binary-tree +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1: DFS + +### 思路 + +题目的意思就是要找到一个子树,满足条件“其左子树高度+右子树高度值最大”,返回这个最大值。 + +要找到符合条件的子树,只需要在计算二叉树高度的同时用一个全局变量来记录就行。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$,N 是二叉树节点数。 +- 空间复杂度:$O(h)$,h 是二叉树的高度。 + +### 代码 + +JavaScript Code + +```js +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +var diameterOfBinaryTree = function(root) { + let max = 0 + dfs(root) + return max + + // **************************************** + function dfs(root) { + if (!root) return 0 + if (!root.left && !root.right) return 1 + + const leftH = dfs(root.left) + const rightH = dfs(root.right) + if (leftH + rightH > max) max = leftH + rightH + + return Math.max(leftH, rightH) + 1 + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/binary-tree/ext-validate-binary-search-tree.md b/basic/binary-tree/ext-validate-binary-search-tree.md new file mode 100644 index 0000000..4f1d145 --- /dev/null +++ b/basic/binary-tree/ext-validate-binary-search-tree.md @@ -0,0 +1,145 @@ +# 98. 验证二叉搜索树 + +https://leetcode-cn.com/problems/validate-binary-search-tree/ + +- [98. 验证二叉搜索树](#98-验证二叉搜索树) + - [题目描述](#题目描述) + - [方法 1:递归](#方法-1递归) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码](#代码) + - [方法 2:中序遍历](#方法-2中序遍历) + - [思路](#思路-1) + - [复杂度](#复杂度-1) + - [代码](#代码-1) + +## 题目描述 + +``` +给定一个二叉树,判断其是否是一个有效的二叉搜索树。 + +假设一个二叉搜索树具有如下特征: + +节点的左子树只包含小于当前节点的数。 +节点的右子树只包含大于当前节点的数。 +所有左子树和右子树自身必须也是二叉搜索树。 +示例 1: + +输入: + 2 + / \ + 1 3 +输出: true +示例 2: + +输入: + 5 + / \ + 1 4 +  / \ +  3 6 +输出: false +解释: 输入为: [5,1,4,null,null,3,6]。 +  根节点的值为 5 ,但是其右子节点值为 4 。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/validate-binary-search-tree +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:递归 + +### 思路 + +- `root`的**左子树**所有节点值必须**小于**`root.val` +- `root`的**右子树**所有节点值必须**大于**`root.val` +- 在递归时需要将 `root.val` 这个信息传递下去,作为左子树节点值的 upperBound 以及右子树节点值的 lowerBound +- 递归出口: + - 空节点 + - 不符合要求的节点(值不在 (lowerBound, upperBound) 范围内的节点) + +### 复杂度 + +- 时间复杂度: $O(N)$,N 为二叉树节点数。 +- 空间复杂度: $O(h)$,h 为二叉树高度。 + +### 代码 + +JavaScript Code + +```js +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +var isValidBST = function ( + root, + lowerBound = -Infinity, + upperBound = Infinity +) { + if (!root) return true; + if (root.val <= lowerBound || root.val >= upperBound) return false; + return ( + isValidBST(root.left, lowerBound, root.val) && + isValidBST(root.right, root.val, upperBound) + ); +}; +``` + +## 方法 2:中序遍历 + +### 思路 + +二叉搜索树的中序遍历结果是一个递增数组,只需检查给定二叉树的中序遍历结果是否符合要求即可。 + +### 复杂度 + +- 时间复杂度: $O(N)$,N 为二叉树节点数。 +- 空间复杂度: $O(h)$,h 为二叉树高度。 + +### 代码 + +JavaScript Code + +```js +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +var isValidBST = function(root) { + const res = []; + inorder(root); + + for (let i = 1; i < res.length; i++) { + if (res[i] <= res[i - 1]) return false; + } + return true; + + // *************** + + function inorder(root) { + if (!root) return; + inorder(root.left); + res.push(root.val); + inorder(root.right); + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/hashmap/19.two-sum.md b/basic/hashmap/19.two-sum.md index 2672d22..19adfa6 100644 --- a/basic/hashmap/19.two-sum.md +++ b/basic/hashmap/19.two-sum.md @@ -7,15 +7,15 @@ https://leetcode-cn.com/problems/two-sum - [方法 1:哈希表](#方法-1哈希表) - [思路](#思路) - [复杂度分析](#复杂度分析) - - [代码](#代码) + - [代码(JavaScript/Python/C++)](#代码javascriptpythonc) - [方法 2:排序+双指针](#方法-2排序双指针) - [思路](#思路-1) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码](#代码) - [方法 3:暴力法](#方法-3暴力法) - [思路](#思路-2) - [复杂度分析](#复杂度分析-2) - - [代码](#代码-2) + - [代码](#代码-1) ## 题目描述 @@ -51,7 +51,7 @@ https://leetcode-cn.com/problems/two-sum - 时间复杂度:$O(N)$,N 为数组长度,最坏的情况下数组中的每个元素都被访问一次,访问数组元素的时间是 $O(1)$,哈希表插入和查询元素的时间也是 $O(1)$。 - 空间复杂度:$O(N)$,N 为数组长度,用来存元素和下标的哈希表所需的空间。 -### 代码 +### 代码(JavaScript/Python/C++) JavaScript Code @@ -93,6 +93,26 @@ class Solution(object): hashmap[n] = i ``` +C++ Code + +```cpp +class Solution { +public: + vector twoSum(vector& nums, int target) { + map seen; + for (int i = 0; i < nums.size(); i++) { + int sub = target - nums[i]; + auto it = seen.find(sub); + if (it != seen.end()) { + return {it->second, i}; + } + seen[nums[i]] = i; + } + return {}; + } +}; +``` + ## 方法 2:排序+双指针 ### 思路 @@ -103,7 +123,7 @@ class Solution(object): ### 复杂度分析 - 时间复杂度:$O(NlogN)$,N 为数组长度。 -- 空间复杂度:$O(1)$。(不是很确定,是 $O(1)$ 还是 $O(N)$) +- 空间复杂度:$O(N)$。 ### 代码 @@ -170,3 +190,5 @@ var twoSum = function (nums, target) { } }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/hashmap/22.longest-substring-without-repeating-characters.md b/basic/hashmap/22.longest-substring-without-repeating-characters.md index 9cfa317..a757866 100644 --- a/basic/hashmap/22.longest-substring-without-repeating-characters.md +++ b/basic/hashmap/22.longest-substring-without-repeating-characters.md @@ -7,7 +7,7 @@ https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ - [方法 1:滑动窗口+哈希表](#方法-1滑动窗口哈希表) - [思路](#思路) - [复杂度分析](#复杂度分析) - - [代码](#代码) + - [代码(JavaScript/C++)](#代码javascriptc) ## 题目描述 @@ -50,9 +50,9 @@ https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ ### 复杂度分析 - 时间复杂度:$O(N)$,N 为 s 长度。 -- 空间复杂度:$O(d)$,d 是字符集的大小,但哈希表最大的大小也只是 $O(N)$。 +- 空间复杂度:$O(d)$,d 是字符集的大小,但哈希表的大小最大也只是 $O(N)$。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -83,3 +83,29 @@ var lengthOfLongestSubstring = function (s) { return max; }; ``` + +C++ Code + +```cpp +class Solution { +public: + int lengthOfLongestSubstring(string s) { + unordered_map seen; + int max_len = 0, l = 0, r = 0; + while (r < s.size()) { + if (seen.count(s[r]) > 0) { + int last_pos = seen[s[r]]; + if (last_pos >= l && last_pos <= r) { + l = last_pos + 1; + } + } + max_len = max(max_len, r - l + 1); + seen[s[r]] = r; + r++; + } + return max_len; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/hashmap/23.substring-with-concatenation-of-all-words.md b/basic/hashmap/23.substring-with-concatenation-of-all-words.md index 9d97616..0545dc9 100644 --- a/basic/hashmap/23.substring-with-concatenation-of-all-words.md +++ b/basic/hashmap/23.substring-with-concatenation-of-all-words.md @@ -67,6 +67,39 @@ naive 的想法是,将 words 里面的单词组合成字符串,然后到 s JavaScript Code +```js +/** + * @param {string} s + * @param {string[]} words + * @return {number[]} + */ +var findSubstring = function(s, words) { + const wordLen = words[0].length; + const substrLen = wordLen * words.length; + const initialWordsMap = words.reduce((map, w) => { + map[w] = (map[w] || 0) + 1; + return map; + }, {}) + const res = []; + + for (let i = 0; i <= s.length - substrLen; i++) { + const wordsMap = {...initialWordsMap}; + for (let j = i; j < i + substrLen; j += wordLen) { + const word = s.slice(j, j + wordLen); + if (!(word in wordsMap) || wordsMap[word] == 0) break; + wordsMap[word]--; + } + if (usedUpWords(wordsMap)) res.push(i); + } + return res; + + // ****************************************** + function usedUpWords(map) { + return Object.values(map).every(n => n == 0); + } +}; +``` + ```js /** * @param {string} s @@ -99,3 +132,5 @@ var findSubstring = function (s, words) { return res; }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/hashmap/ext-max-points-on-a-line.md b/basic/hashmap/ext-max-points-on-a-line.md new file mode 100644 index 0000000..7e27135 --- /dev/null +++ b/basic/hashmap/ext-max-points-on-a-line.md @@ -0,0 +1,161 @@ +# 149. 直线上最多的点数 + +https://leetcode-cn.com/problems/max-points-on-a-line/ + +## 题目描述 +- [149. 直线上最多的点数](#149-直线上最多的点数) + - [题目描述](#题目描述) + - [方法 1:枚举](#方法-1枚举) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法 2: 哈希表](#方法-2-哈希表) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) +``` +给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 + +  + +示例 1: +``` + +![](https://assets.leetcode.com/uploads/2021/02/25/plane1.jpg) + +``` +输入:points = [[1,1],[2,2],[3,3]] +输出:3 +示例 2: +``` + +![](https://assets.leetcode.com/uploads/2021/02/25/plane2.jpg) + +``` +输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] +输出:4 +  + +提示: + +1 <= points.length <= 300 +points[i].length == 2 +-104 <= xi, yi <= 104 +points 中的所有点 互不相同 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/max-points-on-a-line +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:枚举 + +### 思路 + +这题其实不难,只需要知道两个朴素的数学知识: + +- 两点确定一条直线 +- 用斜率方程来判断某点是否在一条直线上 + +暴力点的思路就是,枚举所有两个点的组合: + +- 先用两个点确定一条直线 +- 枚举其他点,判断点是否在这条直线上 + +### 复杂度分析 + +- 时间复杂度:$O(N^3)$,枚举直线的时间是 $O(N^2)$,计算在直线上的点的时间是 $O(N)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[][]} points + * @return {number} + */ +var maxPoints = function (points) { + let max = 1; + // 点两两组合,枚举所有组合的直线 + for (let i = 0; i < points.length; i++) { + for (let j = i + 1; j < points.length; j++) { + // points[i] 和 points[j] 确定了一条直线 + // 计算在这条直线上的点 + let count = 2; + for (let k = j + 1; k < points.length; k++) { + if (areSameLine(points[i], points[j], points[k])) count++ + } + max = Math.max(max, count); + } + } + return max; + + // ********************************************* + function areSameLine([x1, y1], [x2, y2], [x3, y3]) { + if (x1 == x2 && x2 == x3) return true; + if (y1 == y2 && y2 == y3) return true; + if (x1 == x2 || x2 == x3) return false; + if (y1 == y2 || y2 == y3) return false; + const s1 = (y1 - y2) / (x1 - x2); + const s2 = (y2 - y3) / (x2 - x3); + return s1 === s2; + } +}; +``` + +## 方法 2: 哈希表 + +### 思路 + +枚举直线无法避免,但是计算直线上的点这一步可以优化,思路如下: + +- 先确定一个点,计算当前点与剩余其他点的斜率 +- 用哈希表记录这个过程中所有出现过的斜率以及出现次数 +- 因为斜率一样的点就在同一条直线上,所以统计斜率出现次数就能知道该直线上有多少个点了 +- 难点在于斜率的记录方式,直接计算会出现精度问题,所以采取分子分母元祖的记录方式,如,`slope = y / x` 记录为字符串 `'y/x'`,记录前还需要对分式进行约分。 + +### 复杂度分析 + +- 时间复杂度:$O(N^2*logm)$,枚举直线的时间是 $O(N^2)$,计算 gcd 的时间是 $O(logm)$,m 是点的最大差值。 +- 空间复杂度:$O(N)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[][]} points + * @return {number} + */ +var maxPoints = function (points) { + let max = 1; + for (let i = 0; i < points.length; i++) { + // 先确定一个点 points[i] + const map = {}; + for (let j = i + 1; j < points.length; j++) { + // 枚举剩余的点,计算两点的斜率 + // 用哈希表记录所有出现过的斜率的次数 + const key = getSlopeKey(points[i], points[j]); + map[key] = (map[key] || 0) + 1; + } + const count = Math.max(...Object.values(map)) + 1; + max = Math.max(count, max); + } + return max; + + // *********************************** + function getSlopeKey([x1, y1], [x2, y2]) { + const [x, y] = [x1 - x2, y1 - y2]; + const k = gcd(x, y); + return `${y / k}/${x / k}`; + } + function gcd(a, b) { + return b != 0 ? gcd(b, a % b) : a; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/linked-list/07.swap-nodes-in-pairs.md b/basic/linked-list/07.swap-nodes-in-pairs.md index d901459..d79133f 100644 --- a/basic/linked-list/07.swap-nodes-in-pairs.md +++ b/basic/linked-list/07.swap-nodes-in-pairs.md @@ -2,16 +2,16 @@ https://leetcode-cn.com/problems/swap-nodes-in-pairs/ -- [24. 两两交换链表中的节点](#24dot-两两交换链表中的节点) +- [24. 两两交换链表中的节点](#24-两两交换链表中的节点) - [题目描述](#题目描述) - - [方法 1: 循环](#方法-1-循环) + - [方法 1: 迭代](#方法-1-迭代) - [图解](#图解) - [复杂度分析](#复杂度分析) - - [代码](#代码) + - [代码(JavaScript/C++)](#代码javascriptc) - [方法 2: 递归](#方法-2-递归) - [思路](#思路) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码(JavaScript/C++)](#代码javascriptc-1) ## 题目描述 @@ -46,21 +46,21 @@ https://leetcode-cn.com/problems/swap-nodes-in-pairs/ 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 方法 1: 循环 +## 方法 1: 迭代 ### 图解 -- 要注意指针改变的顺序,不然可能会丢失节点。 -- 用一个 dummy 节点来简化操作,不用额外考虑链表头部的情况。 +- 要注意指针改变的顺序,不然可能会丢失节点。 +- 用一个 dummy 节点来简化操作,不用额外考虑链表头部的情况。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/07.swap-nodes-in-pairs-02.png) ### 复杂度分析 -- 时间复杂度:$O(N)$, N 为链表长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(N)$, N 为链表长度。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -77,26 +77,62 @@ JavaScript Code * @return {ListNode} */ var swapPairs = function (head) { - const dummy = new ListNode(null, head); - let prev = dummy; - let cur = prev.next; - - while (cur && cur.next) { - // 按照上图,指针更换顺序是这样子的 - // prev.next = cur.next - // cur.next = prev.next.next - // prev.next.next = cur - - // 也可以先用一个指针把下一个节点存起来 - const next = cur.next; - cur.next = next.next; - next.next = cur; - prev.next = next; - - prev = cur; - cur = cur.next; + const dummy = new ListNode(null, head); + let prev = dummy; + let cur = prev.next; + + while (cur && cur.next) { + // 按照上图,指针更换顺序是这样子的 + // prev.next = cur.next + // cur.next = prev.next.next + // prev.next.next = cur + + // 也可以先用一个指针把下一个节点存起来 + const next = cur.next; + cur.next = next.next; + next.next = cur; + prev.next = next; + + prev = cur; + cur = cur.next; + } + return dummy.next; +}; +``` + +C++ Code + +```cpp +/** + * 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* swapPairs(ListNode* head) { + if (head == nullptr || head->next == nullptr) return head; + + ListNode* dummy = new ListNode(0, head); + ListNode* prev = dummy; + ListNode* cur = prev->next; + + while (cur != nullptr && cur->next != nullptr) { + ListNode* next = cur->next; + cur->next = next->next; + next->next = cur; + prev->next = next; + + prev = cur; + cur = cur->next; + } + return dummy->next; } - return dummy.next; }; ``` @@ -116,22 +152,22 @@ var swapPairs = function (head) { **小问题之间的关系** -- 下一个递归应该返回互换后的第一个节点 -- 当前递归应该返回互换后的第一个节点给上一个递归 +- 下一个递归应该返回互换后的第一个节点 +- 当前递归应该返回互换后的第一个节点给上一个递归 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/07.swap-nodes-in-pairs-01.png) **递归出口** -- 链表尾部 `head === null` -- 链表最后只剩下一个元素 `head.next === null` +- 链表尾部 `head === null` +- 链表最后只剩下一个元素 `head.next === null` ### 复杂度分析 -- 时间复杂度:$O(N)$, N 为链表长度。 -- 空间复杂度:$O(N)$, N 为链表长度,递归栈的空间。 +- 时间复杂度:$O(N)$, N 为链表长度。 +- 空间复杂度:$O(N)$, N 为链表长度,递归栈的空间。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -148,20 +184,53 @@ JavaScript Code * @return {ListNode} */ var swapPairs = function (head) { - // 递归出口 - if (!head || !head.next) return head; + // 递归出口 + if (!head || !head.next) return head; + + // 先保存下一个节点,避免丢失 + const next = head.next; + + // 下一个递归会返回互换后的第一个节点 + // head 是当前组互换后的第二个节点,head.next 指向下一组就好 + head.next = swapPairs(next.next); + + // 将当前组的两个节点互换 + next.next = head; - // 先保存下一个节点,避免丢失 - const next = head.next; + // 返回互换后的第一个节点 + return next; +}; +``` + +C++ Code + +```cpp +/** + * 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* swapPairs(ListNode* head) { + if (head == nullptr || head->next == nullptr) return head; + + ListNode* first = head; + ListNode* second = first->next; - // 下一个递归会返回互换后的第一个节点 - // head 是当前组互换后的第二个节点,head.next 指向下一组就好 - head.next = swapPairs(next.next); + ListNode* head_of_next_group = swapPairs(second->next); - // 将当前组的两个节点互换 - next.next = head; + first->next = head_of_next_group; + second->next = first; - // 返回互换后的第一个节点 - return next; + return second; + } }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/linked-list/08.rotate-list.md b/basic/linked-list/08.rotate-list.md index 2915e34..19de0b8 100644 --- a/basic/linked-list/08.rotate-list.md +++ b/basic/linked-list/08.rotate-list.md @@ -79,3 +79,5 @@ var rotateRight = function (head, k) { return newHead; }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/linked-list/09.convert-sorted-list-to-binary-search-tree.md b/basic/linked-list/09.convert-sorted-list-to-binary-search-tree.md index 6ae1ec1..f11282c 100644 --- a/basic/linked-list/09.convert-sorted-list-to-binary-search-tree.md +++ b/basic/linked-list/09.convert-sorted-list-to-binary-search-tree.md @@ -1,5 +1,16 @@ # 109. 有序链表转换二叉搜索树 +- [109. 有序链表转换二叉搜索树](#109-有序链表转换二叉搜索树) + - [题目描述](#题目描述) + - [方法 1:递归](#方法-1递归) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码(JavaScript/C++/Python)](#代码javascriptcpython) + - [方法 2:空间换时间](#方法-2空间换时间) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码(JavaScript/C++)](#代码javascriptc) + ## 题目描述 ``` @@ -28,17 +39,15 @@ ### 思路 -TODO - -- 先用快慢指针找到中间节点 -- 分治构建平衡二叉树 +- 先用快慢指针找到中间节点 +- 分治构建平衡二叉树 ### 复杂度分析 -- 时间复杂度:$O(NlogN)$,N 为链表长度。 -- 空间复杂度:$O(logN)$,N 为链表长度。 +- 时间复杂度:$O(NlogN)$,N 为链表长度。 +- 空间复杂度:$O(logN)$,N 为链表长度。 -### 代码 +### 代码(JavaScript/C++/Python) JavaScript Code @@ -63,18 +72,213 @@ JavaScript Code * @return {TreeNode} */ var sortedListToBST = function (head, tail = null) { - if (!head || head === tail) return null; + if (!head || head === tail) return null; + + let slow = head, + fast = head; + while (fast !== tail && fast.next !== tail) { + slow = slow.next; + fast = fast.next.next; + } + + const root = new TreeNode(slow.val); + root.left = sortedListToBST(head, slow); + root.right = sortedListToBST(slow.next, tail); + return root; +}; +``` + +C++ Code - let slow = head, - fast = head; - while (fast !== tail && fast.next !== tail) { - slow = slow.next; - fast = fast.next.next; +```cpp +/** + * 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) {} + * }; + */ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* sortedListToBST(ListNode* head) { + if (head == nullptr) return nullptr; + return sortedListToBST(head, nullptr); } + TreeNode* sortedListToBST(ListNode* head, ListNode* tail) { + if (head == tail) return nullptr; + + ListNode* slow = head; + ListNode* fast = head; + + while (fast != tail && fast->next != tail) { + slow = slow->next; + fast = fast->next->next; + } + + TreeNode* root = new TreeNode(slow->val); + root->left = sortedListToBST(head, slow); + root->right = sortedListToBST(slow->next, tail); + return root; + } +}; +``` - const root = new TreeNode(slow.val); - root.left = sortedListToBST(head, slow); - root.right = sortedListToBST(slow.next, tail); +Python Code + +```py +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def sortedListToBST(self, head): + """ + :type head: ListNode + :rtype: TreeNode + """ + if not head: return None + prev, slow, fast = None, head, head + + while fast and fast.next: + prev = slow + slow = slow.next + fast = fast.next.next + + root = TreeNode(slow.val) + if slow == fast: return root + + if prev: prev.next = None + root.left = self.sortedListToBST(head) + root.right = self.sortedListToBST(slow.next) + return root +``` + +## 方法 2:空间换时间 + +### 思路 + +由于寻找链表中点的时间复杂度是 $O(N)$,如果事先使用数组将链表的值存储起来,寻找中点就变成了 $O(1)$ 时间的操作,代价则是 $O(N)$ 的额外空间,问题转换成了**将有序数组转换成搜索二叉树**。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$,N 为链表长度。 +- 空间复杂度:$O(N)$,N 为链表长度。 + +### 代码(JavaScript/C++) + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {ListNode} head + * @return {TreeNode} + */ +var sortedListToBST = function (head) { + if (!head) return null; + + const nodes = []; + while (head) { + nodes.push(head.val); + head = head.next; + } + + return sortedArrayToBST(nodes, 0, nodes.length); + + // ******************************************** + function sortedArrayToBST(array, start, end) { + if (start >= end) return null; + + const mid = (((end - start) >> 1) >> 0) + start; + const root = new TreeNode(array[mid]); + root.left = sortedArrayToBST(array, start, mid); + root.right = sortedArrayToBST(array, mid + 1, end); return root; + } +}; +``` + +C++ Code + +```cpp +/** + * 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) {} + * }; + */ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* sortedListToBST(ListNode* head) { + vector nodes; + while (head != nullptr) { + nodes.push_back(head->val); + head = head->next; + } + return sortedListToBST(nodes, 0, nodes.size()); + } + TreeNode* sortedListToBST(vector& nodes, int start, int end) { + if (start >= end) return nullptr; + + int mid = (end - start) / 2 + start; + TreeNode* root = new TreeNode(nodes[mid]); + root->left = sortedListToBST(nodes, start, mid); + root->right = sortedListToBST(nodes, mid + 1, end); + return root; + } }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/linked-list/10.intersection-of-two-linked-lists.md b/basic/linked-list/10.intersection-of-two-linked-lists.md index a4a3dce..706792a 100644 --- a/basic/linked-list/10.intersection-of-two-linked-lists.md +++ b/basic/linked-list/10.intersection-of-two-linked-lists.md @@ -7,15 +7,15 @@ https://leetcode-cn.com/problems/intersection-of-two-linked-lists - [方法 1:暴力法](#方法-1暴力法) - [思路](#思路) - [复杂度](#复杂度) - - [代码](#代码) + - [代码(JavaScript/C++)](#代码javascriptc) - [方法 2:哈希表](#方法-2哈希表) - [思路](#思路-1) - [复杂度](#复杂度-1) - - [代码](#代码-1) + - [代码(JavaScript/C++)](#代码javascriptc-1) - [方法 3:双指针](#方法-3双指针) - [思路](#思路-2) - [复杂度](#复杂度-2) - - [代码](#代码-2) + - [代码(JavaScript/C++)](#代码javascriptc-2) ## 题目描述 @@ -36,7 +36,7 @@ https://leetcode-cn.com/problems/intersection-of-two-linked-lists - 时间复杂度:$O(M * N)$, M, N 分别为两个链表的长度。 - 空间复杂度:$O(1)$。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -71,6 +71,38 @@ var getIntersectionNode = function (headA, headB) { }; ``` +C++ Code +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + if (headA == NULL || headB == NULL) return NULL; + + ListNode *pA = headA; + + while (pA != NULL) { + ListNode *pB = headB; + while (pB != NULL) { + if (pA == pB) { + return pA; + } + pB = pB->next; + } + pA = pA->next; + } + return NULL; + } +}; +``` + ## 方法 2:哈希表 ### 思路 @@ -83,7 +115,7 @@ var getIntersectionNode = function (headA, headB) { - 时间复杂度:$O(M + N)$, M, N 分别为两个链表的长度。 - 空间复杂度:$O(N)$,N 为链表 A 的长度。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -120,6 +152,35 @@ var getIntersectionNode = function (headA, headB) { }; ``` +C++ Code +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + if (headA == NULL || headB == NULL) return NULL; + + map seen; + while (headA) { + seen.insert(pair(headA, true)); + headA = headA->next; + } + while (headB) { + if (seen.find(headB) != seen.end()) return headB; + headB = headB->next; + } + return NULL; + } +}; +``` + ## 方法 3:双指针 ### 思路 @@ -140,7 +201,7 @@ var getIntersectionNode = function (headA, headB) { - 时间复杂度:$O(M + N)$, M, N 分别为两个链表的长度。 - 空间复杂度:$O(1)$。 -### 代码 +### 代码(JavaScript/C++) ```js /** @@ -168,3 +229,32 @@ var getIntersectionNode = function (headA, headB) { return pA; }; ``` + +C++ Code +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + if (headA == NULL || headB == NULL) return NULL; + + ListNode* pA = headA; + ListNode* pB = headB; + while (pA != pB) { + pA = pA == NULL ? headB : pA->next; + pB = pB == NULL ? headA : pB->next; + } + + return pA; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/basic/linked-list/11.linked-list-cycle-ii.md b/basic/linked-list/11.linked-list-cycle-ii.md index 4a527c1..8e4ac1e 100644 --- a/basic/linked-list/11.linked-list-cycle-ii.md +++ b/basic/linked-list/11.linked-list-cycle-ii.md @@ -2,20 +2,20 @@ https://leetcode-cn.com/problems/linked-list-cycle-ii/ -- [142.环形链表 II](#142dot环形链表-ii) +- [142.环形链表 II](#142环形链表-ii) - [题目描述](#题目描述) - - [方法 1:哈希表标记已遍历节点](#方法-1哈希表标记已遍历节点) + - [方法 1:哈希法](#方法-1哈希法) - [思路](#思路) - [复杂度分析](#复杂度分析) - - [代码](#代码) + - [代码(JavaScript/C++)](#代码javascriptc) - [方法 2:双指针](#方法-2双指针) - [思路](#思路-1) - [复杂度分析](#复杂度分析-1) - - [代码](#代码-1) + - [代码(JavaScript)](#代码javascript) - [方法 3:双指针 + 数学证明](#方法-3双指针--数学证明) - [思路](#思路-2) - [复杂度分析](#复杂度分析-2) - - [代码](#代码-2) + - [代码(JavaScript/C++)](#代码javascriptc-1) ## 题目描述 @@ -34,21 +34,21 @@ https://leetcode-cn.com/problems/linked-list-cycle-ii/ 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 方法 1:哈希表标记已遍历节点 +## 方法 1:哈希法 ### 思路 -1. 从头开始遍历链表并给每个节点增加一个“已遍历”的标记; -2. 如果在遍历过程中遇到了一个“已遍历”的节点,说明这个就是环的入口了; -3. 题目要求不允许修改给定的链表,但我们可以用一个 hashmap 来记录; -4. 由于题目中没有提到节点值是否唯一,也就是说两个不同的节点可能会有相同的值,那仅用节点值作为 hashmap 的 key 是不够的,得用整个节点对象来当 key,所以需要 `Map`。 +1. 可以从头开始遍历链表并给每个节点增加一个“已遍历”的标记; +2. 如果在遍历过程中遇到了一个“已遍历”的节点,说明这就是环的入口; +3. 但题目不允许修改给定的链表,所以我们可以用一个额外的 hashmap 来记录; +4. 注意题目中没有提到节点值是否唯一,所以仅用节点值作为 hashmap 的 key 是不够的,需要用到整个节点对象来当 key。 ### 复杂度分析 -- 时间复杂度:$O(n)$, n 为链表长度。 -- 空间复杂度:$O(n)$。 +- 时间复杂度:$O(n)$, n 为链表长度。 +- 空间复杂度:$O(n)$。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -66,15 +66,41 @@ JavaScript Code * @return {ListNode} */ var detectCycle = function (head) { - const map = new Map(); + const map = new Map(); - while (head) { - if (map.has(head)) return head; - map.set(head, true); - head = head.next; - } + while (head) { + if (map.has(head)) return head; + map.set(head, true); + head = head.next; + } + + return null; +}; +``` - return null; +C++ Code + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *detectCycle(ListNode *head) { + set seen; + ListNode *cur = head; + while (cur != NULL) { + if (seen.find(cur) != seen.end()) return cur; + seen.insert(cur); + cur = cur->next; + } + return NULL; + } }; ``` @@ -83,19 +109,19 @@ var detectCycle = function (head) { ### 思路 1. 先使用快慢指针确定链表是否有环; -2. 如果链表有环,那快慢指针相遇的点一定是在环上; -3. 接着把一个指针 A 移到链表头部,另一个指针 B 留在环内; -4. 指针 A 开始遍历环外的节点,指针 A 每走一步,指针 B 在环内走一圈; +2. 如果链表有环,那快慢指针相遇的点一定是在环中; +3. 接着把指针 A 移到链表头部,指针 B 留在环内; +4. 指针 A 开始遍历环外的节点,指针 B 遍历环内的节点,指针 A 每走一步,指针 B 在环内走一圈; 5. 如果指针 A 和指针 B 相遇了,说明这个节点就是环的入口。 > 因为环和环外的唯一交点就是环的入口点 ### 复杂度分析 -- 时间复杂度:$O(n*p)$, n 是环外链表的长度,p 是环的长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(n*p)$, n 是环外链表的长度,p 是环的长度。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码(JavaScript) JavaScript Code @@ -113,31 +139,31 @@ JavaScript Code * @return {ListNode} */ var detectCycle = function (head) { - let slow = head, - fast = head; - // 快慢指针确定有环 - while (fast && fast.next) { - slow = slow.next; - fast = fast.next.next; - // 确定有环,开始找环的第一个节点 - if (slow === fast) return findConnection(head, fast); - } - return null; - - // ****************************************** - - function findConnection(head, loopNode) { - // p1 走一步,p2 绕环一圈 - let p1 = head; - while (true) { - let p2 = loopNode; - while (p2.next !== loopNode && p2.next !== p1) { - p2 = p2.next; - } - if (p2.next === p1) return p1; - p1 = p1.next; - } + let slow = head, + fast = head; + // 快慢指针确定有环 + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + // 确定有环,开始找环的第一个节点 + if (slow === fast) return findConnection(head, fast); + } + return null; + + // ****************************************** + + function findConnection(head, loopNode) { + // p1 走一步,p2 绕环一圈 + let p1 = head; + while (true) { + let p2 = loopNode; + while (p2.next !== loopNode && p2.next !== p1) { + p2 = p2.next; + } + if (p2.next === p1) return p1; + p1 = p1.next; } + } }; ``` @@ -180,7 +206,7 @@ class Solution(object): ### 思路 -先用快慢指针确定链表有环,快慢指针会在环上的某个节点相遇。 +先用快慢指针确定链表是否有环,如果是环形链表,快慢指针会在环内的某个节点相遇。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/first_node_of_loop_in_linked_list_0.png) @@ -188,17 +214,23 @@ class Solution(object): **快指针** -假设走到相遇点之前,快指针在环内走了 x 圈,那快指针走过的总路程可以用 `S(fast) = a + x(b + c) + b` 来表示,其中 `(b + c)` 就是环的长度。 +假设走到相遇点之前,快指针在环内走了 x 圈,那快指针走过的总路程可以用 + +`S(fast) = a + x(b + c) + b` + +来表示,其中 `(b + c)` 就是环的长度。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/first_node_of_loop_in_linked_list_1.png) **慢指针** -假设走到相遇点之前,慢指针在环内走了 y 圈,同理可得慢指针走过的总路程是 `S(slow) = a + y(b + c) + b`。 +假设走到相遇点之前,慢指针在环内走了 y 圈,同理可得慢指针走过的总路程是 + +`S(slow) = a + y(b + c) + b` 而由于快指针的速度是慢指针速度的 2 倍,所以可得以下方程式: -`S(slow) = 2S(fast)` => `a + x(b + c) + b = 2(a + y(b + c) + b)` +`2S(slow) = S(fast)` => `2(a + x(b + c) + b) = a + y(b + c) + b` 稍微整理一下我们就得到了: @@ -214,10 +246,10 @@ class Solution(object): ### 复杂度分析 -- 时间复杂度:$O(n)$,n 为链表长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(n)$,n 为链表长度。 +- 空间复杂度:$O(1)$。 -### 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -235,24 +267,60 @@ JavaScript Code * @return {ListNode} */ var detectCycle = function (head) { - let fast = head, - slow = head; - - // 快慢指针确定有环 - while (fast && fast.next) { - fast = fast.next.next; + let fast = head, + slow = head; + + // 快慢指针确定有环 + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + + // 确定有环,开始找环的第一个节点 + if (fast === slow) { + slow = head; + while (slow !== fast) { slow = slow.next; + fast = fast.next; + } + return slow; + } + } + return null; +}; +``` - // 确定有环,开始找环的第一个节点 - if (fast === slow) { - slow = head; - while (slow !== fast) { - slow = slow.next; - fast = fast.next; +C++ Code + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *detectCycle(ListNode *head) { + ListNode *slow = head; + ListNode *fast = head; + + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) { + fast = head; + while (slow != fast) { + slow = slow->next; + fast = fast->next; + } + return slow; } - return slow; } + return NULL; } - return null; }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/linked-list/12.lru-cache.md b/basic/linked-list/12.lru-cache.md index 1a0ad10..40b73ce 100644 --- a/basic/linked-list/12.lru-cache.md +++ b/basic/linked-list/12.lru-cache.md @@ -2,12 +2,13 @@ https://leetcode-cn.com/problems/lru-cache/ -- [146. LRU 缓存机制](#146dot-lru-缓存机制) +- [146. LRU 缓存机制](#146-lru-缓存机制) - [题目描述](#题目描述) - - [思路](#思路) - - [复杂度分析](#复杂度分析) - - [伪代码](#伪代码) - - [代码](#代码) + - [方法1: 哈希表+双向链表](#方法1-哈希表双向链表) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [伪代码](#伪代码) + - [代码(JavaScript/C++)](#代码javascriptc) ## 题目描述 @@ -40,44 +41,52 @@ cache.get(4); // 返回 4 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 思路 +## 方法1: 哈希表+双向链表 -假设我们有一个玩具摊位,可以向顾客展示小玩具,但是摊位大小有限,我们不能把所有的玩具都摆在摊位上,所以我们就把大部分的玩具都放在了仓库里。 +### 思路 + +先来看个非计算机的例子理解下题意,假设我们有一个玩具摊位,可以向顾客展示小玩具。玩具很多,但摊位大小有限,不能一次性展示所有玩具,于是我们就把大部分的玩具都放在了仓库里。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_0.png) -如果有顾客来问,我们就去仓库把那个玩具拿出来,摆在摊位上。 +如果有顾客来询问某个玩具,我们就去仓库把那个玩具拿出来,摆在摊位上。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_1.png) -因为最上面的那个位置最显眼,所以我们想总是把最新拿出来的玩具放在那。 +因为摊位最上面的位置最显眼,所以我们总是把最新拿出来的玩具放在那。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_2.png) -但是摊位大小有限,很快就摆满了,如果这时又来了顾客想看新玩具。 +不过由于摊位大小有限,很快就摆满了,这时如果又来了顾客想看新玩具。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_3.png) -我们只能把最下面的玩具拿回仓库(因为最下面的位置相对没那么受欢迎),腾出一个位置来放新玩具。 +我们只能把摊位最下面的玩具拿回仓库(因为最下面的位置相对没那么受欢迎),然后其他玩具往下移,腾出最上面的位置来放新玩具。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_4.png) -如果顾客想看的玩具就在摊位上,我们就可以直接展示这个玩具,同时把它放到最上面的位置(有人问说明它受欢迎嘛),其他的玩具就要挪挪位置了。 +如果顾客想看的玩具就摆在摊位上,我们就可以把这个玩具直接移到摊位最上面的位置,其他的玩具就要往下挪挪位置了。还记得我们的规则吧,最近有人询问的玩具要摆在最上面显眼的位置。 ![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/LRU_5.png) -回到计算机问题上面来,我们要用什么来表示我们的玩具摊位呢,如果用数组,玩具在摊位上的位置挪来挪去的,时间复杂度得是 $O(N)$,所以只能用链表了。 +回到计算机问题上面来,玩具摊位代表的就是缓存空间,我们需要考虑的问题是使用哪种数据结构来表示玩具摊位。 + +**选择1: 数组** + +如果选择数组,因为玩具在摊位上的位置会挪来挪去,时间复杂度是 $O(N)$,不符合题意。 -用链表的话,随意移除一个节点的时间复杂度是 $O(1)$,移除节点后,我们还得把它前后两个节点连起来,所以用双向链表会比较方便。 +**选择2: 链表** -但是链表获取节点的时间复杂度是 $O(N)$,我们手动移动玩具的时候,只需要看一眼就知道要找的玩具在哪个位置上,但是计算机没有那么聪明,所以我们还需要一个数据结构(哈希表)来帮计算机记录什么玩具在什么位置上。 +- 如果选择链表,我们知道在已知位置上新增节点,或者移除一个已知节点的时间复杂度是 $O(1)$。不过,链表查找节点的时间复杂度是 $O(N)$,同样不符合题意,但这还有办法补救。 +- 在玩具摊位的例子中,我们手动移动玩具的时候,只需要看一眼就知道要找的玩具在哪个位置上,但计算机没那么聪明,因此还需要给它一个脑子(哈希表)来记录什么玩具在什么位置上,也就是要用一个哈希表来记录每个 key 对应的链表节点引用。这样查找链表节点的时间复杂度就降到了 $O(1)$,不过代价是空间复杂度增加到了 $O(N)$。 +- 另外,由于移除链表节点后还需要把该节点前后的两个节点连起来,因此我们需要的是双向链表而不是单向链表。 -## 复杂度分析 +### 复杂度分析 - 时间复杂度:$O(1)$。 -- 空间复杂度:链表 $O(N)$,哈希表 $O(N)$,结果还是 $O(N)$。 +- 空间复杂度:链表 $O(N)$,哈希表 $O(N)$,结果还是 $O(N)$,N 为容量大小。 -## 伪代码 +### 伪代码 ``` // put @@ -92,8 +101,8 @@ else: 删除它在哈希表中的映射 新建一个节点 - 在哈希表中增加映射 把节点加到链表头部 + 在哈希表中增加映射 // get @@ -105,7 +114,7 @@ else: 返回 -1 ``` -## 代码 +### 代码(JavaScript/C++) JavaScript Code @@ -190,3 +199,104 @@ class LRUCache { * obj.put(key,value) */ ``` + +C++ Code +```cpp +class DLinkedListNode { +public: + int key; + int value; + DLinkedListNode *prev; + DLinkedListNode *next; + DLinkedListNode() : key(0), value(0), prev(NULL), next(NULL) {}; + DLinkedListNode(int k, int val) : key(k), value(val), prev(NULL), next(NULL) {}; +}; + +class LRUCache { +public: + LRUCache(int capacity) : capacity_(capacity) { + // 创建两个 dummy 节点来简化操作,这样就不用特殊对待头尾节点了 + dummy_head_ = new DLinkedListNode(); + dummy_tail_ = new DLinkedListNode(); + dummy_head_->next = dummy_tail_; + dummy_tail_->prev = dummy_head_; + } + + int get(int key) { + if (!key_exists_(key)) { + return -1; + } + // 1. 通过哈希表找到 key 对应的节点 + // 2. 将节点移到链表头部 + // 3. 返回节点值 + DLinkedListNode *node = key_node_map_[key]; + move_to_head_(node); + return node->value; + } + + void put(int key, int value) { + if (key_exists_(key)) { + // key 存在的情况 + DLinkedListNode *node = key_node_map_[key]; + node->value = value; + move_to_head_(node); + } else { + // key 不存在的情况: + // 1. 如果缓存空间满了,先删除尾节点,再新建节点 + // 2. 否则直接新建节点 + if (is_full_()) { + DLinkedListNode *tail = dummy_tail_->prev; + remove_node_(tail); + key_node_map_.erase(tail->key); + } + + DLinkedListNode *new_node = new DLinkedListNode(key, value); + add_to_head_(new_node); + key_node_map_[key] = new_node; + } + } +private: + unordered_map key_node_map_; + DLinkedListNode *dummy_head_; + DLinkedListNode *dummy_tail_; + int capacity_; + + void move_to_head_(DLinkedListNode *node) { + remove_node_(node); + add_to_head_(node); + }; + + void add_to_head_(DLinkedListNode *node) { + DLinkedListNode *prev_head = dummy_head_->next; + + dummy_head_->next = node; + node->prev = dummy_head_; + + node->next = prev_head; + prev_head->prev = node; + }; + + void remove_node_(DLinkedListNode *node) { + node->prev->next = node->next; + node->next->prev = node->prev; + node->prev = node->next = NULL; + }; + + bool key_exists_(int key) { + return key_node_map_.count(key) > 0; + }; + + bool is_full_() { + return key_node_map_.size() == capacity_; + }; +}; + +/** + * 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); + */ +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/basic/linked-list/ext-merge-two-sorted-lists.md b/basic/linked-list/ext-merge-two-sorted-lists.md deleted file mode 100644 index 3203579..0000000 --- a/basic/linked-list/ext-merge-two-sorted-lists.md +++ /dev/null @@ -1,116 +0,0 @@ -# 21. 合并两个有序链表 - -https://leetcode-cn.com/problems/merge-two-sorted-lists/ - -## 题目描述 - -``` -将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  - -示例: - -输入:1->2->4, 1->3->4 -输出:1->1->2->3->4->4 - -来源:力扣(LeetCode) -链接:https://leetcode-cn.com/problems/merge-two-sorted-lists -著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 -``` - -## 方法 1: 迭代 - -### 思路 - -- 用两个指针分别遍历两个链表,比较两个指针节点的大小。 - - 将较小的那个节点加到新链表中,然后指针后移。 - - 较大的那个节点指针不动,下一轮继续比较。 -- 如果两个链表长度不一样,继续遍历将多出来的节点加到新链表中就好了。 - -### 复杂度分析 - -- 时间复杂度:$O(N)$, N 为链表长度。 -- 空间复杂度:$O(1)$。 - -### 代码 - -JavaScript Code - -```js -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -/** - * @param {ListNode} l1 - * @param {ListNode} l2 - * @return {ListNode} - */ -var mergeTwoLists = function (l1, l2) { - const dummy = new ListNode(); - let p1 = l1, - p2 = l2, - cur = dummy; - - while (p1 || p2) { - if (!p2 || (p1 && p1.val <= p2.val)) { - cur.next = new ListNode(p1.val); - p1 = p1.next; - } else { - cur.next = new ListNode(p2.val); - p2 = p2.next; - } - cur = cur.next; - } - - return dummy.next; -}; -``` - -## 方法 2: 递归 - -### 思路 - -- 如果 `l1 < l2`,那就把 l1 作为合并链表的头部返回,然后继续合并 `l1.next` 和 `l2` 之后的节点。 -- 如果 `l2 < l1`,那就把 l2 作为合并链表的头部返回,然后继续合并 `l2.next` 和 `l1` 之后的节点。 -- 递归出口: - - 没有节点了。 - - 只剩一个节点,不用比较,返回那个节点就行。 - -### 复杂度分析 - -- 时间复杂度:$O(N)$, N 为链表长度。 -- 空间复杂度:$O(N)$, N 为链表长度,递归栈的空间。 - -### 代码 - -JavaScript Code - -```js -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -/** - * @param {ListNode} l1 - * @param {ListNode} l2 - * @return {ListNode} - */ -var mergeTwoLists = function (l1, l2) { - if (!l1) return l2; - if (!l2) return l1; - - if (l1.val < l2.val) { - l1.next = mergeTwoLists(l1.next, l2); - return l1; - } else { - l2.next = mergeTwoLists(l1, l2.next); - return l2; - } -}; -``` diff --git a/extensions/1755.closest-subsequence-sum.md b/extensions/1755.closest-subsequence-sum.md new file mode 100644 index 0000000..ad369d2 --- /dev/null +++ b/extensions/1755.closest-subsequence-sum.md @@ -0,0 +1,186 @@ +# 1755. 最接近目标值的子序列和 + +https://leetcode-cn.com/problems/closest-subsequence-sum/ + +- [1755. 最接近目标值的子序列和](#1755-最接近目标值的子序列和) + - [题目描述](#题目描述) + - [方法1:暴力法](#方法1暴力法) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法2:双向搜索](#方法2双向搜索) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) + +## 题目描述 + +``` +给你一个整数数组 nums 和一个目标值 goal 。 + +你需要从 nums 中选出一个子序列,使子序列元素总和最接近 goal 。也就是说,如果子序列元素和为 sum ,你需要 最小化绝对差 abs(sum - goal) 。 + +返回 abs(sum - goal) 可能的 最小值 。 + +注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。 + +  + +示例 1: + +输入:nums = [5,-7,3,5], goal = 6 +输出:0 +解释:选择整个数组作为选出的子序列,元素和为 6 。 +子序列和与目标值相等,所以绝对差为 0 。 +示例 2: + +输入:nums = [7,-9,15,-2], goal = -5 +输出:1 +解释:选出子序列 [7,-9,-2] ,元素和为 -4 。 +绝对差为 abs(-4 - (-5)) = abs(1) = 1 ,是可能的最小值。 +示例 3: + +输入:nums = [1,2,3], goal = -7 +输出:7 +  + +提示: + +1 <= nums.length <= 40 +-107 <= nums[i] <= 107 +-109 <= goal <= 109 + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/closest-subsequence-sum +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:暴力法 + +### 思路 + +首先尝试用最简单直接的思路来解题: + +- 枚举 `nums` 的所有子集,找到子集和最接近 `goal` 的那个 + +如果不知道怎么枚举子集可以先做下这道题 [78.子集](../medium/hot/36.subsets.md)。 + +### 复杂度分析 + +- 时间复杂度:$O(2^N)$,N 为 nums 的长度。 +- 空间复杂度:$O(N)$,N 为 nums 的长度,递归栈的深度。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +var minAbsDifference = function(nums, goal) { + return dfs(nums, 0, 0); + + function dfs(nums, pos, sum) { + // 对 nums 的所有元素作出选择后确定了子集 + // 返回子集和与 goal 的差值 + if (pos == nums.length) return Math.abs(sum - goal); + // prune + // 0 是可能的最小差值了,没必要继续搜索 + if (sum === goal) return 0; + + // 选当前数字 + const a = dfs(nums, pos + 1, sum + nums[pos]); + // 不选当前数字 + const b = dfs(nums, pos + 1, sum); + // 目标是找到最小的差值 + return Math.min(a, b); + } +}; +``` + +## 方法2:双向搜索 + +### 思路 + + + +### 复杂度分析 + +- 时间复杂度:$O(2^m + mlogm)$,m 为 nums 长度的一半,$2^m$ 是枚举半截数组所有子集的时间,$mlogm$ 是。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +var minAbsDifference = function (nums, goal) { + const mid = nums.length >> 1; + + // divide |nums| into two halves + // calculate sums of all possible subsets repectively + const leftSums = []; + dfs(nums, 0, mid, 0, leftSums); + const rightSums = []; + dfs(nums, mid, nums.length, 0, rightSums); + + // we need to choose one value from |leftSums| and |rightSums| respectively + // the |x| and |y| chosen should sum closest to |goal| + + // first sort |leftSums| for using binary search to find target + leftSums.sort((a, b) => a - b); + + // now iterate through |rightSums| + // for each sum |x| from |rightSums|, go find the value closest to |goal-x| in |leftSums|, let's call it |closest| + // idealy |closest| will be equal to |goal-x|, which makes the total subset sum equal to |goal| + // if not so lucky, we pick the closest |closest| over the iteration + let minDiff = Number.MAX_SAFE_INTEGER; + for (let i = 0; i < rightSums.length; i++) { + const x = rightSums[i]; + const target = goal - x; + const closest = findClosest(leftSums, target); + const diff = Math.abs(target - closest); + minDiff = Math.min(diff, minDiff) + } + return minDiff + + // ****************************************** + function dfs(nums, start, end, currentSum, bucket) { + if (start == end) { + bucket.push(currentSum); + return; + } + dfs(nums, start + 1, end, currentSum + nums[start], bucket); + dfs(nums, start + 1, end, currentSum, bucket); + } + + function findClosest(list, target) { + let l = 0, + r = list.length - 1, + m = 0; + + while (l <= r) { + m = ((r - l) >> 1) + l; + if (list[m] == target) return target + if (list[m] < target) l = m + 1 + else r = m - 1 + } + + if (l >= list.length) return list[r]; + if (r < 0) return list[l]; + + return Math.abs(list[l] - target) < Math.abs(list[r] - target) ? list[l] : list[r]; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/extensions/5.longest-palindromic-substring.md b/extensions/5.longest-palindromic-substring.md new file mode 100644 index 0000000..2465e61 --- /dev/null +++ b/extensions/5.longest-palindromic-substring.md @@ -0,0 +1,80 @@ +# 5. 最长回文子串 + +https://leetcode-cn.com/problems/longest-palindromic-substring/ + +- [5. 最长回文子串](#5-最长回文子串) + - [题目描述](#题目描述) + - [方法1:中心扩展](#方法1中心扩展) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 + +示例 1: + +输入: "babad" +输出: "bab" +注意: "aba" 也是一个有效答案。 +示例 2: + +输入: "cbbd" +输出: "bb" + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/longest-palindromic-substring +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:中心扩展 + +### 思路 + +最简单的思路,以 `单个` 或者 `两个一组相同` 的字符为中心,向左右两侧扩展,找到以这个(或者这两个)字符为中心的最长回文子串。接着对 `s` 中的所有字符重复这个操作,记录这个过程中找到的最长回文子串。 + +### 复杂度分析 + +- 时间复杂度:$O(N^2)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {string} s + * @return {string} + */ +var longestPalindrome = function (s) { + // 中心扩展,有两种情况: + // 1. 对于每个单个字符,向两侧扩展 + // 2. 对于每组两个相同的字符,向两侧扩展 + + let ans = ''; + for (let i = 0; i < s.length; i++) { + const str1 = expand(s, i, i); + if (str1.length > ans.length) ans = str1; + + if (s[i] === s[i + 1]) { + const str2 = expand(s, i, i + 1); + if (str2.length > ans.length) ans = str2; + } + } + return ans; + + // ************************************************** + function expand(s, l, r) { + while (l >= 0 && r < s.length && s[l] === s[r]) { + l--; + r++; + } + return s.slice(l + 1, r); + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/day-42.md b/medium/day-42.md deleted file mode 100644 index 1e8c6cd..0000000 --- a/medium/day-42.md +++ /dev/null @@ -1,434 +0,0 @@ -# 677.键值映射 - -https://leetcode-cn.com/problems/map-sum-pairs - -- HashMap -- Trie -- Trie (优化版) -- Trie + HashMap -- Trie + HashMap (优化版) - -## 题目描述 - -``` -实现一个 MapSum 类里的两个方法,insert 和 sum。 - -对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。 - -对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。 - -示例 1: - -输入: insert("apple", 3), 输出: Null -输入: sum("ap"), 输出: 3 -输入: insert("app", 2), 输出: Null -输入: sum("ap"), 输出: 5 - -来源:力扣(LeetCode) -链接:https://leetcode-cn.com/problems/map-sum-pairs -著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 -``` - -## HashMap - -### 复杂度分析 - -- 时间复杂度:`insert` 是 $O(1)$ (不考虑哈希冲突的话),`sum` 是 $O(n*len(prefix))$,n 是 hashmap 的 key 总数,prefix 是要查找的前缀。 -- 空间复杂度:$O(n)$,n 是字符串的数量, - -### 代码 - -Python Code - -```py -class MapSum(object): - def __init__(self): - """ - Initialize your data structure here. - """ - self.hashmap = {} - - def insert(self, key, val): - """ - :type key: str - :type val: int - :rtype: None - """ - self.hashmap[key] = val - - def sum(self, prefix): - """ - :type prefix: str - :rtype: int - """ - res = 0 - for key in self.hashmap: - if key.startswith(prefix): - res += self.hashmap[key] - return res - - - -# Your MapSum object will be instantiated and called as such: -# obj = MapSum() -# obj.insert(key,val) -# param_2 = obj.sum(prefix) -``` - -## Trie - -### 思路 - -- 构建前缀树。 -- `sum` 操作的时候,先判断 `prefix` 是否存在前缀树中,然后找到 `prefix` 最后的节点,开始 DFS。 - -**DFS** - -- **大问题**:`dfs(node)` 应该要返回以这个节点开始的所有路径中的 `value` 的和。 -- **小问题**:`dfs(node.child)`,先找到以 `node` 的子节点开始的所有路径中的 `value` 的和。不过由于 `node` 有很多子节点,所以我们需要一个循环。 -- **大问题与小问题的关系**:当我们求出了全部 `dfs(node.child)`,那么 - - - `dfs(node) = node.value + dfs(node.child1) + dfs(node.child2) + ...` - -- **递归出口**:如果节点不存在,我们直接返回 0,停止递归。 - -### 复杂度分析 - -- 时间复杂度:`insert` 操作的时间复杂度是 $O(len(key))$,`sum` 操作的时间复杂度是 $O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。 -- 空间复杂度:$O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。 - -### 代码 - -TypeScript Code - -```ts -class TrieNode { - value: number - children: Array - - constructor(value: number) { - this.value = value - this.children = Array(26) - } -} - -class MapSum { - private root: TrieNode - - constructor() { - this.root = this._getTrieNode(0) - } - - private _getTrieNode(value: number): TrieNode { - return new TrieNode(value) - } - - private _char2Index(char: string): number { - return char.toLowerCase().charCodeAt(0) - 97 - } - - insert(key: string, val: number): void { - let crawl: TrieNode = this.root - for (let char of key) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) { - crawl.children[index] = this._getTrieNode(0) - } - crawl = crawl.children[index] - } - crawl.value = val - } - - private _dfs(crawl: TrieNode): number { - if (!crawl) return 0 - - return crawl.children.reduce( - (res: number, pointer: TrieNode): number => { - return res + (pointer ? this._dfs(pointer) : 0) - }, - crawl.value, - ) - } - - sum(prefix: string): number { - let crawl: TrieNode = this.root - for (let char of prefix) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return 0 - crawl = crawl.children[index] - } - return this._dfs(crawl) - } -} - -/** - * Your MapSum object will be instantiated and called as such: - * var obj = new MapSum() - * obj.insert(key,val) - * var param_2 = obj.sum(prefix) - */ -``` - -## Trie (优化版) - -在每个节点上存 `prefixSum`,可以把 `sum` 操作的时间复杂度降到 $O(1)$,代价是在 `insert` 的时候需要先检查 key 是否已经存在,存在的话要想从 `prefixSum` 中减去旧的 value,再加上新的 value。 - -### 复杂度分析 - -- 时间复杂度:`insert` 操作的时间复杂度是 $O(len(key))$,具体来说是 $O(2*len(key))$,一次查找 key 是否存在前缀树中,一次插入。`sum` 操作的时间复杂度是 $O(1)$。 -- 空间复杂度:$O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。 - -### 代码 - -```ts -class TrieNode { - value: number - prefixSum: number - children: Array - - constructor(value: number) { - this.value = value - this.prefixSum = 0 - this.children = Array(26) - } -} - -class MapSum { - private root: TrieNode - - constructor() { - this.root = this._getTrieNode(0) - } - - private _getTrieNode(value: number): TrieNode { - return new TrieNode(value) - } - - private _char2Index(char: string): number { - return char.toLowerCase().charCodeAt(0) - 97 - } - - search(key: string): number { - let crawl: TrieNode = this.root - for (let char of key) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return 0 - crawl = crawl.children[index] - } - return crawl.value - } - - insert(key: string, val: number): void { - let crawl: TrieNode = this.root - const existedVal: number = this.search(key) - for (let char of key) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) { - crawl.children[index] = this._getTrieNode(0) - } - crawl = crawl.children[index] - crawl.prefixSum = crawl.prefixSum - existedVal + val - } - crawl.value = val - } - - sum(prefix: string): number { - let crawl: TrieNode = this.root - - for (let char of prefix) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return 0 - crawl = crawl.children[index] - } - return crawl.prefixSum - } -} - -/** - * Your MapSum object will be instantiated and called as such: - * var obj = new MapSum() - * obj.insert(key,val) - * var param_2 = obj.sum(prefix) - */ -``` - -## Trie + HashMap - -### 思路 - -把以某个前缀开始的 `key` 相应的 `value`,以 hashmap 的形式存在这个前缀的最后一个节点中。比如, - -- 我们先插入了一个 `(dark, 3)`, -- 然后再插入一个 `(darkest, 2)`, -- 那这时表示 `k` 的那个节点的 hashmap 应该是这样: - - `{ dark: 3, darkest: 2 }` -- 这时如果我们再次插入 `(darkest, 5)`,覆盖了之前的值,那 `k` 节点的 hashmap 就变成了: - - `{ dark: 3, darkest: 5 }` - -> 当然,d, a, r 节点上的数据结构也和 k 节点一样 - -现在,我们的 `sum` 操作就变成了: - -1. 找到 `prefix` 的结束节点。 -2. 计算这个节点中的 hashmap 的 `value` 和。 - -不过我们还可以继续优化一点,在存 hashmap 的时候,也顺便存一个 `prefixSum`,也就是上述第 2 步得到的值。当我们往前缀树插入重复的 `key` 时,由于有 hashmap 的存在,我们就可以从 `prefixSum` 中删除这个 `key` 对应的旧的 `value`,然后加上新的 `value`。 - -### 复杂度分析 - -- 时间复杂度:`insert` 是 $O(len(key))$,`sum` 是 $O(len(prefix))$。 -- 空间复杂度:Trie 的空间复杂度是 $O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。然后每个节点还有一个 hashmap,这个,怎么算啊? - -### 代码 - -TypeScript Code - -```ts -class TrieNode { - value: number - prefixSum: number - prefixMap: { - [key: string]: number - } - children: Array - - constructor(value: number) { - this.value = value - this.prefixSum = 0 - this.prefixMap = {} - this.children = Array(26) - } -} - -class MapSum { - private root: TrieNode - - constructor() { - this.root = this._getTrieNode(0) - } - - private _getTrieNode(value: number): TrieNode { - return new TrieNode(value) - } - - private _char2Index(char: string): number { - return char.toLowerCase().charCodeAt(0) - 97 - } - - insert(key: string, val: number): void { - let crawl: TrieNode = this.root - for (let char of key) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) { - crawl.children[index] = this._getTrieNode(0) - } - crawl = crawl.children[index] - if (key in crawl.prefixMap) { - crawl.prefixSum -= crawl.prefixMap[key] - } - crawl.prefixMap[key] = val - crawl.prefixSum += val - } - crawl.value = val - } - - sum(prefix: string): number { - let crawl: TrieNode = this.root - - for (let char of prefix) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return 0 - crawl = crawl.children[index] - } - return crawl.prefixSum - } -} - -/** - * Your MapSum object will be instantiated and called as such: - * var obj = new MapSum() - * obj.insert(key,val) - * var param_2 = obj.sum(prefix) - */ -``` - -## Trie + HashMap (优化版 1) - -### 思路 - -上一个方法中其实没有必要把 hashmap 放到每个节点中,只需要用一个全局的 hashmap 来记录前缀树已存在的 key 就好了。 - -### 代码 - -```ts -class TrieNode { - value: number - prefixSum: number - children: Array - - constructor(value: number) { - this.value = value - this.prefixSum = 0 - this.children = Array(26) - } -} - -class MapSum { - private root: TrieNode - private existedWords: { - [key: string]: number - } - - constructor() { - this.root = this._getTrieNode(0) - this.existedWords = {} - } - - private _getTrieNode(value: number): TrieNode { - return new TrieNode(value) - } - - private _char2Index(char: string): number { - return char.toLowerCase().charCodeAt(0) - 97 - } - - insert(key: string, val: number): void { - let crawl: TrieNode = this.root - for (let char of key) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) { - crawl.children[index] = this._getTrieNode(0) - } - crawl = crawl.children[index] - if (key in this.existedWords) { - crawl.prefixSum -= this.existedWords[key] - } - crawl.prefixSum += val - } - this.existedWords[key] = val - crawl.value = val - } - - sum(prefix: string): number { - let crawl: TrieNode = this.root - - for (let char of prefix) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return 0 - crawl = crawl.children[index] - } - return crawl.prefixSum - } -} - -/** - * Your MapSum object will be instantiated and called as such: - * var obj = new MapSum() - * obj.insert(key,val) - * var param_2 = obj.sum(prefix) - */ -``` - -**官方题解** - -https://github.com/leetcode-pp/91alg-1/issues/69#issuecomment-657210282 diff --git a/medium/day-47.md b/medium/day-47.md deleted file mode 100644 index 7a44a35..0000000 --- a/medium/day-47.md +++ /dev/null @@ -1,54 +0,0 @@ -# 1206.设计跳表 - -https://leetcode-cn.com/problems/design-skiplist - -## 题目描述 - -``` -不使用任何库函数,设计一个跳表。 - -跳表是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。 - -例如,一个跳表包含 [30, 40, 50, 60, 70, 90],然后增加 80、45 到跳表中,以下图的方式操作: - - - -Artyom Kalinin [CC BY-SA 3.0], via Wikimedia Commons - -跳表中有很多层,每一层是一个短的链表。在第一层的作用下,增加、删除和搜索操作的时间复杂度不超过 O(n)。跳表的每一个操作的平均时间复杂度是 O(log(n)),空间复杂度是 O(n)。 - -在本题中,你的设计应该要包含这些函数: - -bool search(int target) : 返回target是否存在于跳表中。 -void add(int num): 插入一个元素到跳表。 -bool erase(int num): 在跳表中删除一个值,如果 num 不存在,直接返回false. 如果存在多个 num ,删除其中任意一个即可。 -了解更多 : https://en.wikipedia.org/wiki/Skip_list - -注意,跳表中可能存在多个相同的值,你的代码需要处理这种情况。 - -样例: - -Skiplist skiplist = new Skiplist(); - -skiplist.add(1); -skiplist.add(2); -skiplist.add(3); -skiplist.search(0); // 返回 false -skiplist.add(4); -skiplist.search(1); // 返回 true -skiplist.erase(0); // 返回 false,0 不在跳表中 -skiplist.erase(1); // 返回 true -skiplist.search(1); // 返回 false,1 已被擦除 -约束条件: - -0 <= num, target <= 20000 -最多调用 50000 次 search, add, 以及 erase操作。 - -来源:力扣(LeetCode) -链接:https://leetcode-cn.com/problems/design-skiplist -著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 -``` - -**参考题解** - -https://github.com/leetcode-pp/91alg-1/issues/74#issuecomment-660018285 diff --git a/medium/dp/number-of-longest-increasing-subsequence.md b/medium/dp/number-of-longest-increasing-subsequence.md new file mode 100644 index 0000000..d3ef10f --- /dev/null +++ b/medium/dp/number-of-longest-increasing-subsequence.md @@ -0,0 +1,106 @@ +# 673. 最长递增子序列的个数 + +https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/ + +## 题目描述 + +``` +给定一个未排序的整数数组,找到最长递增子序列的个数。 + +示例 1: + +输入: [1,3,5,4,7] +输出: 2 +解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。 +示例 2: + +输入: [2,2,2,2,2] +输出: 5 +解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。 +注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:动态规划 + +### 思路 + + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @return {number} + */ +var findNumberOfLIS = function (nums) { + const n = nums.length; + const length = Array.from({ length: n }).fill(1); + const count = Array.from({ length: n }).fill(1); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (nums[j] >= nums[i]) continue; + + if (length[j] + 1 > length[i]) { + length[i] = length[j] + 1; + count[i] = count[j]; + } else if (length[j] + 1 == length[i]) { + count[i] += count[j]; + } + } + } + + const longest = Math.max(...length); + return length.reduce( + (cnt, len, i) => (len == longest ? cnt + count[i] : cnt), + 0 + ); +}; +``` + +C++ Code + +```cpp +class Solution { +public: + int findNumberOfLIS(vector& nums) { + int n = nums.size(); + vector length(n, 1); + vector count(n, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] <= nums[j]) continue; + + if (length[j] + 1 > length[i]) { + length[i] = length[j] + 1; + count[i] = count[j]; + } + else if (length[j] + 1 == length[i]) { + count[i] += count[j]; + } + } + } + + int longest = *max_element(length.begin(), length.end()); + int ans = 0; + for (int i = 0; i < n; i++) { + if (length[i] == longest) { + ans += count[i]; + } + } + return ans; + } +}; +``` + +### 复杂度分析 + +- 时间复杂度:$O(N^2)$。N 是数组 `nums` 的长度。 +- 空间复杂度:$O(N)$。N 是辅助数组 `length` 和 `count` 的长度。 \ No newline at end of file diff --git a/basic/hashmap/ext-kth-largest-element-in-an-array.md b/medium/heap/54.kth-largest-element-in-an-array.md similarity index 100% rename from basic/hashmap/ext-kth-largest-element-in-an-array.md rename to medium/heap/54.kth-largest-element-in-an-array.md diff --git a/medium/heap/55.last-stone-weight.md b/medium/heap/55.last-stone-weight.md new file mode 100644 index 0000000..7fda019 --- /dev/null +++ b/medium/heap/55.last-stone-weight.md @@ -0,0 +1,148 @@ +# 1046. 最后一块石头的重量 + +https://leetcode-cn.com/problems/last-stone-weight/ + +- [1046. 最后一块石头的重量](#1046-最后一块石头的重量) + - [题目描述](#题目描述) + - [方法1:大顶堆](#方法1大顶堆) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +有一堆石头,每块石头的重量都是正整数。 + +每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下: + +如果 x == y,那么两块石头都会被完全粉碎; +如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。 +最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。 + +  + +示例: + +输入:[2,7,4,1,8,1] +输出:1 +解释: +先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1], +再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1], +接着是 2 和 1,得到 1,所以数组转换为 [1,1,1], +最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。 +  + +提示: + +1 <= stones.length <= 30 +1 <= stones[i] <= 1000 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/last-stone-weight +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:大顶堆 + +### 思路 + +直接用大顶堆来模拟粉碎石头的游戏。 + +### 复杂度分析 + +- 时间复杂度:$O(nlogn)$,n 是数组大小,最坏的情况是,每回合粉碎两块石头之后,都有一颗新的小石头生成。 +- 空间复杂度:$O(n)$,n 是数组大小。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} stones + * @return {number} + */ +var lastStoneWeight = function(stones) { + const heap = new MaxHeap(stones); + + while (heap.size() > 1) { + const first = heap.pop(); + const second = heap.pop(); + if (first > second) heap.insert(first - second) + } + return heap.size() ? heap.pop() : 0; +}; + +// ************************************************** + +class Heap { + constructor(list = [], comparator) { + this.list = list; + this.comparator = comparator; + + this.init(); + } + + init() { + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + insert(n) { + this.list.push(n); + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + peek() { + return this.list[0]; + } + + pop() { + const last = this.list.pop(); + if (this.size() === 0) return last; + const returnItem = this.list[0]; + this.list[0] = last; + this.heapify(this.list, this.size(), 0); + return returnItem; + } + + size() { + return this.list.length; + } +} + +class MaxHeap extends Heap { + constructor(list, comparator) { + if (typeof comparator != 'function') { + comparator = function comparator(inserted, compared) { + return inserted < compared; + }; + } + super(list, comparator); + } + + heapify(arr, size, i) { + let largest = i; + const left = Math.floor(i * 2 + 1); + const right = Math.floor(i * 2 + 2); + + if (left < size && this.comparator(arr[largest], arr[left])) + largest = left; + if (right < size && this.comparator(arr[largest], arr[right])) + largest = right; + + if (largest !== i) { + [arr[largest], arr[i]] = [arr[i], arr[largest]]; + this.heapify(arr, size, largest); + } + } +} +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/heap/56.merge-k-sorted-lists.md b/medium/heap/56.merge-k-sorted-lists.md new file mode 100644 index 0000000..3a2607b --- /dev/null +++ b/medium/heap/56.merge-k-sorted-lists.md @@ -0,0 +1,386 @@ +# 23. 合并K个升序链表 + +https://leetcode-cn.com/problems/merge-k-sorted-lists/ + +- [23. 合并K个升序链表](#23-合并k个升序链表) + - [题目描述](#题目描述) + - [方法1:顺序合并](#方法1顺序合并) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码(JavaScript/C++)](#代码javascriptc) + - [方法2:顺序合并+堆](#方法2顺序合并堆) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码) + - [方法3:分治](#方法3分治) + - [思路](#思路-2) + - [复杂度分析](#复杂度分析-2) + - [代码(JavaScript/C++)](#代码javascriptc-1) + +## 题目描述 + +``` +给你一个链表数组,每个链表都已经按升序排列。 + +请你将所有链表合并到一个升序链表中,返回合并后的链表。 + +  + +示例 1: + +输入:lists = [[1,4,5],[1,3,4],[2,6]] +输出:[1,1,2,3,4,4,5,6] +解释:链表数组如下: +[ + 1->4->5, + 1->3->4, + 2->6 +] +将它们合并到一个有序链表中得到。 +1->1->2->3->4->4->5->6 +示例 2: + +输入:lists = [] +输出:[] +示例 3: + +输入:lists = [[]] +输出:[] +  + +提示: + +k == lists.length +0 <= k <= 10^4 +0 <= lists[i].length <= 500 +-10^4 <= lists[i][j] <= 10^4 +lists[i] 按 升序 排列 +lists[i].length 的总和不超过 10^4 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/merge-k-sorted-lists +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:顺序合并 + +### 思路 + +跟 [21.合并两个有序链表](../../problems/0021.merge-two-sorted-lists.md) 的基本思路是一样的,只不过每轮操作需要比较 k 个链表节点的值。 + +### 复杂度分析 + +- 时间复杂度:$O(k*n)$,k 是链表个数,n 是合并后链表的长度。 +- 空间复杂度:$O(1)$。 + +### 代码(JavaScript/C++) + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +var mergeKLists = function (lists) { + if (!lists || !lists.length) return null; + + let dummy = new ListNode(); + let tail = dummy; + + while (!isEmpty(lists)) { + const min = getMin(lists); + tail.next = new ListNode(min.val); + tail = tail.next; + } + + return dummy.next; + + // ********************************************** + function getMin(lists) { + let minIndex = -1, + minNode = new ListNode(Infinity); + + for (let i = 0; i < lists.length; i++) { + const node = lists[i]; + if (node && node.val < minNode.val) { + minNode = node; + minIndex = i; + } + } + + lists[minIndex] = minNode.next; + return minNode; + } + + function isEmpty(lists) { + return lists.every(n => n === null); + } +}; +``` + +C++ code + +```cpp +/** + * 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 { +private: + bool isEmpty_(vector& lists) { + for (int i = 0; i < lists.size(); i++) { + if (lists[i]) return false; + } + return true; + } + int getMinVal_(vector& lists) { + int ans = INT_MAX; + int idx = -1; + for (int i = 0; i < lists.size(); i++) { + if (lists[i] && lists[i]->val < ans) { + ans = lists[i]->val; + idx = i; + } + } + lists[idx] = lists[idx]->next; + return ans; + } + +public: + ListNode* mergeKLists(vector& lists) { + ListNode* dummy = new ListNode(); + ListNode* tail = dummy; + + while (!isEmpty_(lists)) { + int min_val = getMinVal_(lists); + tail->next = new ListNode(min_val); + tail = tail->next; + } + + return dummy->next; + } +}; +``` + +## 方法2:顺序合并+堆 + +### 思路 + +跟 方法1 思路一致,不过用了堆来寻找 k 个链表节点中的最小值。 + +### 复杂度分析 + +- 时间复杂度:$O(nlogk)$,k 是链表个数,n 是合并后链表的长度。 +- 空间复杂度:$O(k)$,k 是链表个数,堆的空间大小。 + +### 代码 + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +var mergeKLists = function (lists) { + if (!lists || !lists.length) return null; + + let dummy = new ListNode(); + let tail = dummy; + + const heap = new MinHeap(lists.filter(Boolean), function comparator(inserted, compared) { + return inserted.val > compared.val; + }); + + while (heap.size() > 0) { + const min = heap.pop(); + tail.next = new ListNode(min.val); + tail = tail.next; + min.next && heap.insert(min.next) + } + + return dummy.next; +}; + +// ************************************************** + +class Heap { + constructor(list = [], comparator) { + this.list = list; + this.comparator = comparator; + + this.init(); + } + + init() { + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + insert(n) { + this.list.push(n); + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + peek() { + return this.list[0]; + } + + pop() { + const last = this.list.pop(); + if (this.size() === 0) return last; + const returnItem = this.list[0]; + this.list[0] = last; + this.heapify(this.list, this.size(), 0); + return returnItem; + } + + size() { + return this.list.length; + } +} + +class MinHeap extends Heap { + constructor(list, comparator) { + if (typeof comparator != 'function') { + comparator = function comparator(inserted, compared) { + return inserted > compared; + }; + } + super(list, comparator); + } + + heapify(arr, size, i) { + let smallest = i; + const left = Math.floor(i * 2 + 1); + const right = Math.floor(i * 2 + 2); + if (left < size && this.comparator(arr[smallest], arr[left])) + smallest = left; + if (right < size && this.comparator(arr[smallest], arr[right])) + smallest = right; + + if (smallest !== i) { + [arr[smallest], arr[i]] = [arr[i], arr[smallest]]; + this.heapify(arr, size, smallest); + } + } +} +``` + +## 方法3:分治 + +### 思路 + +- 将 k 个链表平均分成两份,分别进行合并后,再将两个结果进行合并。 +- 最后一步就是简单的 [合并两个有序链表](../../problems/0021.merge-two-sorted-lists.md)。 +- 而中间的步骤也很简单,只需要将 k/2 个链表再细分,再细分,细分到一次只需要处理两个链表就好了。 + +### 复杂度分析 + +- 时间复杂度:$O(nlogk)$,k 是链表个数,n 是合并后链表的长度。 +- 空间复杂度:$O(k)$,k 是链表个数,堆的空间大小。 + +### 代码(JavaScript/C++) + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +var mergeKLists = function(lists, start = 0, end = lists.length - 1) { + if (start > end) return null; + if (start === end) return lists[start]; + const mid = ((end - start) >> 1) + start; + return mergeTwoLists(mergeKLists(lists, start, mid), mergeKLists(lists, mid + 1, end)); +}; + +function mergeTwoLists(l1, l2) { + if (!l1) return l2; + if (!l2) return l1; + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } +} +``` + +C++ Code + +```cpp +/** + * 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* mergeKLists(vector& lists) { + return mergeKLists(lists, 0, lists.size() - 1); + } + + ListNode* mergeKLists(vector& lists, int start, int end) { + if (start > end) return nullptr; + if (start == end) return lists[start]; + int m = (end - start) / 2 + start; + return merge2Lists(mergeKLists(lists, start, m), mergeKLists(lists, m + 1, end)); + } + + ListNode* merge2Lists(ListNode* l1, ListNode* l2) { + if (!l1) return l2; + if (!l2) return l1; + if (l1->val < l2->val) { + l1->next = merge2Lists(l1->next, l2); + return l1; + } else { + l2->next = merge2Lists(l1, l2->next); + return l2; + } + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/heap/57.sort-characters-by-frequency.md b/medium/heap/57.sort-characters-by-frequency.md new file mode 100644 index 0000000..5464b8a --- /dev/null +++ b/medium/heap/57.sort-characters-by-frequency.md @@ -0,0 +1,166 @@ +# 451. 根据字符出现频率排序 + +https://leetcode-cn.com/problems/sort-characters-by-frequency/ + +- [451. 根据字符出现频率排序](#451-根据字符出现频率排序) + - [题目描述](#题目描述) + - [方法1:哈希表+堆](#方法1哈希表堆) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +给定一个字符串,请将字符串里的字符按照出现的频率降序排列。 + +示例 1: + +输入: +"tree" + +输出: +"eert" + +解释: +'e'出现两次,'r'和't'都只出现一次。 +因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。 +示例 2: + +输入: +"cccaaa" + +输出: +"cccaaa" + +解释: +'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。 +注意"cacaca"是不正确的,因为相同的字母必须放在一起。 +示例 3: + +输入: +"Aabb" + +输出: +"bbAa" + +解释: +此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。 +注意'A'和'a'被认为是两种不同的字符。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/sort-characters-by-frequency +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:哈希表+堆 + +### 思路 + +- 用哈希表来记录每个字符的出现次数 +- 以字符出现次数建立一个大顶堆 +- 一边弹出堆顶,一边构建新的字符串 + +### 复杂度分析 + +- 时间复杂度:$O(n+klogk)$,n 是字符串的长度,k 是字符串中字符集的大小。 +- 空间复杂度:$O(k)$,k 是字符串中字符集的大小,堆的大小。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {string} s + * @return {string} + */ +var frequencySort = function (s) { + const map = {} + + for (let i = 0; i < s.length; i++) { + const c = s[i]; + map[c] = (map[c] || 0) + 1 + } + + // 堆的数据结构 [char, count] + const list = Object.keys(map).map(c => [c, map[c]]) + const heap = new MaxHeap(list, function comparator(inserted, compared) { + return inserted[1] < compared[1]; + }); + + let str = '' + while (heap.size() > 0) { + const [char, cnt] = heap.pop(); + str += char.repeat(cnt) + } + return str +}; + +// ************************************************** + +class Heap { + constructor(list = [], comparator) { + this.list = list; + this.comparator = comparator; + + this.init(); + } + + init() { + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + insert(n) { + this.list.push(n); + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + peek() { + return this.list[0]; + } + + pop() { + const last = this.list.pop(); + if (this.size() === 0) return last; + const returnItem = this.list[0]; + this.list[0] = last; + this.heapify(this.list, this.size(), 0); + return returnItem; + } + + size() { + return this.list.length; + } +} + +class MaxHeap extends Heap { + constructor(list, comparator) { + super(list, comparator); + } + + heapify(arr, size, i) { + let largest = i; + const left = Math.floor(i * 2 + 1); + const right = Math.floor(i * 2 + 2); + + if (left < size && this.comparator(arr[largest], arr[left])) + largest = left; + if (right < size && this.comparator(arr[largest], arr[right])) + largest = right; + + if (largest !== i) { + [arr[largest], arr[i]] = [arr[i], arr[largest]]; + this.heapify(arr, size, largest); + } + } +} +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/heap/58.kth-smallest-element-in-a-sorted-matrix.md b/medium/heap/58.kth-smallest-element-in-a-sorted-matrix.md new file mode 100644 index 0000000..8d515aa --- /dev/null +++ b/medium/heap/58.kth-smallest-element-in-a-sorted-matrix.md @@ -0,0 +1,201 @@ +# 378. 有序矩阵中第K小的元素 + +https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/ + +- [378. 有序矩阵中第K小的元素](#378-有序矩阵中第k小的元素) + - [题目描述](#题目描述) + - [方法1:归并排序](#方法1归并排序) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法2:归并排序+堆](#方法2归并排序堆) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) + +## 题目描述 + +``` +给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。 +请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。 + +  + +示例: + +matrix = [ + [ 1, 5, 9], + [10, 11, 13], + [12, 13, 15] +], +k = 8, + +返回 13。 +  + +提示: +你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:归并排序 + +### 思路 + +矩阵的每一行都是一个升序的数组,用合并多个有序数组的思路,找出前 k 个最小的元素就行。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/378_0.png) + +用 n 个指针来记录每一行当前最小元素。 + +### 复杂度分析 + +- 时间复杂度:$O(k*n)$,n 是矩阵宽高,其中 k 最坏的情况下是 $n^2$,所以最坏的时间复杂度是 $O(n^3)$。 +- 空间复杂度:$O(n)$,指针数组的长度。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +var kthSmallest = function (matrix, k) { + const rows = matrix.length; + const cols = matrix[0].length + const indices = Array(rows).fill(0); + + let kth; + while (k-- > 0) { + let min = Infinity + let minRow = -1 + for (let r = 0; r < rows; r++) { + if (indices[r] >= cols) continue + + const num = matrix[r][indices[r]]; + if (num <= min) { + min = num; + minRow = r + } + } + kth = min + indices[minRow]++; + } + return kth; +}; +``` + +## 方法2:归并排序+堆 + +### 思路 + +还是上一个方法的思路,只不过在寻找多行中的最小值时,不用循环查找,而是用堆将这个查找时间从 n 降到 logn。 + +### 复杂度分析 + +- 时间复杂度:$O(k*logn)$,n 是矩阵宽高,其中 k 最坏的情况下是 $n^2$,所以最坏的时间复杂度是 $O(n^2*logn)$。 +- 空间复杂度:$O(n)$,堆的大小。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +var kthSmallest = function (matrix, k) { + const list = matrix.map((row, x) => [row[0], x, 0]); + // 堆中的数据结构是 [num, x, y] + const heap = new MinHeap(list, function comparator(inserted, compared) { + return inserted[0] > compared[0]; + }); + + while (k-- > 1) { + const [, x, y] = heap.pop(); + if (y < matrix[0].length - 1) { + heap.insert([matrix[x][y + 1], x, y + 1]); + } + } + return heap.pop()[0]; +}; + +// ************************************************** + +class Heap { + constructor(list = [], comparator) { + this.list = list; + this.comparator = comparator; + + this.init(); + } + + init() { + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + insert(n) { + this.list.push(n); + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + peek() { + return this.list[0]; + } + + pop() { + const last = this.list.pop(); + if (this.size() === 0) return last; + const returnItem = this.list[0]; + this.list[0] = last; + this.heapify(this.list, this.size(), 0); + return returnItem; + } + + size() { + return this.list.length; + } +} + +class MinHeap extends Heap { + constructor(list, comparator) { + if (typeof comparator != 'function') { + comparator = function comparator(inserted, compared) { + return inserted > compared; + }; + } + super(list, comparator); + } + + heapify(arr, size, i) { + let smallest = i; + const left = Math.floor(i * 2 + 1); + const right = Math.floor(i * 2 + 2); + if (left < size && this.comparator(arr[smallest], arr[left])) + smallest = left; + if (right < size && this.comparator(arr[smallest], arr[right])) + smallest = right; + + if (smallest !== i) { + [arr[smallest], arr[i]] = [arr[i], arr[smallest]]; + this.heapify(arr, size, smallest); + } + } +} +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/heap/59.distant-barcodes.md b/medium/heap/59.distant-barcodes.md new file mode 100644 index 0000000..ed651ad --- /dev/null +++ b/medium/heap/59.distant-barcodes.md @@ -0,0 +1,268 @@ +# 1054. 距离相等的条形码 + +https://leetcode-cn.com/problems/distant-barcodes/ + +- [1054. 距离相等的条形码](#1054-距离相等的条形码) + - [题目描述](#题目描述) + - [方法1:直接排序](#方法1直接排序) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法2:堆排序](#方法2堆排序) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) + - [方法3](#方法3) + - [思路](#思路-2) + - [复杂度分析](#复杂度分析-2) + - [代码](#代码-2) + +## 题目描述 + +``` +在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]。 + +请你重新排列这些条形码,使其中两个相邻的条形码 不能 相等。 你可以返回任何满足该要求的答案,此题保证存在答案。 + +  + +示例 1: + +输入:[1,1,1,2,2,2] +输出:[2,1,2,1,2,1] +示例 2: + +输入:[1,1,1,1,2,2,3,3] +输出:[1,3,1,3,2,1,2,1] +  + +提示: + +1 <= barcodes.length <= 10000 +1 <= barcodes[i] <= 10000 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/distant-barcodes +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1:直接排序 + +### 思路 + +- 统计条形码的出现次数,按出现次数排序 +- 取出现次数最多的条形码,填充偶数位(0, 2, 4...) +- 重复上一步骤直到偶数位填充完毕,然后开始填充奇数位(1, 3, 5...) + +### 复杂度分析 + +- 时间复杂度:$O(NlogN)$,N 是 barcodes 的长度,统计条形码出现次数的时间是 $O(N)$,排序时间是 $O(klogk)$,k 是条形码总数,k 最坏情况下是 N。 +- 空间复杂度:$O(N)$,哈希表的空间,最坏的情况是每个条形码都不一样。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} barcodes + * @return {number[]} + */ +var rearrangeBarcodes = function (barcodes) { + const map = {}; + + for (let i = 0; i < barcodes.length; i++) { + const barcode = barcodes[i]; + map[barcode] = (map[barcode] || 0) + 1; + } + + const list = Object.keys(map).map(b => [Number(b), map[b]]); + list.sort((a, b) => a[1] - b[1]) + + const res = Array(barcodes.length); + let i = 0; + + while (list.length) { + let [barcode, count] = list.pop(); + + while (count-- > 0) { + if (i >= barcodes.length) i = 1; + + res[i] = barcode; + i += 2; + } + } + return res; +}; +``` + +## 方法2:堆排序 + +### 思路 + +- 统计条形码的出现次数,建堆 +- 从堆中取出现次数最多的条形码,填充偶数位(0, 2, 4...) +- 重复上一步骤直到偶数位填充完毕,然后开始填充奇数位(1, 3, 5...) + +### 复杂度分析 + +- 时间复杂度:$O(NlogN)$,N 是 barcodes 的长度,统计条形码出现次数的时间是 $O(N)$,每个条形码入堆出堆一次,时间是 $O(NlogN)$。 +- 空间复杂度:$O(N)$,哈希表的空间。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} barcodes + * @return {number[]} + */ +var rearrangeBarcodes = function (barcodes) { + const map = {}; + + for (let i = 0; i < barcodes.length; i++) { + const barcode = barcodes[i]; + map[barcode] = (map[barcode] || 0) + 1; + } + + // 堆的数据结构 [barcode, count] + const list = Object.keys(map).map(b => [Number(b), map[b]]); + const heap = new MaxHeap(list, function comparator(inserted, compared) { + return inserted[1] < compared[1]; + }); + + const res = Array(barcodes.length); + let i = 0; + + while (heap.size() > 0) { + let [barcode, count] = heap.pop(); + + while (count-- > 0) { + if (i >= barcodes.length) i = 1; + + res[i] = barcode; + i += 2; + } + } + return res; +}; + +// ************************************************** + +class Heap { + constructor(list = [], comparator) { + this.list = list; + this.comparator = comparator; + + this.init(); + } + + init() { + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + insert(n) { + this.list.push(n); + const size = this.size(); + for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { + this.heapify(this.list, size, i); + } + } + + peek() { + return this.list[0]; + } + + pop() { + const last = this.list.pop(); + if (this.size() === 0) return last; + const returnItem = this.list[0]; + this.list[0] = last; + this.heapify(this.list, this.size(), 0); + return returnItem; + } + + size() { + return this.list.length; + } +} + +class MaxHeap extends Heap { + constructor(list, comparator) { + super(list, comparator); + } + + heapify(arr, size, i) { + let largest = i; + const left = Math.floor(i * 2 + 1); + const right = Math.floor(i * 2 + 2); + + if (left < size && this.comparator(arr[largest], arr[left])) + largest = left; + if (right < size && this.comparator(arr[largest], arr[right])) + largest = right; + + if (largest !== i) { + [arr[largest], arr[i]] = [arr[i], arr[largest]]; + this.heapify(arr, size, largest); + } + } +} +``` + +## 方法3 + +### 思路 + +- 统计条形码的出现次数,建堆 +- 每次从堆中取两个出现次数最多的条形码,将它们加入排列结果中,然后数量分别减一后重新入堆 +- 直到堆中元素少于两个 + +### 复杂度分析 + +- 时间复杂度:$O(NlogN)$,N 是 barcodes 的长度,统计条形码出现次数的时间是 $O(N)$,每个条形码入堆出堆一次,时间是 $O(NlogN)$。 +- 空间复杂度:$O(N)$,哈希表的空间,最坏的情况是每个条形码都不一样。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} barcodes + * @return {number[]} + */ +var rearrangeBarcodes = function (barcodes) { + const map = {}; + + for (let i = 0; i < barcodes.length; i++) { + const barcode = barcodes[i]; + map[barcode] = (map[barcode] || 0) + 1; + } + + // 堆的数据结构 [barcode, count] + const list = Object.keys(map).map(b => [Number(b), map[b]]); + const heap = new MaxHeap(list, function comparator(inserted, compared) { + return inserted[1] < compared[1]; + }); + + const res = []; + while (heap.size() > 1) { + let [b1, cnt1] = heap.pop(); + let [b2, cnt2] = heap.pop(); + res.push(b1, b2) + if (--cnt1 > 0) heap.insert([b1, cnt1]) + if (--cnt2 > 0) heap.insert([b2, cnt2]) + } + if (heap.size()) { + res.push(heap.pop()[0]); + } + return res +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/medium/day-48.md b/medium/prune/48.binary-tree-pruning.md similarity index 75% rename from medium/day-48.md rename to medium/prune/48.binary-tree-pruning.md index 6714aaa..ac219fe 100644 --- a/medium/day-48.md +++ b/medium/prune/48.binary-tree-pruning.md @@ -2,6 +2,12 @@ https://leetcode-cn.com/problems/binary-tree-pruning +- [814.二叉树剪枝](#814二叉树剪枝) + - [题目描述](#题目描述) + - [思路](#思路) + - [代码](#代码) + - [复杂度分析](#复杂度分析) + ## 题目描述 ``` @@ -35,7 +41,7 @@ https://leetcode-cn.com/problems/binary-tree-pruning ## 思路 -本题解由 lucifer 著名的[产品经理法](https://github.com/leetcode-pp/91alg-1/issues/32#issuecomment-643620727)倾情支持。 +用【产品经理法】的思维来解决递归问题。 **产品** @@ -43,11 +49,11 @@ https://leetcode-cn.com/problems/binary-tree-pruning **子问题** -明显就是 `pruneTree(root.left)` 和 `pruneTree(root.right)` 啦。 +明显是 `pruneTree(root.left)` 和 `pruneTree(root.right)`。 **大小问题的关系** -首先,我们用 `pruneTree(root.left)` 和 `pruneTree(root.right)` 的结果分别替换掉原本的左子树和右子树。接着,再决定这棵树要不要保留。 +首先,对于 `root`,我们用 `pruneTree(root.left)` 和 `pruneTree(root.right)` 的结果分别替换掉原本的 `root.left` 和 `root.right`。接着,再决定当前这棵树要不要保留。 - 如果此时左右子树有一个不为空的话,那说明这棵树是要保留的,直接返回 `root` 就行。 - 如果左右子树都为空,那我们就判断 `root.val` 的值,等于 1 就返回 `root`,等于 0 就返回 `null` 把这棵树移除。 @@ -76,20 +82,16 @@ TypeScript Code */ function pruneTree(root: TreeNode | null): TreeNode | null { - if (!root) return null + if (!root) return null; - root.left = pruneTree(root.left) - root.right = pruneTree(root.right) + root.left = pruneTree(root.left); + root.right = pruneTree(root.right); - return root.left || root.right || root.val === 1 ? root : null + return root.left || root.right || root.val === 1 ? root : null; } ``` ## 复杂度分析 - 时间复杂度:$O(N)$,N 为二叉树节点数。 -- 空间复杂度:$O(H)$,H 为二叉树的高度,递归时调用栈占用的最大空间就是二叉树的最大深度。 - -**参考题解** - -https://github.com/leetcode-pp/91alg-1/issues/75#issuecomment-660483924 +- 空间复杂度:$O(H)$,H 为二叉树的高度,递归栈的最大空间。 diff --git a/medium/day-49.md b/medium/prune/49.combination-sum.md similarity index 50% rename from medium/day-49.md rename to medium/prune/49.combination-sum.md index 3ae3c53..ac46655 100644 --- a/medium/day-49.md +++ b/medium/prune/49.combination-sum.md @@ -2,6 +2,13 @@ https://leetcode-cn.com/problems/combination-sum +- [39.组合总和](#39组合总和) + - [题目描述](#题目描述) + - [方法 1:回溯](#方法-1回溯) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + ## 题目描述 ``` @@ -44,7 +51,9 @@ candidate 中的每个元素都是独一无二的。 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 思路 +## 方法 1:回溯 + +### 思路 因为题目是求“所有可能的组合”,所以很自然想到了递归。感觉一提到组合我的第一反应就是,“对于每个元素,都有选与不选两种选择”,对每个元素分别作出选择后我们就得到了其中一个组合。 @@ -55,12 +64,15 @@ candidate 中的每个元素都是独一无二的。 - 不选:把数字从篮子里拿出来(回溯),然后对后面的数字进行递归(不包括当前数字) - 递归出口:如果篮子里的数字和大于 `target` 了,那我们就把这个篮子扔掉不管(剪枝);如果刚好等于 `target`,那就把篮子加到要返回的结果中,然后结束递归。 -## 复杂度分析 +### 复杂度分析 + +力扣官方的分析: -- 时间复杂度:时间复杂度我就从 n 叉树的角度来想吧,也不知道对不对,$O(len(candidates)^{target/min(candidates)})$。 -- 空间复杂度:调用栈的空间我感觉是 $O(target/min(candidates))$,一个组合最长的情况就是所有元素都是 min(candidate),所以返回结果的空间应该是......不会算了... +- 时间复杂度:$O(S)$,其中 S 为所有可行解的长度之和。从分析给出的搜索树我们可以看出时间复杂度取决于搜索树所有叶子节点的深度之和,即所有可行解的长度之和。在这题中,我们很难给出一个比较紧的上界,我们知道 $O(n*2^n)$ 是一个比较松的上界,即在这份代码中,n 个位置每次考虑选或者不选,如果符合条件,就加入答案的时间代价。但是实际运行的时候,因为不可能所有的解都满足条件,递归的时候我们还会用 `target - candidates[idx] >= 0` 进行剪枝,所以实际运行情况是远远小于这个上界的。 -## 代码 +- 空间复杂度:$O(target)$。除答案数组外,空间复杂度取决于递归的栈深度,在最差情况下需要递归 $O(target)$ 层。 + +### 代码 JavaScript Code @@ -72,25 +84,66 @@ JavaScript Code */ var combinationSum = function (candidates, target) { const dfs = (candidates, ans, remain, cur) => { - if (remain < 0) return + if (remain < 0) return; if (remain === 0) { - res.push(ans) - return + res.push(ans); + return; } while (cur < candidates.length) { if (candidates[cur] <= remain) { - ans.push(candidates[cur]) - dfs(candidates, [...ans], remain - candidates[cur], cur) - ans.pop() + ans.push(candidates[cur]); + dfs(candidates, [...ans], remain - candidates[cur], cur); + ans.pop(); } - cur++ + cur++; } - } + }; + + const res = []; + dfs(candidates, [], target, 0); + return res; +}; +``` + +JavaScript Code - const res = [] - dfs(candidates, [], target, 0) - return res -} +```js +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +var combinationSum = function (candidates, target) { + candidates.sort((a, b) => a - b); + const res = []; + dfs(candidates, 0, target); + return res; + + // ****************************************** + function dfs(arr, cur, target, tempArr = [], total = 0) { + if (total > target) return; + + if (total === target) { + res.push([...tempArr]); + return; + } + + // 因为数字可以重复选择,所以 i 从 cur 开始 + for (let i = cur; i < arr.length; i++) { + // 剪枝 + if (total + arr[cur] > target) break; + + // 选当前数字 + tempArr.push(arr[i]); + + // 递归决定选不选后面的数字 + dfs(arr, i, target, tempArr, total + arr[i]); + + // 不选当前数字 + tempArr.pop(); + } + } +}; ``` diff --git a/medium/day-50.md b/medium/prune/50.combination-sum-ii.md similarity index 100% rename from medium/day-50.md rename to medium/prune/50.combination-sum-ii.md diff --git a/medium/day-51.md b/medium/prune/51.permutations-ii.md similarity index 100% rename from medium/day-51.md rename to medium/prune/51.permutations-ii.md diff --git a/medium/rk-kpm/52.implement-strstr.md b/medium/rk-kpm/52.implement-strstr.md new file mode 100644 index 0000000..046c8f8 --- /dev/null +++ b/medium/rk-kpm/52.implement-strstr.md @@ -0,0 +1,75 @@ +# 28. 实现 strStr() + +https://leetcode-cn.com/problems/implement-strstr/ + +## 题目描述 + +``` +实现 strStr() 函数。 + +给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。 + +示例 1: + +输入: haystack = "hello", needle = "ll" +输出: 2 +示例 2: + +输入: haystack = "aaaaa", needle = "bba" +输出: -1 +说明: + +当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 + +对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/implement-strstr +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:暴力 + +### 思路 + +将长串的所有子串与短串进行一一对比。 + +### 复杂度分析 + +- 时间复杂度:$O(M*N)$,M 是长串的长度,N 是短串的长度。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +var strStr = function (haystack, needle) { + if (!needle) return 0; + + let l = 0, + r = needle.length; + if (haystack[l] === needle[0]) { + if (compare(haystack, needle, l, r)) return l; + } + l++; + r++; + } + return -1; + + // ******************************** + function compare(long, short, l, r) { + for (let i = 0; i < r - l; i++) { + if (long[i + l] !== short[i]) return false; + } + return true; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/medium/day-41.md b/medium/trie/41.implement-trie-prefix-tree.md similarity index 60% rename from medium/day-41.md rename to medium/trie/41.implement-trie-prefix-tree.md index ddfbaf8..78f50dc 100644 --- a/medium/day-41.md +++ b/medium/trie/41.implement-trie-prefix-tree.md @@ -33,48 +33,6 @@ trie.search("app"); // 返回 true https://medium.com/basecs/trying-to-understand-tries-3ec6bede0014 -## 输入输出 - -Nodejs - -```js -const __main__ = function () { - const readline = require('readline') - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }) - - console.log('******输入******') - rl.prompt() - const lines = [] - rl.on('line', line => lines.push(line)) - - rl.on('close', () => { - console.log('\n******输出******') - - const test = (operations, params) => { - if (operations[0] === 'Trie') { - const trie = new Trie() - const output = [null] - for (let i = 1; i < operations.length; i++) { - const res = trie[operations[i]](...params[i]) - output.push(res === void 0 ? null : res) - } - console.log(output) - } else { - console.log(Array(operations.length).fill(null)) - } - } - - while (lines.length >= 2) { - const params = lines.splice(0, 2) - test(...params.map(el => JSON.parse(el))) - } - }) -} -``` - ## 复杂度分析 - 时间复杂度:$O(L)$,L 是字符串长度, `insert` `search` `startsWith` 操作都是。 @@ -86,60 +44,60 @@ TypeScript Code ```ts class TrieNode { - value: string - children: Array + value: string; + children: Array; constructor(value) { - this.value = value - this.children = Array(26) + this.value = value; + this.children = Array(26); } } class Trie { - private root: TrieNode + private root: TrieNode; constructor() { - this.root = this._getTrieNode('') + this.root = this._getTrieNode(''); } private _getTrieNode(value: string): TrieNode { - return new TrieNode(value) + return new TrieNode(value); } private _char2Index(char: string): number { - return char.toLowerCase().charCodeAt(0) - 97 + return char.toLowerCase().charCodeAt(0) - 97; } insert(word: string): void { - let crawl: TrieNode = this.root + let crawl: TrieNode = this.root; for (let char of word) { - const index: number = this._char2Index(char) + const index: number = this._char2Index(char); if (!crawl.children[index]) { - crawl.children[index] = this._getTrieNode('') + crawl.children[index] = this._getTrieNode(''); } - crawl = crawl.children[index] + crawl = crawl.children[index]; } - crawl.value = word + crawl.value = word; } search(word: string): boolean { - let crawl: TrieNode = this.root + let crawl: TrieNode = this.root; for (let char of word) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return false - crawl = crawl.children[index] + const index: number = this._char2Index(char); + if (!crawl.children[index]) return false; + crawl = crawl.children[index]; } - return crawl.value === word + return crawl.value === word; } startsWith(prefix: string): boolean { - let crawl: TrieNode = this.root + let crawl: TrieNode = this.root; for (let char of prefix) { - const index: number = this._char2Index(char) - if (!crawl.children[index]) return false - crawl = crawl.children[index] + const index: number = this._char2Index(char); + if (!crawl.children[index]) return false; + crawl = crawl.children[index]; } - return true + return true; } } @@ -157,21 +115,21 @@ JavaScript Code ```js class TrieNode { constructor(val) { - this.value = val - this.pointers = Array(26) + this.value = val; + this.pointers = Array(26); } } class Trie { constructor() { - this.root = this._getTrieNode('') + this.root = this._getTrieNode(''); } /** * @param {string} val */ _getTrieNode(val) { - return new TrieNode(val) + return new TrieNode(val); } /** @@ -179,7 +137,7 @@ class Trie { * @returns {number} */ _char2Index(char) { - return char.toLowerCase().charCodeAt(0) - 97 + return char.toLowerCase().charCodeAt(0) - 97; } /** @@ -188,16 +146,16 @@ class Trie { * @return {void} */ insert(word) { - let crawl = this.root + let crawl = this.root; for (let char of word) { - const index = this._char2Index(char) + const index = this._char2Index(char); if (!crawl.pointers[index]) { - crawl.pointers[index] = this._getTrieNode('') + crawl.pointers[index] = this._getTrieNode(''); } - crawl = crawl.pointers[index] + crawl = crawl.pointers[index]; } // Store the word in the last TrieNode as an end mark. - crawl.value = word + crawl.value = word; } /** @@ -206,16 +164,16 @@ class Trie { * @return {boolean} */ search(word) { - let crawl = this.root + let crawl = this.root; for (let char of word) { - const index = this._char2Index(char) - if (!crawl.pointers[index]) return false + const index = this._char2Index(char); + if (!crawl.pointers[index]) return false; - crawl = crawl.pointers[index] + crawl = crawl.pointers[index]; } // If it has a stored value, it is the last TrieNode, i.e., the desired word is found. // Otherwise, the word doesn't exist in Trie. - return !!crawl.value + return !!crawl.value; } /** @@ -224,18 +182,56 @@ class Trie { * @return {boolean} */ startsWith(prefix) { - let crawl = this.root + let crawl = this.root; for (let char of prefix) { - const index = this._char2Index(char) - if (!crawl.pointers[index]) return false + const index = this._char2Index(char); + if (!crawl.pointers[index]) return false; - crawl = crawl.pointers[index] + crawl = crawl.pointers[index]; } - return true + return true; } } ``` -**官方题解** +## 输入输出 + +Nodejs + +```js +const __main__ = function () { + const readline = require('readline'); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + console.log('******输入******'); + rl.prompt(); + const lines = []; + rl.on('line', line => lines.push(line)); -https://github.com/leetcode-pp/91alg-1/issues/68#issuecomment-657077878 + rl.on('close', () => { + console.log('\n******输出******'); + + const test = (operations, params) => { + if (operations[0] === 'Trie') { + const trie = new Trie(); + const output = [null]; + for (let i = 1; i < operations.length; i++) { + const res = trie[operations[i]](...params[i]); + output.push(res === void 0 ? null : res); + } + console.log(output); + } else { + console.log(Array(operations.length).fill(null)); + } + }; + + while (lines.length >= 2) { + const params = lines.splice(0, 2); + test(...params.map(el => JSON.parse(el))); + } + }); +}; +``` diff --git a/medium/trie/42.map-sum-pairs.md b/medium/trie/42.map-sum-pairs.md new file mode 100644 index 0000000..8eff95f --- /dev/null +++ b/medium/trie/42.map-sum-pairs.md @@ -0,0 +1,372 @@ +# 677.键值映射 + +https://leetcode-cn.com/problems/map-sum-pairs + +- [677.键值映射](#677键值映射) + - [题目描述](#题目描述) + - [方法 1:HashMap](#方法-1hashmap) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法 2:Trie + DFS](#方法-2trie--dfs) + - [思路](#思路) + - [复杂度分析](#复杂度分析-1) + - [代码](#代码-1) + - [方法 3:Trie + 时间优化](#方法-3trie--时间优化) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-2) + - [代码](#代码-2) + - [方法 4:Trie + HashMap](#方法-4trie--hashmap) + - [思路](#思路-2) + - [复杂度分析](#复杂度分析-3) + - [代码](#代码-3) + +## 题目描述 + +``` +实现一个 MapSum 类里的两个方法,insert 和 sum。 + +对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。 + +对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。 + +示例 1: + +输入: insert("apple", 3), 输出: Null +输入: sum("ap"), 输出: 3 +输入: insert("app", 2), 输出: Null +输入: sum("ap"), 输出: 5 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/map-sum-pairs +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:HashMap + +### 复杂度分析 + +| | 时间 | 空间 | +| ------ | ----------------------------------------------- | -------------- | +| insert | $O(1)$ (不考虑哈希冲突的话) | $O(n)$ | +| sum | $O(n*len(prefix))$ | $O(n)$ | +| 备注 | n 是 hashmap 的 key 总数,prefix 是要查找的前缀 | n 是字符串数量 | + +### 代码 + +Python Code + +```py +class MapSum(object): + def __init__(self): + """ + Initialize your data structure here. + """ + self.hashmap = {} + + def insert(self, key, val): + """ + :type key: str + :type val: int + :rtype: None + """ + self.hashmap[key] = val + + def sum(self, prefix): + """ + :type prefix: str + :rtype: int + """ + res = 0 + for key in self.hashmap: + if key.startswith(prefix): + res += self.hashmap[key] + return res + + + +# Your MapSum object will be instantiated and called as such: +# obj = MapSum() +# obj.insert(key,val) +# param_2 = obj.sum(prefix) +``` + +## 方法 2:Trie + DFS + +### 思路 + +- 构建前缀树。 +- `sum` 操作的时候,先判断 `prefix` 是否存在前缀树中,然后找到 `prefix` 最后的节点,开始 DFS。 + +**DFS** + +- **大问题**:`dfs(node)` 应该要返回以这个节点开始的所有路径中的 `value` 的和。 +- **小问题**:`dfs(node.child)`,先找到以 `node` 的子节点开始的所有路径中的 `value` 的和。不过由于 `node` 有很多子节点,所以我们需要一个循环。 +- **大问题与小问题的关系**:当我们求出了全部 `dfs(node.child)`,那么 + + - `dfs(node) = node.value + dfs(node.child1) + dfs(node.child2) + ...` + +- **递归出口**:如果节点不存在,我们直接返回 0,停止递归。 + +### 复杂度分析 + +- 时间复杂度:`insert` 操作的时间复杂度是 $O(len(key))$,`sum` 操作的时间复杂度是 $O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。 +- 空间复杂度:$O(m^{n})$,m 是字符集中字符数量,n 是字符串长度。 + +| | 时间 | 空间 | +| ------ | ------------------------------------ | ---------- | +| insert | $O(len(key))$ | $O(m^{n})$ | +| sum | $O(m^{n})$ | $O(m^{n})$ | +| 备注 | m 是字符集中字符数量,n 是字符串长度 | | + +### 代码 + +TypeScript Code + +```ts +class TrieNode { + value: number; + children: Array; + + constructor(value: number) { + this.value = value; + this.children = Array(26); + } +} + +class MapSum { + private root: TrieNode; + + constructor() { + this.root = this._getTrieNode(0); + } + + private _getTrieNode(value: number): TrieNode { + return new TrieNode(value); + } + + private _char2Index(char: string): number { + return char.toLowerCase().charCodeAt(0) - 97; + } + + insert(key: string, val: number): void { + let crawl: TrieNode = this.root; + for (let char of key) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) { + crawl.children[index] = this._getTrieNode(0); + } + crawl = crawl.children[index]; + } + crawl.value = val; + } + + private _dfs(crawl: TrieNode): number { + if (!crawl) return 0; + + return crawl.children.reduce( + (res: number, pointer: TrieNode): number => { + return res + (pointer ? this._dfs(pointer) : 0); + }, + crawl.value, + ); + } + + sum(prefix: string): number { + let crawl: TrieNode = this.root; + for (let char of prefix) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) return 0; + crawl = crawl.children[index]; + } + return this._dfs(crawl); + } +} + +/** + * Your MapSum object will be instantiated and called as such: + * var obj = new MapSum() + * obj.insert(key,val) + * var param_2 = obj.sum(prefix) + */ +``` + +## 方法 3:Trie + 时间优化 + +### 思路 + +在每个节点上存 `prefixSum`,可以把 `sum` 操作的时间复杂度降到 $O(1)$,代价是在 `insert` 的时候需要先检查 key 是否已经存在,存在的话要先从 `prefixSum` 中减去旧的 value,再加上新的 value。 + +### 复杂度分析 + +| | 时间 | 空间 | +| ------ | ------------- | ------------------------------------ | +| insert | $O(len(key))$ | $O(m^{n})$ | +| sum | $O(1)$ | $O(m^{n})$ | +| 备注 | | m 是字符集中字符数量,n 是字符串长度 | + +### 代码 + +```ts +class TrieNode { + value: number; + prefixSum: number; + children: Array; + + constructor(value: number) { + this.value = value; + this.prefixSum = 0; + this.children = Array(26); + } +} + +class MapSum { + private root: TrieNode; + + constructor() { + this.root = this._getTrieNode(0); + } + + private _getTrieNode(value: number): TrieNode { + return new TrieNode(value); + } + + private _char2Index(char: string): number { + return char.toLowerCase().charCodeAt(0) - 97; + } + + search(key: string): number { + let crawl: TrieNode = this.root; + for (let char of key) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) return 0; + crawl = crawl.children[index]; + } + return crawl.value; + } + + insert(key: string, val: number): void { + let crawl: TrieNode = this.root; + const existedVal: number = this.search(key); + for (let char of key) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) { + crawl.children[index] = this._getTrieNode(0); + } + crawl = crawl.children[index]; + crawl.prefixSum = crawl.prefixSum - existedVal + val; + } + crawl.value = val; + } + + sum(prefix: string): number { + let crawl: TrieNode = this.root; + + for (let char of prefix) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) return 0; + crawl = crawl.children[index]; + } + return crawl.prefixSum; + } +} + +/** + * Your MapSum object will be instantiated and called as such: + * var obj = new MapSum() + * obj.insert(key,val) + * var param_2 = obj.sum(prefix) + */ +``` + +## 方法 4:Trie + HashMap + +### 思路 + +在方法 3 的基础上再加一个 hashmap,把以某个前缀开始的 `key` 和相应的 `value`存起来,比如, + +- 我们先插入了一个 `(dark, 3)`,然后再插入一个 `(darkest, 2)` +- 这时的 hashmap 应该是这样: + - `{ dark: 3, darkest: 2 }` +- 这时如果我们再次插入 `(darkest, 5)`,覆盖了之前的值,那 hashmap 就变成了: + - `{ dark: 3, darkest: 5 }` + +### 复杂度分析 + +| | 时间 | 空间 | +| ------ | ---------------- | ------------------------------------ | +| insert | $O(len(key))$ | $O(m^{n})$ | +| sum | $O(len(prefix))$ | $O(m^{n})$ | +| 备注 | | m 是字符集中字符数量,n 是字符串长度 | + +### 代码 + +```ts +class TrieNode { + value: number; + prefixSum: number; + children: Array; + + constructor(value: number) { + this.value = value; + this.prefixSum = 0; + this.children = Array(26); + } +} + +class MapSum { + private root: TrieNode; + private existedWords: { + [key: string]: number; + }; + + constructor() { + this.root = this._getTrieNode(0); + this.existedWords = {}; + } + + private _getTrieNode(value: number): TrieNode { + return new TrieNode(value); + } + + private _char2Index(char: string): number { + return char.toLowerCase().charCodeAt(0) - 97; + } + + insert(key: string, val: number): void { + let crawl: TrieNode = this.root; + for (let char of key) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) { + crawl.children[index] = this._getTrieNode(0); + } + crawl = crawl.children[index]; + if (key in this.existedWords) { + crawl.prefixSum -= this.existedWords[key]; + } + crawl.prefixSum += val; + } + this.existedWords[key] = val; + crawl.value = val; + } + + sum(prefix: string): number { + let crawl: TrieNode = this.root; + + for (let char of prefix) { + const index: number = this._char2Index(char); + if (!crawl.children[index]) return 0; + crawl = crawl.children[index]; + } + return crawl.prefixSum; + } +} + +/** + * Your MapSum object will be instantiated and called as such: + * var obj = new MapSum() + * obj.insert(key,val) + * var param_2 = obj.sum(prefix) + */ +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/medium/day-43.md b/medium/trie/43.multi-search-lcci.md similarity index 74% rename from medium/day-43.md rename to medium/trie/43.multi-search-lcci.md index 2120bd0..3fd43a5 100644 --- a/medium/day-43.md +++ b/medium/trie/43.multi-search-lcci.md @@ -2,8 +2,15 @@ https://leetcode-cn.com/problems/multi-search-lcci -- Trie -- 暴力 +- [面试题 17.17.多次搜索](#面试题-1717多次搜索) + - [题目描述](#题目描述) + - [方法 1:Trie](#方法-1trie) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法 2:暴力法](#方法-2暴力法) + - [思路](#思路-1) + - [代码](#代码-1) ## 题目描述 @@ -29,7 +36,7 @@ smalls的总字符数不会超过 100000。 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## Trie +## 方法 1:Trie ### 思路 @@ -44,8 +51,10 @@ smalls的总字符数不会超过 100000。 ### 复杂度分析 -- 时间复杂度:`insert` 是 $O(n*m)$,n 是 `smalls` 的长度,m 是短串的平均长度,`search` -- 空间复杂度: +| | 时间 | 空间 | +| ------ | ----------------------------------------- | ------------------------------------------------- | +| insert | $O(len(smalls)*avg)$ avg 是短串的平均长度 | $O(n^{avg})$ n 是字符集大小,avg 是短串的平均长度 | +| search | $O(maxLen(smalls)*len(smalls))$ | $O(n^{m})$ | ### 代码 @@ -76,33 +85,33 @@ TypeScript Code ```ts function multiSearch(big: string, smalls: string[]): number[][] { // 把短字符串存进 Trie - const trie: Trie = new Trie() + const trie: Trie = new Trie(); smalls.forEach((word: string, index: number): void => { - trie.insert(word, index) - }) + trie.insert(word, index); + }); const res: number[][] = Array(smalls.length) .fill(0) - .map(() => []) + .map(() => []); // 找到 smalls 中最长字符串长度 const longest: number = smalls.reduce( (res: number, word: string): number => Math.max(res, word.length), 0, - ) + ); // 遍历 big,将以 longest 为长度的子串拿到 Trie 中去找有没有匹配的短串 // 有的话,会返回那个短串在 smalls 中对应的下标,那就把子串对应的开始下标 i 存在对应的结果数组里好了 for (let i = 0; i < big.length; i++) { - const indices = trie.search(big.slice(i, i + longest)) - indices.forEach(index => res[index].push(i)) + const indices = trie.search(big.slice(i, i + longest)); + indices.forEach(index => res[index].push(i)); } - return res + return res; } ``` -## 暴力 +## 方法 2:暴力法 ### 思路 @@ -119,27 +128,25 @@ JavaScript * @return {number[][]} */ function multiSearch(big, smalls) { - const longest = smalls.reduce((res, w) => Math.max(res, w.length), 0) + const longest = smalls.reduce((res, w) => Math.max(res, w.length), 0); const res = Array(smalls.length) .fill(0) - .map(() => []) + .map(() => []); for (let i = 0; i < big.length; i++) { for (let j = i + 1; j <= i + longest && j <= big.length; j++) { - const subStr = big.slice(i, j) + const subStr = big.slice(i, j); for (let k = 0; k < smalls.length; k++) { if (smalls[k] === subStr) { - res[k].push(i) + res[k].push(i); } } } } - return res + return res; } ``` -**官方题解** - -https://github.com/leetcode-pp/91alg-1/issues/70#issuecomment-657434460 +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/medium/day-44.md b/medium/union-find/44.friend-circles.md similarity index 63% rename from medium/day-44.md rename to medium/union-find/44.friend-circles.md index f7f7199..b04e4d0 100644 --- a/medium/day-44.md +++ b/medium/union-find/44.friend-circles.md @@ -2,9 +2,17 @@ https://leetcode-cn.com/problems/friend-circles/ -- [并查集](#并查集) -- [DFS](#DFS) -- [BFS](#BFS) +- [547.朋友圈](#547朋友圈) + - [题目描述](#题目描述) + - [方法 1:并查集](#方法-1并查集) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + - [方法 2:DFS](#方法-2dfs) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码(递归)](#代码递归) + - [代码(迭代)](#代码迭代) ## 题目描述 @@ -41,7 +49,7 @@ N 在[1,200]的范围内。 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 并查集 +## 方法 1:并查集 ### 思路 @@ -51,13 +59,13 @@ N 在[1,200]的范围内。 **入门学习资料** -- [Using Disjoint Set (Union-Find) To Build A Maze Generator](https://coderscat.com/using-disjoint-set-union-find-to-create-maze) - [Disjoint Set Data Structure](https://www.topcoder.com/community/competitive-programming/tutorials/disjoint-set-data-structures/) -- [个人笔记](https://github.com/suukii/Articles/blob/master/articles/dsa_union_find.md) +- [Using Disjoint Set (Union-Find) To Build A Maze Generator](https://coderscat.com/using-disjoint-set-union-find-to-create-maze) +- [笔记](https://github.com/suukii/Articles/blob/master/articles/dsa/dsa_union_find.md) ### 复杂度分析 -- 时间复杂度:$O(α(n))$。 +- 时间复杂度:$O(α(n))$,无论 n 为多少, $α(n)$ 都小于 5。 - 空间复杂度:$O(N)$,N 为学生人数。 ### 代码 @@ -65,57 +73,57 @@ N 在[1,200]的范围内。 TypeScript Code ```ts +function findCircleNum(M: number[][]): number { + const len: number = M.length; + const uf: UnionFind = new UnionFind(len); + for (let i = 0; i < len; i++) { + for (let j = i + 1; j < len; j++) { + M[i][j] === 1 && uf.unionSet(i, j); + } + } + return uf.size(); +} + class UnionFind { - private parents: Array - private rank: Array - private numOfSets: number + private parents: Array; + private rank: Array; + private numOfSets: number; constructor(size: number) { this.parents = Array(size) .fill(0) - .map((_, i) => i) - this.rank = Array(size).fill(0) - this.numOfSets = size + .map((_, i) => i); + this.rank = Array(size).fill(0); + this.numOfSets = size; } size(): number { - return this.numOfSets + return this.numOfSets; } findSet(x: number): number { if (x !== this.parents[x]) { - this.parents[x] = this.findSet(this.parents[x]) + this.parents[x] = this.findSet(this.parents[x]); } - return this.parents[x] + return this.parents[x]; } unionSet(x: number, y: number): void { - const px: number = this.findSet(x) - const py: number = this.findSet(y) - if (px === py) return + const px: number = this.findSet(x); + const py: number = this.findSet(y); + if (px === py) return; if (this.rank[px] > this.rank[py]) { - this.parents[py] = px + this.parents[py] = px; } else { - this.parents[px] = py - this.rank[px] === this.rank[py] && ++this.rank[py] - } - this.numOfSets-- - } -} - -function findCircleNum(M: number[][]): number { - const len: number = M.length - const uf: UnionFind = new UnionFind(len) - for (let i = 0; i < len; i++) { - for (let j = i + 1; j < len; j++) { - M[i][j] === 1 && uf.unionSet(i, j) + this.parents[px] = py; + this.rank[px] === this.rank[py] && ++this.rank[py]; } + this.numOfSets--; } - return uf.size() } ``` -## DFS +## 方法 2:DFS ### 思路 @@ -127,74 +135,67 @@ function findCircleNum(M: number[][]): number { - 时间复杂度:$O(N)$,N 是矩阵 M 的长度,也就是学生数量。 - 空间复杂度:$O(N)$,N 是学生数量,记录访问状态的 `visited` 数组空间是 $O(N)$,递归栈的空间也是 $O(N)$。 -### 代码 +### 代码(递归) TypeScript Code ```ts function findCircleNum(M: number[][]): number { - const visited: Array = Array(M.length) - let groups: number = 0 + const visited: Array = Array(M.length); + let groups: number = 0; - const bfs = (M: number[][], cur: number, visited: Array): void => { + const dfs = (M: number[][], cur: number, visited: Array): void => { for (let i = 0; i < M[cur].length; i++) { // If they are not friends or the ith person has been visited, skip him. - if (M[cur][i] === 0 || visited[i]) continue + if (M[cur][i] === 0 || visited[i]) continue; // Mark as visited because they are all in the same friend circle with the cur person. // And continue the search. - visited[i] = true - bfs(M, i, visited) + visited[i] = true; + dfs(M, i, visited); } - } + }; for (let i = 0; i < M.length; i++) { // If he's not been visited, then there is a new friend circle. // Start searching for all his friends. if (!visited[i]) { - groups++ - visited[i] = true - bfs(M, i, visited) + groups++; + visited[i] = true; + dfs(M, i, visited); } } - return groups + return groups; } ``` -## BFS - -### 复杂度分析 - -- 时间复杂度:$O(N)$,N 是学生数量。 -- 空间复杂度:$O(N)$,N 是学生数量。 +### 代码(迭代) TypeScript Code ```ts function findCircleNum(M: number[][]): number { - let ans: number = 0 - const visited: Array = Array(M.length) - const stack: Array = [] + let ans: number = 0; + const visited: Array = Array(M.length); + const stack: Array = []; for (let i = 0; i < M.length; i++) { - if (visited[i]) continue + if (visited[i]) continue; - stack.push(i) - ans++ + stack.push(i); + ans++; while (stack.length) { - const cur: number = stack.pop() as number + const cur: number = stack.pop() as number; - visited[cur] = true - const friends: Array = M[cur] + visited[cur] = true; + const friends: Array = M[cur]; for (let j = 0; j < friends.length; j++) { - if (visited[j] || friends[j] === 0) continue - stack.push(j) + if (visited[j] || friends[j] === 0) continue; + stack.push(j); } } } - return ans + return ans; } ``` - -**官方题解** diff --git a/medium/day-45.md b/medium/union-find/45.minimize-malware-spread.md similarity index 65% rename from medium/day-45.md rename to medium/union-find/45.minimize-malware-spread.md index 83f8e01..2cf1c48 100644 --- a/medium/day-45.md +++ b/medium/union-find/45.minimize-malware-spread.md @@ -2,6 +2,14 @@ https://leetcode-cn.com/problems/minimize-malware-spread +- [924.尽量减少恶意软件的传播](#924尽量减少恶意软件的传播) + - [题目描述](#题目描述) + - [方法 1:并查集](#方法-1并查集) + - [思路 1](#思路-1) + - [代码](#代码) + - [思路 2](#思路-2) + - [代码](#代码-1) + ## 题目描述 ``` @@ -41,159 +49,149 @@ graph[i][i] == 1 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 思路 - -**前置知识** - -- 并查集 - -**入门学习资料** - -- [Using Disjoint Set (Union-Find) To Build A Maze Generator](https://coderscat.com/using-disjoint-set-union-find-to-create-maze) -- [Disjoint Set Data Structure](https://www.topcoder.com/community/competitive-programming/tutorials/disjoint-set-data-structures/) -- [个人笔记](https://github.com/suukii/Articles/blob/master/articles/dsa_union_find.md) +## 方法 1:并查集 -**思路 1** +### 思路 1 - 先构建并查集,并记录每个不交集的节点数。 -- 依次从 initial 中拿掉一个节点,然后分别计算感染节点数,记录最小感染数和对应的节点索引。 +- 依次从 initial 中删除一个节点,重新计算感染节点数,找到最小感染数和对应的节点索引。 -**思路 2** - -- 构建并查集 -- 找到一个满足以下条件的不交集: - 1. 集合中只有一个感染节点 - 2. 集合的节点数量最大 -- 如果不存在上述集合,那就返回 `initial` 中的最小索引 - -## 代码 +### 代码 TypeScript Code -UnionFind - -```ts -class UnionFind { - private parents: Array - private sizes: Array - - constructor(size: number) { - this.parents = Array(size) - .fill(0) - .map((_, i) => i) - this.sizes = Array(size).fill(1) - } - - getSizeOfSet(x: number): number { - const px = this.findSet(x) - return this.sizes[px] - } - - findSet(x: number): number { - if (x !== this.parents[x]) { - this.parents[x] = this.findSet(this.parents[x]) - } - return this.parents[x] - } - - unionSet(x: number, y: number): void { - const px: number = this.findSet(x) - const py: number = this.findSet(y) - if (px === py) return - if (this.sizes[px] > this.sizes[py]) { - this.parents[py] = px - this.sizes[px] += this.sizes[py] - } else { - this.parents[px] = py - this.sizes[py] += this.sizes[px] - } - } -} -``` - -思路 1: - ```ts function minMalwareSpread(graph: number[][], initial: number[]): number { // 构建并查集 - const len: number = graph.length - const uf: UnionFind = new UnionFind(len) + const len: number = graph.length; + const uf: UnionFind = new UnionFind(len); for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { - graph[i][j] === 1 && uf.unionSet(i, j) + graph[i][j] === 1 && uf.unionSet(i, j); } } // 计算最终感染节点数 const countInfected = (initial: number[]): number => { - const parents: number[] = [] + const parents: number[] = []; for (let i = 0; i < initial.length; i++) { - const p = uf.findSet(initial[i]) - parents.find(e => e === p) || parents.push(p) + const p = uf.findSet(initial[i]); + parents.find(e => e === p) || parents.push(p); } return parents.reduce( (res: number, p: number): number => res + uf.getSizeOfSet(p), 0, - ) - } + ); + }; - let ans: number = 0 - let leastInfected: number = Infinity + let ans: number = 0; + let leastInfected: number = Infinity; for (let i = 0; i < initial.length; i++) { // 把第 i 个节点拿掉,然后计算感染节点数 const infected: number = countInfected([ ...initial.slice(0, i), ...initial.slice(i + 1), - ]) + ]); // 如果感染数更少,更新 ans if (infected < leastInfected) { - leastInfected = infected - ans = initial[i] + leastInfected = infected; + ans = initial[i]; } // 如果感染数一样少,取索引值较小的那个 else if (infected === leastInfected) { - initial[i] < ans && (ans = initial[i]) + initial[i] < ans && (ans = initial[i]); } } - return ans + return ans; } ``` -思路 2: +UnionFind + +```ts +class UnionFind { + private parents: Array; + private sizes: Array; + + constructor(size: number) { + this.parents = Array(size) + .fill(0) + .map((_, i) => i); + this.sizes = Array(size).fill(1); + } + + getSizeOfSet(x: number): number { + const px = this.findSet(x); + return this.sizes[px]; + } + + findSet(x: number): number { + if (x !== this.parents[x]) { + this.parents[x] = this.findSet(this.parents[x]); + } + return this.parents[x]; + } + + unionSet(x: number, y: number): void { + const px: number = this.findSet(x); + const py: number = this.findSet(y); + if (px === py) return; + if (this.sizes[px] > this.sizes[py]) { + this.parents[py] = px; + this.sizes[px] += this.sizes[py]; + } else { + this.parents[px] = py; + this.sizes[py] += this.sizes[px]; + } + } +} +``` + +### 思路 2 + +- 构建并查集 +- 找到一个满足以下条件的不交集: + 1. 集合中只有一个感染节点 + 2. 集合的节点数量最大 +- 如果不存在上述集合,那就返回 `initial` 中的最小索引 + +### 代码 + +TypeScript Code ```ts function minMalwareSpread(graph: number[][], initial: number[]): number { // 构建并查集 - const len: number = graph.length - const uf: UnionFind = new UnionFind(len) + const len: number = graph.length; + const uf: UnionFind = new UnionFind(len); for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { - graph[i][j] === 1 && uf.unionSet(i, j) + graph[i][j] === 1 && uf.unionSet(i, j); } } // 计算每个不交集中分别有多少个感染节点 - const malwares: number[] = Array(len).fill(0) - initial.forEach(i => malwares[uf.findSet(i)]++) + const malwares: number[] = Array(len).fill(0); + initial.forEach(i => malwares[uf.findSet(i)]++); // ans: [集合的节点数总数,感染节点索引] - let ans: [number, number] = [1, Infinity] + let ans: [number, number] = [1, Infinity]; for (let i of initial) { // 如果某个集合中只有一个感染节点 if (malwares[uf.findSet(i)] === 1) { - const count = uf.getSizeOfSet(i) + const count = uf.getSizeOfSet(i); // 如果这个集合的节点数更多,更新 ans if (count > ans[0]) { - ans = [count, i] + ans = [count, i]; } // 如果有多个满足条件的集合,取索引值更小的那个节点 else if (count === ans[0]) { - ans = [count, Math.min(ans[1], i)] + ans = [count, Math.min(ans[1], i)]; } } } // 如果不存在满足条件的集合,返回感染节点中索引值最小的那个节点 - return ans[1] === Infinity ? Math.min(...initial) : ans[1] + return ans[1] === Infinity ? Math.min(...initial) : ans[1]; } ``` diff --git a/medium/day-46.md b/medium/union-find/46.number-of-operations-to-make-network-connected.md similarity index 62% rename from medium/day-46.md rename to medium/union-find/46.number-of-operations-to-make-network-connected.md index f7893fd..4d6b76e 100644 --- a/medium/day-46.md +++ b/medium/union-find/46.number-of-operations-to-make-network-connected.md @@ -1,6 +1,12 @@ # 1319.连通网络的操作次数 -https://github.com/leetcode-pp/91alg-1/issues/73 +https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/ + +- [1319.连通网络的操作次数](#1319连通网络的操作次数) + - [题目描述](#题目描述) + - [方法 1:并查集](#方法-1并查集) + - [思路](#思路) + - [代码](#代码) ## 题目描述 @@ -46,73 +52,75 @@ connections[i][0] != connections[i][1] 两台计算机不会通过多条线缆连接。 ``` -## 思路 +## 方法 1:并查集 + +### 思路 -一开始的思路: +一开始的思路是: -- 先构建并查集,这样我们就能知道一共有多少个网络了,接着我们需要把网络连接起来。 -- 要连接 n 个网络,需要 n - 1 根网线,那怎么知道我们有多少条多余的网线? +- 先构建并查集,这样我们就能知道一共有多少个网络(即多少个不交集)了,接着我们需要把网络连接起来。 +- 要连接 n 个网络,需要 n - 1 根网线,那怎么知道我们有多少多余的网线? - 很简单,在构建网络时,也就是合并不交集的时候,如果两个节点原本就在同一集合中,那我们就多出来一根网线了。 -- 最后判断一下多余网线是否不小于 n - 1 即可。 +- 最后判断一下多余网线是否大于等于 n - 1 即可。 但其实没有必要记录多余的网线,只要算一下数学就好了: - 如果连接数小于 `n - 1`,那就直接返回 -1; -- 否则,说明网线是足够连接 n 个节点的,构建完并查集之后,返回集合数量减一即可。 +- 否则,说明网线是足够连接 n 个节点的,构建完并查集之后,返回不交集的数量减一即可。 -## 代码 +### 代码 TypeScript Code ```ts function makeConnected(n: number, connections: number[][]): number { - const cables: number = connections.length - if (cables < n - 1) return -1 + const cables: number = connections.length; + if (cables < n - 1) return -1; - const uf: UnionFind = new UnionFind(n) + const uf: UnionFind = new UnionFind(n); for (let c of connections) { - uf.unionSet(c[0], c[1]) + uf.unionSet(c[0], c[1]); } - return uf.size() - 1 + return uf.size() - 1; } ``` ```ts class UnionFind { - private parents: Array - private rank: Array - private numOfSets: number + private parents: Array; + private rank: Array; + private numOfSets: number; constructor(size: number) { this.parents = Array(size) .fill(0) - .map((_, i) => i) - this.rank = Array(size).fill(0) - this.numOfSets = size + .map((_, i) => i); + this.rank = Array(size).fill(0); + this.numOfSets = size; } size(): number { - return this.numOfSets + return this.numOfSets; } findSet(x: number): number { if (x !== this.parents[x]) { - this.parents[x] = this.findSet(this.parents[x]) + this.parents[x] = this.findSet(this.parents[x]); } - return this.parents[x] + return this.parents[x]; } unionSet(x: number, y: number): void { - const px: number = this.findSet(x) - const py: number = this.findSet(y) - if (px === py) return + const px: number = this.findSet(x); + const py: number = this.findSet(y); + if (px === py) return; if (this.rank[px] > this.rank[py]) { - this.parents[py] = px + this.parents[py] = px; } else { - this.parents[px] = py - this.rank[px] === this.rank[py] && ++this.rank[py] + this.parents[px] = py; + this.rank[px] === this.rank[py] && ++this.rank[py]; } - this.numOfSets-- + this.numOfSets--; } } ``` diff --git a/medium/union-find/ext-smallest-string-with-swaps.md b/medium/union-find/ext-smallest-string-with-swaps.md new file mode 100644 index 0000000..bdfb095 --- /dev/null +++ b/medium/union-find/ext-smallest-string-with-swaps.md @@ -0,0 +1,175 @@ +# 1202. 交换字符串中的元素 + +https://leetcode-cn.com/problems/smallest-string-with-swaps/ + +- [1202. 交换字符串中的元素](#1202-交换字符串中的元素) + - [题目描述](#题目描述) + - [方法 1:并查集](#方法-1并查集) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。 + +你可以 任意多次交换 在 pairs 中任意一对索引处的字符。 + +返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。 + +  + +示例 1: + +输入:s = "dcab", pairs = [[0,3],[1,2]] +输出:"bacd" +解释: +交换 s[0] 和 s[3], s = "bcad" +交换 s[1] 和 s[2], s = "bacd" +示例 2: + +输入:s = "dcab", pairs = [[0,3],[1,2],[0,2]] +输出:"abcd" +解释: +交换 s[0] 和 s[3], s = "bcad" +交换 s[0] 和 s[2], s = "acbd" +交换 s[1] 和 s[2], s = "abcd" +示例 3: + +输入:s = "cba", pairs = [[0,1],[1,2]] +输出:"abc" +解释: +交换 s[0] 和 s[1], s = "bca" +交换 s[1] 和 s[2], s = "bac" +交换 s[0] 和 s[1], s = "abc" +  + +提示: + +1 <= s.length <= 10^5 +0 <= pairs.length <= 10^5 +0 <= pairs[i][0], pairs[i][1] < s.length +s 中只含有小写英文字母 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/smallest-string-with-swaps +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:并查集 + +### 思路 + +换个思路,如果字符串 s 中的所有字符都可以随意互换,那我们只需要对 s 进行排序就可以得到结果了。 + +但字符串并不是所有字符都可随意互换,pairs  中的一对索引表示这两处的字符可以互换,但如果其中两对索引有重叠,则说明这三处的字符都可以随意互换,如果我们将这三个索引处的字符进行排序后再分别填充回去,也就能得到想要的结果了。 + +剩下的问题就是 + +1. 如何找出字符可以随意互换的区域? +2. 如何重新填充字符? + +第一个问题可以用并查集来解决,关于并查集这里就不详细展开了。通过并查集处理我们可以将字符串 s 分为若干个区域,每个区域内的字符都是可以随意互换的,我们只需要分别对每个区域中的字符进行排序就可以了。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/1202_0.png) + +第二个问题,要重新填充字符,我们需要知道当前索引属于哪个区域,以及当前区域有哪些字符。前者可以通过并查集的查找功能,后者可以使用一个哈希表来存储,使用并查集中每个不交集的代表元来作为哈希表的 key,当前区域内的所有字符作为 value。当然也可以修改并查集的结构,把数据直接存储在并查集中。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/1202_1.png) + +最后一步就是填充结果字符串。先对 map 中的字符进行分组排序,然后遍历 s 字符串,对于每个索引的处理是:先判断当前索引处于哪个不交集中,然后在 map 中找到这个不交集中的所有字符,取出字典序最小的字符,填充当前索引。 + +### 复杂度分析 + +| 操作 | 时间复杂度 | 空间复杂度 | +| -------------- | ----------------------------------------------------------------------- | ---------- | +| 构建并查集 | $O(M*α(N))$ | $O(N)$ | +| 构建哈希表 | $O(N*α(N))$, 并查集查询时间 $O(α(N))$,一共查询了 N 次 | $O(N)$ | +| 字符排序 | $O(NlogN)$, 最坏情况字符串 s 的所有字符都可互换,即对整个字符串进行排序 | $O(1)$ | +| 构建结果字符串 | $O(N*α(N))$ | $O(1)$ | +| 总计 | $O((M + N)*α(N) + NlogN)$ | $O(N)$ | + +- M 为 pairs 长度,N 为字符串 s 的长度。 + +### 代码 + +TypeScript Code + +```js +function smallestStringWithSwaps(s: string, pairs: number[][]): string { + if (pairs.length === 0) return s; + + const uf: UnionFind = new UnionFind(s.length); + for (const [x, y] of pairs) { + uf.unionSet(x, y); + } + + const map: { + [prop: string]: string[]; + } = {}; + + for (let i = 0; i < s.length; i++) { + const parent: number = uf.findSet(i); + if (!(parent in map)) map[parent] = []; + map[parent].push(s[i]); + } + + for (const k in map) { + map[k].sort( + (a: string, b: string): number => b.charCodeAt(0) - a.charCodeAt(0), + ); + } + + const res: string[] = Array(s.length); + for (let i = 0; i < s.length; i++) { + const parent: number = uf.findSet(i); + const strings: string[] = map[parent]; + res[i] = strings.pop(); + } + + return res.join(''); +} + +// ************************************************* + +class UnionFind { + private parents: Array; + private rank: Array; + private numOfSets: number; + + constructor(size: number) { + this.parents = Array(size) + .fill(0) + .map((_, i) => i); + this.rank = Array(size).fill(0); + this.numOfSets = size; + } + + size(): number { + return this.numOfSets; + } + + findSet(x: number): number { + if (x !== this.parents[x]) { + this.parents[x] = this.findSet(this.parents[x]); + } + return this.parents[x]; + } + + unionSet(x: number, y: number): void { + const px: number = this.findSet(x); + const py: number = this.findSet(y); + if (px === py) return; + if (this.rank[px] > this.rank[py]) { + this.parents[py] = px; + } else { + this.parents[px] = py; + this.rank[px] === this.rank[py] && ++this.rank[py]; + } + this.numOfSets--; + } +} +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/problems/0019.remove-nth-node-from-end-of-list.md b/problems/0019.remove-nth-node-from-end-of-list.md new file mode 100644 index 0000000..f73cb62 --- /dev/null +++ b/problems/0019.remove-nth-node-from-end-of-list.md @@ -0,0 +1,144 @@ +# 19. 删除链表的倒数第 N 个结点 + +https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/ + +- [19. 删除链表的倒数第 N 个结点](#19-删除链表的倒数第-n-个结点) + - [题目描述](#题目描述) + - [方法1: 快慢指针](#方法1-快慢指针) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 + +进阶:你能尝试使用一趟扫描实现吗? + +  + +示例 1: + + +输入:head = [1,2,3,4,5], n = 2 +输出:[1,2,3,5] +示例 2: + +输入:head = [1], n = 1 +输出:[] +示例 3: + +输入:head = [1,2], n = 1 +输出:[1] +  + +提示: + +链表中结点的数目为 sz +1 <= sz <= 30 +0 <= Node.val <= 100 +1 <= n <= sz + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1: 快慢指针 + +### 思路 + +**找到倒数第 N 个节点** + +- 要删除倒数第 N 个节点,第一步要先找到倒数第 N 个节点(实际上对于单向链表,还需要找到倒数第 N+1 个节点才能完成删除倒数第 N 个节点的操作)。 +- 简单的思路是,遍历确定链表长度 L,通过计算得到倒数第 N 个节点是顺数第 L-N 个节点。 +- 快慢指针的思路是,定义两个指针,快指针先走 N 步,剩下的路程自然是 L-N,这时再让快慢指针同时走,等快指针走路末尾时,慢指针走过的路程刚好是 L-N,也就是刚好走到倒数第 N 个节点。 + +**使用 dummy 节点来避免单独处理头节点** + +假如要删除的节点刚好是头节点的话,要额外处理就很麻烦。但如果事先在头节点前面添加一个 dummy 节点,就可以把头节点当成一个普通节点来处理了,这是链表题中常用的技巧。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +C++ Code + +```cpp +/** + * 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* removeNthFromEnd(ListNode* head, int n) { + ListNode *fast = head, *slow = head; + while (n--) { + fast = fast->next; + } + // 额外处理头部节点 + if (!fast) { + ListNode *new_head = head->next; + head->next = nullptr; + return new_head; + } + while (fast->next) { + fast = fast->next; + slow = slow->next; + } + ListNode *target = slow->next; + slow->next = target->next; + target->next = nullptr; + return head; + } +}; +``` + +使用 dummy 节点 + +```cpp +/** + * 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* removeNthFromEnd(ListNode* head, int n) { + ListNode *dummy = new ListNode(0, head); + ListNode *fast = dummy, *slow = dummy; + + // 快指针先走 n 步 + while (n-- > 0) { + fast = fast->next; + } + // 当快指针走到尾节点时 + // 慢指针刚好走到倒数 n+1 个节点 + while (fast && fast->next) { + fast = fast->next; + slow = slow->next; + } + ListNode *target = slow->next; + slow->next = target->next; + target->next = nullptr; + return dummy->next; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/problems/0021.merge-two-sorted-lists.md b/problems/0021.merge-two-sorted-lists.md new file mode 100644 index 0000000..d73b5ef --- /dev/null +++ b/problems/0021.merge-two-sorted-lists.md @@ -0,0 +1,203 @@ +# 21. 合并两个有序链表 + +https://leetcode-cn.com/problems/merge-two-sorted-lists/ + +- [21. 合并两个有序链表](#21-合并两个有序链表) + - [题目描述](#题目描述) + - [方法 1: 迭代](#方法-1-迭代) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码(JavaScript/C++)](#代码javascriptc) + - [方法 2: 递归](#方法-2-递归) + - [思路](#思路-1) + - [复杂度分析](#复杂度分析-1) + - [代码(JavaScript/C++)](#代码javascriptc-1) + +## 题目描述 + +``` +将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  + +示例: + +输入:1->2->4, 1->3->4 +输出:1->1->2->3->4->4 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/merge-two-sorted-lists +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1: 迭代 + +### 思路 + +- 用两个指针分别遍历两个链表,比较两个指针节点的大小。 + - 将较小的那个节点加到新链表中,然后指针后移。 + - 较大的那个节点指针不动,下一轮继续比较。 +- 如果两个链表长度不一样,继续遍历将多出来的节点加到新链表中就好了。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$, N 为新链表长度。 +- 空间复杂度:$O(1)$。 + +### 代码(JavaScript/C++) + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function (l1, l2) { + const dummy = new ListNode(); + let p1 = l1, + p2 = l2, + cur = dummy; + + while (p1 || p2) { + if (!p2 || (p1 && p1.val <= p2.val)) { + cur.next = new ListNode(p1.val); + p1 = p1.next; + } else { + cur.next = new ListNode(p2.val); + p2 = p2.next; + } + cur = cur.next; + } + + return dummy.next; +}; +``` + +C++ Code + +```cpp +/** + * 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* mergeTwoLists(ListNode* l1, ListNode* l2) { + ListNode *dummy = new ListNode(0); + ListNode *tail = dummy; + + while (l1 && l2) { + if (l1->val <= l2->val) { + tail->next = new ListNode(l1->val); + l1 = l1->next; + } else { + tail->next = new ListNode(l2->val); + l2 = l2->next; + } + tail = tail->next; + } + while (l1) { + tail->next = new ListNode(l1->val); + l1 = l1->next; + tail = tail->next; + } + while (l2) { + tail->next = new ListNode(l2->val); + l2 = l2->next; + tail = tail->next; + } + return dummy->next; + } +}; +``` + +## 方法 2: 递归 + +### 思路 + +- 如果 `l1.val < l2.val`,那就把 l1 作为合并链表的头部返回,然后继续合并 `l1.next` 和 `l2` 之后的节点。 +- 如果 `l1.val > l2.val`,那就把 l2 作为合并链表的头部返回,然后继续合并 `l2.next` 和 `l1` 之后的节点。 +- 递归出口: + - 没有节点了。 + - 只剩一个节点,直接返回。 + +### 复杂度分析 + +- 时间复杂度:$O(N)$, N 为新链表长度。 +- 空间复杂度:$O(N)$, N 为新链表长度,递归栈的空间。 + +### 代码(JavaScript/C++) + +JavaScript Code + +```js +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function (l1, l2) { + if (!l1) return l2; + if (!l2) return l1; + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } +}; +``` + +C++ Code + +```cpp +/** + * 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* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (!l1) return l2; + if (!l2) return l1; + + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } else { + l2->next = mergeTwoLists(l1, l2->next); + return l2; + } + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/problems/2.add-two-numbers.md b/problems/2.add-two-numbers.md new file mode 100644 index 0000000..df2901f --- /dev/null +++ b/problems/2.add-two-numbers.md @@ -0,0 +1,105 @@ +# 2. 两数相加 + +https://leetcode-cn.com/problems/add-two-numbers/ + +- [2. 两数相加](#2-两数相加) + - [题目描述](#题目描述) + - [方法1: 模拟](#方法1-模拟) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 + +请你将两个数相加,并以相同形式返回一个表示和的链表。 + +你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 + +  + +示例 1: + + +输入:l1 = [2,4,3], l2 = [5,6,4] +输出:[7,0,8] +解释:342 + 465 = 807. +示例 2: + +输入:l1 = [0], l2 = [0] +输出:[0] +示例 3: + +输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] +输出:[8,9,9,9,0,0,0,1] +  + +提示: + +每个链表中的节点数在范围 [1, 100] 内 +0 <= Node.val <= 9 +题目数据保证列表表示的数字不含前导零 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/add-two-numbers +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1: 模拟 + +### 思路 + +- 简单加法 +- 对链表数据结构有基础了解 + +### 复杂度分析 + +- 时间复杂度:$O(N)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +C++ Code + +```cpp +/** + * 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* addTwoNumbers(ListNode* l1, ListNode* l2) { + ListNode* dummy = new ListNode(); + ListNode *tail = dummy, *p1 = l1, *p2 = l2; + + int carry = 0; + while (p1 || p2) { + int val1 = p1 ? p1->val : 0; + int val2 = p2 ? p2->val : 0; + + int sum = val1 + val2 + carry; + carry = sum / 10; + + tail->next = new ListNode(sum % 10); + tail = tail->next; + + if (p1) p1 = p1->next; + if (p2) p2 = p2->next; + } + if (carry > 0) { + tail->next = new ListNode(carry); + } + return dummy->next; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/templates/binary-search.js b/templates/binary-search.js new file mode 100644 index 0000000..8ac10c6 --- /dev/null +++ b/templates/binary-search.js @@ -0,0 +1,145 @@ +/** + * @description 搜索排序数组 + * @param {number[]} nums + * @param {number} target + * @returns {number} + */ +function binarySearch(nums, target) { + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + const mid = Math.floor(left + (right - left) / 2); + + if (nums[mid] == target) return mid; + + // 搜索区间变为 [mid+1, right] + if (nums[mid] < target) left = mid + 1; + + // 搜索区间变为 [left, mid - 1] + if (nums[mid] > target) right = mid - 1; + } + + return -1; +} + +/** + * @description 在排序数组中寻找最左边的满足条件的值 + * @param {number[]} nums + * @param {number} target + */ +function binarySearchLeft(nums, target) { + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + const mid = Math.floor(left + (right - left) / 2); + + if (nums[mid] >= target) right = mid - 1; + else left = mid + 1; + } + + // 检查是否越界 + if (left >= nums.length || nums[left] != target) return -1; + + return left; +} + +/** + * @description 在排序数组中寻找最右边的满足条件的值 + * @param {number[]} nums + * @param {number} target + * @returns {number} + */ +function binarySearchRight(nums, target) { + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + const mid = Math.floor(left + (right - left) / 2); + + if (nums[mid] <= target) left = mid + 1; + else right = mid - 1; + } + + // 检查是否越界 + if (right < 0 || nums[right] != target) return -1; + + return right; +} + +/** + * @description 在排序数组中寻找最左插入位置 + * @param {number[]} nums + * @param {number} x + * @returns {number} + */ +function searchInsertLeft(nums, x) { + // 题意转换一下,其实就是寻找第一个“大于等于” x 的数字,返回它的下标 + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + const mid = Math.floor(left + (right - left) / 2); + + if (nums[mid] >= x) right = mid - 1; + if (nums[mid] < x) left = mid + 1; + } + + return left; +} + +/** + * @description 在排序数组中寻找最右插入位置 + * @param {number[]} nums + * @param {number} x + * @returns {number} + */ +function searchInsertRight(nums, x) { + // 题意转换一下,其实就是寻找第一个“大于” x 的数字,返回它的下标 + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + const mid = Math.floor(left + (right - left) / 2); + + if (nums[mid] > x) right = mid - 1; + if (nums[mid] <= x) left = mid + 1; + } + + return left; +} + +/** + * @description 搜索旋转排序数组 + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var searchRotate = function (nums, target) { + let l = 0, + r = nums.length - 1; + while (l <= r) { + const m = l + ((r - l) >> 1); + if (nums[m] === target) return m; + + // 将重复元素排除在搜索区间外 + while (l < m && nums[l] === nums[m]) { + l++; + } + + // m 位于左侧有序部分 + if (nums[l] <= nums[m]) { + // m 大于 target,并且 target 大于左侧最小值,才缩小右边界 + if (nums[m] > target && target >= nums[l]) r = m - 1; + else l = m + 1; + } + // m 位于右侧有序部分 + else { + // m 小于 target,并且 target 小于右侧最大值,才缩小左边界 + if (nums[m] < target && target <= nums[r]) l = m + 1; + else r = m - 1; + } + } + return -1; +}; diff --git a/topics/day-62.md b/topics/binary-search/61.sqrtx.md similarity index 86% rename from topics/day-62.md rename to topics/binary-search/61.sqrtx.md index cef4a6a..ba72a65 100644 --- a/topics/day-62.md +++ b/topics/binary-search/61.sqrtx.md @@ -2,6 +2,13 @@ https://leetcode-cn.com/problems/sqrtx +- [69. x 的平方根](#69-x-的平方根) + - [题目描述](#题目描述) + - [方法1:二分法](#方法1二分法) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码](#代码) + ## 题目描述 ``` @@ -26,8 +33,9 @@ https://leetcode-cn.com/problems/sqrtx 链接:https://leetcode-cn.com/problems/sqrtx 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` +## 方法1:二分法 -## 思路 +### 思路 这个问题分两种情况: @@ -46,12 +54,12 @@ https://leetcode-cn.com/problems/sqrtx 需要特别注意一下的是 0 和 1 这两个数字,不过上面的算法对这两个数字也是有效的。 -## 复杂度 +### 复杂度 - 时间复杂度:$O(logx)$ - 空间复杂度:$O(1)$ -## 代码 +### 代码 Python Code @@ -70,3 +78,5 @@ class Solution(object): else: l = m + 1 return r ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/topics/day-63.md b/topics/binary-search/62.first-bad-version.md similarity index 85% rename from topics/day-63.md rename to topics/binary-search/62.first-bad-version.md index a436a0f..2db5173 100644 --- a/topics/day-63.md +++ b/topics/binary-search/62.first-bad-version.md @@ -2,6 +2,13 @@ https://leetcode-cn.com/problems/first-bad-version +- [278. 第一个错误的版本](#278-第一个错误的版本) + - [题目描述](#题目描述) + - [方法1:二分法](#方法1二分法) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码](#代码) + ## 题目描述 ``` @@ -26,7 +33,9 @@ https://leetcode-cn.com/problems/first-bad-version 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 思路 +## 方法1:二分法 + +### 思路 **寻找最左边的满足条件的值** @@ -41,12 +50,12 @@ https://leetcode-cn.com/problems/first-bad-version - 如果不符合题目要求,或者 left 出了右边的边界,说明没有找到,返回 -1。 - 否则返回 left 即可。 -## 复杂度 +### 复杂度 -- 时间复杂度:$O(log_n)$ +- 时间复杂度:$O(logn)$ - 空间复杂度:$O(1)$ -## 代码 +### 代码 Python Code @@ -72,3 +81,5 @@ class Solution(object): # 本题中“错误版本”一定存在,不然还是需要检查最终的左指针 # return l if l <= n and isBadVersion(l) else -1 ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/topics/day-64.md b/topics/binary-search/63.find-peak-element.md similarity index 70% rename from topics/day-64.md rename to topics/binary-search/63.find-peak-element.md index 8d62d98..2491e8a 100644 --- a/topics/day-64.md +++ b/topics/binary-search/63.find-peak-element.md @@ -2,6 +2,13 @@ https://leetcode-cn.com/problems/find-peak-element +- [162. 寻找峰值](#162-寻找峰值) + - [题目描述](#题目描述) + - [方法1:二分法](#方法1二分法) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码](#代码) + ## 题目描述 ``` @@ -33,7 +40,26 @@ https://leetcode-cn.com/problems/find-peak-element 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 ``` -## 代码 +## 方法1:二分法 + +### 思路 + +假如存在目标值 `nums[m]`,那么目标值需要满足的条件是: + +```py +nums[m] > nums[m - 1] and nums[m] > nums[m + 1] +``` + +剩下就是二分模板的事。 + +### 复杂度 + +- 时间复杂度:$O(logn)$ +- 空间复杂度:$O(1)$ + +### 代码 + +JavaScript Code ```js /** @@ -53,7 +79,4 @@ var findPeakElement = function (nums) { }; ``` -## 复杂度 - -- 时间复杂度:$O(logn)$ -- 空间复杂度:$O(1)$ +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/topics/binary-search/ext-search-in-rotated-sorted-array-ii.md b/topics/binary-search/ext-search-in-rotated-sorted-array-ii.md new file mode 100644 index 0000000..91cb219 --- /dev/null +++ b/topics/binary-search/ext-search-in-rotated-sorted-array-ii.md @@ -0,0 +1,96 @@ +# 81. 搜索旋转排序数组 II + +https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/ + +- [81. 搜索旋转排序数组 II](#81-搜索旋转排序数组-ii) + - [题目描述](#题目描述) + - [方法 1:二分法](#方法-1二分法) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + +( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。 + +编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。 + +示例 1: + +输入: nums = [2,5,6,0,0,1,2], target = 0 +输出: true +示例 2: + +输入: nums = [2,5,6,0,0,1,2], target = 3 +输出: false +进阶: + +这是 搜索旋转排序数组 的延伸题目,本题中的 nums  可能包含重复元素。 +这会影响到程序的时间复杂度吗?会有怎样的影响,为什么? + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1:二分法 + +### 思路 + +跟 [33. 搜索旋转排序数组](./ext-search-in-rotated-sorted-array.md) 的思路差不多,只不过多了重复元素这一条件。 + +```js +// 将重复元素排除在搜索区间外 +while (l < m && nums[l] === nums[m]) { + l++; +} +``` + +### 复杂度分析 + +- 时间复杂度:$O(nlogn)$。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {boolean} + */ +var search = function (nums, target) { + let l = 0, + r = nums.length - 1; + while (l <= r) { + const m = l + ((r - l) >> 1); + if (nums[m] === target) return true; + + // 将重复元素排除在搜索区间外 + while (l < m && nums[l] === nums[m]) { + l++; + } + + // m 位于左侧有序部分 + if (nums[l] <= nums[m]) { + // m 大于 target,并且 target 大于左侧最小值,才缩小右边界 + if (nums[m] > target && target >= nums[l]) r = m - 1; + else l = m + 1; + } + // m 位于右侧有序部分 + else { + // m 小于 target,并且 target 小于右侧最大值,才缩小左边界 + if (nums[m] < target && target <= nums[r]) l = m + 1; + else r = m - 1; + } + } + return false; +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/topics/binary-search/ext-search-in-rotated-sorted-array.md b/topics/binary-search/ext-search-in-rotated-sorted-array.md new file mode 100644 index 0000000..2f78dea --- /dev/null +++ b/topics/binary-search/ext-search-in-rotated-sorted-array.md @@ -0,0 +1,100 @@ +# 33. 搜索旋转排序数组 + +https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + +- [33. 搜索旋转排序数组](#33-搜索旋转排序数组) + - [题目描述](#题目描述) + - [方法 1: 二分法](#方法-1-二分法) + - [思路](#思路) + - [复杂度分析](#复杂度分析) + - [代码](#代码) + +## 题目描述 + +``` +升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。 + +请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + +  + +示例 1: + +输入:nums = [4,5,6,7,0,1,2], target = 0 +输出:4 +示例 2: + +输入:nums = [4,5,6,7,0,1,2], target = 3 +输出:-1 +示例 3: + +输入:nums = [1], target = 0 +输出:-1 +  + +提示: + +1 <= nums.length <= 5000 +-10^4 <= nums[i] <= 10^4 +nums 中的每个值都 独一无二 +nums 肯定会在某个点上旋转 +-10^4 <= target <= 10^4 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法 1: 二分法 + +### 思路 + +旋转数组其实可以分为两个有序的数组,从旋转点切分开,前半部分和后半部分都是有序的。我们按正常的二分法思路,先确定一个中点 mid 的话,那么 + +- 如果 mid 位于 `左侧有序部分`,则从 mid 切分数组后,`左侧是有序的`,右侧是无序的 +- 如果 mid 位于 `右侧有序部分`,则从 mid 切分数组后,`右侧是有序的`,左侧是无序的 + +也就是说我们选定一个中点之后,数组总会被分为有序和无序两个部分,对于有序部分,我们很容易能判断是否需要继续搜索,如果有序部分不满足搜索条件,那我们就将搜索区间缩小为数组无序部分。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/33_0.png) + +### 复杂度分析 + +- 时间复杂度:$O(logn)$,n 为数组长度。 +- 空间复杂度:$O(1)$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function (nums, target) { + let l = 0, + r = nums.length - 1; + while (l <= r) { + const m = l + ((r - l) >> 1); + if (nums[m] === target) return m; + + // m 位于左侧有序部分 + if (nums[l] <= nums[m]) { + // m 大于 target,并且 target 大于左侧最小值,才缩小右边界 + if (nums[m] > target && target >= nums[l]) r = m - 1; + else l = m + 1; + } + // m 位于右侧有序部分 + else { + // m 小于 target,并且 target 小于右侧最大值,才缩小左边界 + if (nums[m] < target && target <= nums[r]) l = m + 1; + else r = m - 1; + } + } + return -1; +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) diff --git a/topics/searching/ext-where-will-the-ball-fall.md b/topics/searching/ext-where-will-the-ball-fall.md new file mode 100644 index 0000000..88c3c82 --- /dev/null +++ b/topics/searching/ext-where-will-the-ball-fall.md @@ -0,0 +1,124 @@ +# 5210. 球会落何处 + +https://leetcode-cn.com/problems/where-will-the-ball-fall/ + +## 题目描述 + +``` +用一个大小为 m x n 的二维网格 grid 表示一个箱子。你有 n 颗球。箱子的顶部和底部都是开着的。 + +箱子中的每个单元格都有一个对角线挡板,跨过单元格的两个角,可以将球导向左侧或者右侧。 + +将球导向右侧的挡板跨过左上角和右下角,在网格中用 1 表示。 +将球导向左侧的挡板跨过右上角和左下角,在网格中用 -1 表示。 +在箱子每一列的顶端各放一颗球。每颗球都可能卡在箱子里或从底部掉出来。如果球恰好卡在两块挡板之间的 "V" 形图案,或者被一块挡导向到箱子的任意一侧边上,就会卡住。 + +返回一个大小为 n 的数组 answer ,其中 answer[i] 是球放在顶部的第 i 列后从底部掉出来的那一列对应的下标,如果球卡在盒子里,则返回 -1 。 + +  + +示例 1: +``` + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/12/26/ball.jpg) + +``` +输入:grid = [[1,1,1,-1,-1],[1,1,1,-1,-1],[-1,-1,-1,1,1],[1,1,1,1,-1],[-1,-1,-1,-1,-1]] +输出:[1,-1,-1,-1,-1] +解释:示例如图: +b0 球开始放在第 0 列上,最终从箱子底部第 1 列掉出。 +b1 球开始放在第 1 列上,会卡在第 2、3 列和第 1 行之间的 "V" 形里。 +b2 球开始放在第 2 列上,会卡在第 2、3 列和第 0 行之间的 "V" 形里。 +b3 球开始放在第 3 列上,会卡在第 2、3 列和第 0 行之间的 "V" 形里。 +b4 球开始放在第 4 列上,会卡在第 2、3 列和第 1 行之间的 "V" 形里。 +示例 2: + +输入:grid = [[-1]] +输出:[-1] +解释:球被卡在箱子左侧边上。 +  + +提示: + +m == grid.length +n == grid[i].length +1 <= m, n <= 100 +grid[i][j] 为 1 或 -1 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/where-will-the-ball-fall +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +``` + +## 方法1: DFS + +### 思路 + +用 DFS,模拟小球的运动轨迹就好了。小球可以从三个方向进入一个格子。 + +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/5210_0.png) + +具体看代码注释。 + +### 复杂度分析 + +- 时间复杂度:$O()$。 +- 空间复杂度:$O()$。 + +### 代码 + +JavaScript Code + +```js +/** + * @param {number[][]} grid + * @return {number[]} + */ +var findBall = function (grid) { + if (!grid || !grid[0]) return []; + + const cols = grid[0].length; + const ans = Array(cols).fill(-1); + + for (let i = 0; i < cols; i++) { + // 一开始所有小球都是从格子上方掉入格子中 + ans[i] = roll(grid, 0, i, 'TOP'); + } + return ans; + + // ****************************** + /** + * @param {number[][]} grid + * @param {number} x + * @param {number} y + * @param {string} 表示小球是从哪个方向进入当前格子的 + */ + function roll(grid, x, y, dir) { + // 顺利掉到了网格下方的 + if (x >= grid.length) return y; + // 左右边界 + if (x < 0 || y < 0 || y >= grid[0].length) return -1; + + // 挡板 + let board = grid[x][y]; + let res = -1; + + // 从上方掉落的,看挡板方向,小球只能滚向左侧或者右侧 + if (dir === 'TOP') { + if (board === 1) res = roll(grid, x, y + 1, 'LEFT'); + else if (board === -1) res = roll(grid, x, y - 1, 'RIGHT'); + } + // 从左右两侧进入的,看挡板方向,小球只能卡在当前格子或者往下掉 + else if ( + (dir === 'LEFT' && board === -1) || + (dir === 'RIGHT' && board === 1) + ) + res = -1; + else res = roll(grid, x + 1, y, 'TOP'); + + return res; + } +}; +``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm) \ No newline at end of file diff --git a/topics/day-68.md b/topics/sliding-window/67.maximum-number-of-vowels-in-a-substring-of-given-length.md similarity index 67% rename from topics/day-68.md rename to topics/sliding-window/67.maximum-number-of-vowels-in-a-substring-of-given-length.md index 22549c4..6fcfbb2 100644 --- a/topics/day-68.md +++ b/topics/sliding-window/67.maximum-number-of-vowels-in-a-substring-of-given-length.md @@ -2,6 +2,12 @@ https://leetcode-cn.com/problems/maximum-number-of-vowels-in-a-substring-of-given-length +- [1456. 定长子串中元音的最大数目](#1456-定长子串中元音的最大数目) + - [题目描述](#题目描述) + - [思路](#思路) + - [复杂度](#复杂度) + - [代码](#代码) + ## 题目描述 ``` @@ -54,8 +60,8 @@ s 由小写英文字母组成 看到题目第一个想法就是滑动窗口了,因为子字符串的长度 k 是固定的,所以真的很简单。 -- 使用一个长度为 k 的窗口从 s 的左侧滑向右侧 -- 分别计算窗口中包含的元音个数,最终返回最大值 +- 使用一个长度为 k 的窗口从 s 的左侧滑向右侧 +- 分别计算窗口中包含的元音个数,最终返回最大值 要点是如何计算窗口中的元音个数?如果窗口每移动一步就遍历计算一次,必然是超时的。 @@ -66,12 +72,12 @@ s 由小写英文字母组成 那这样我们只需要在滑动开始时记录一下窗口中的元音个数 `count`,之后移动窗口时判断左侧丢弃的元素和右侧新增的元素是不是元音,对应地减少或者增加 `count` 就行。 -![temp.png](https://pic.leetcode-cn.com/938297f94d75b5408e096e49ad7d3f28d9da48dbbd962abb33b8c6078af3dea5-temp.png) +![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/1456_0.png) ## 复杂度 -- 时间复杂度:$O(N)$,N 为字符串的长度。 -- 空间复杂度:$O(1)$。 +- 时间复杂度:$O(N)$,N 为字符串的长度。 +- 空间复杂度:$O(1)$。 ## 代码 @@ -82,22 +88,24 @@ s 由小写英文字母组成 * @return {number} */ var maxVowels = function (s, k) { - const vowels = new Set(['a', 'e', 'i', 'o', 'u']); - let count = 0, - l = 0, - r = 0; - while (r < k) { - vowels.has(s[r]) && count++; - r++; - } - let max = count; - while (r < s.length) { - vowels.has(s[r]) && count++; - vowels.has(s[l]) && count--; - l++; - r++; - max = Math.max(max, count); - } - return max; + const vowels = new Set(["a", "e", "i", "o", "u"]); + let count = 0, + l = 0, + r = 0; + while (r < k) { + vowels.has(s[r]) && count++; + r++; + } + let max = count; + while (r < s.length) { + vowels.has(s[r]) && count++; + vowels.has(s[l]) && count--; + l++; + r++; + max = Math.max(max, count); + } + return max; }; ``` + +更多题解可以访问:[https://github.com/suukii/91-days-algorithm](https://github.com/suukii/91-days-algorithm)