diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..36b22ef8 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,39 @@ +name: Deploy Docusaurus Site + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Install dependencies + run: npm install + working-directory: ./leetcode_101 + + - name: Configure Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Build Docusaurus site + run: npm run build + working-directory: ./leetcode_101 + + - name: Deploy to GitHub Pages + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + GIT_USER: ${{ secrets.GH_TOKEN }} + run: npm run deploy + working-directory: ./leetcode_101 diff --git a/leetcode_101/.gitignore b/leetcode_101/.gitignore new file mode 100644 index 00000000..b2d6de30 --- /dev/null +++ b/leetcode_101/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/leetcode_101/README.md b/leetcode_101/README.md new file mode 100644 index 00000000..0c6c2c27 --- /dev/null +++ b/leetcode_101/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +``` +$ USE_SSH=true yarn deploy +``` + +Not using SSH: + +``` +$ GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/leetcode_101/docs/1-greedy-algorithms/1-1-algorithm-explanation.md b/leetcode_101/docs/1-greedy-algorithms/1-1-algorithm-explanation.md new file mode 100644 index 00000000..bb5e2321 --- /dev/null +++ b/leetcode_101/docs/1-greedy-algorithms/1-1-algorithm-explanation.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 1 +--- + +# 1.1 算法解释 + +顾名思义,`贪心算法或贪心思想` (greedy algorithm) 采用贪心的策略,`保证每次操作都是局部最优的`,从而使最后得到的结果是`全局最优的`。 + +举一个最简单的例子:小明和小王喜欢吃苹果,小明可以吃五个,小王可以吃三个。已知苹果园里有吃不完的苹果,求小明和小王一共最多吃多少个苹果。在这个例子中,我们可以选用的贪心策略为,每个人吃自己能吃的最多数量的苹果,这在每个人身上都是局部最优的。又因为全局结果是局部结果的简单求和,且局部结果互不相干,因此局部最优的策略同样是全局最优的。 + +证明一道题能用贪心算法解决,有时远比用贪心算法解决该题更复杂。一般情况下,在简单操作后,具有明显的从局部到整体的递推关系,或者可以通过数学归纳法推测结果时,我们才会使用贪心算法。 diff --git a/leetcode_101/docs/1-greedy-algorithms/1-2-assignment-problems.mdx b/leetcode_101/docs/1-greedy-algorithms/1-2-assignment-problems.mdx new file mode 100644 index 00000000..aef59bf4 --- /dev/null +++ b/leetcode_101/docs/1-greedy-algorithms/1-2-assignment-problems.mdx @@ -0,0 +1,143 @@ +--- +sidebar_position: 2 +--- + +# 1.2 分配问题 + +## [455. Assign Cookies](https://leetcode.com/problems/assign-cookies/) + +### 题目描述 + +有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个饱腹度。每个孩子只能吃一个饼干,且只有饼干的饱腹度不小于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩子可以吃饱。 + +### 输入输出样例 + +输入两个数组,分别代表孩子的饥饿度和饼干的饱腹度。输出可以吃饱的孩子的最大数量。 + +``` +Input: [1,2], [1,2,3] +Output: 2 +``` + +在这个样例中,我们可以给两个孩子喂 [1,2]、[1,3]、[2,3] 这三种组合的任意一种。 + +### 题解 + +因为饥饿度最小的孩子最容易吃饱,所以我们先考虑这个孩子。为了尽量使得剩下的饼干可以满足饥饿度更大的孩子,所以我们应该把大于等于这个孩子饥饿度的、且大小最小的饼干给这个孩子。满足了这个孩子之后,我们采取同样的策略,考虑剩下孩子里饥饿度最小的孩子,直到没有满足条件的饼干存在。 + +简而言之,这里的贪心策略是,给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干。至于具体实现,因为我们需要获得大小关系,一个便捷的方法就是把孩子和饼干分别排序。这样我们就可以从饥饿度最小的孩子和饱腹度最小的饼干出发,计算有多少个对子可以满足条件。 + +:::warning + +对数组或字符串排序是常见的操作,方便之后的大小比较。排序顺序默认是从小到大。 + +::: + +:::warning + +在之后的讲解中,若我们谈论的是对连续空间的变量进行操作,我们并不会明确区分数组和字符串,因为他们本质上都是在连续空间上的有序变量集合。一个字符串“abc”可以被看作一个数组 [‘a’,‘b’,‘c’]。 + +::: + + + + +```cpp +int findContentChildren(vector &children, vector &cookies) { + sort(children.begin(), children.end()); + sort(cookies.begin(), cookies.end()); + int child_i = 0, cookie_i = 0; + int n_children = children.size(), n_cookies = cookies.size(); + while (child_i < n_children && cookie_i < n_cookies) { + if (children[child_i] <= cookies[cookie_i]) { + ++child_i; + } + ++cookie_i; + } + return child_i; +} +``` + + + + +```py +def findContentChildren(children: List[int], cookies: List[int]) -> int: + children.sort() + cookies.sort() + child_i, cookie_i = 0, 0 + n_children, n_cookies = len(children), len(cookies) + while child_i < n_children and cookie_i < n_cookies: + if children[child_i] <= cookies[cookie_i]: + child_i += 1 + cookie_i += 1 + return child_i +``` + + + + + +## [135. Candy](https://leetcode.com/problems/candy/) + +### 题目描述 + +一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果。所有孩子至少要有一个糖果。求解最少需要多少个糖果。 + +### 输入输出样例 + +输入是一个数组,表示孩子的评分。输出是最少糖果的数量。 + +``` +Input: [1,0,2] +Output: 5 +``` +在这个样例中,最少的糖果分法是 [2,1,2]。 + + +### 题解 + +存在比较关系的贪心策略并不一定需要排序。虽然这一道题也是运用贪心策略,但我们只需要简单的两次遍历即可:把所有孩子的糖果数初始化为 1;先从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1;再从右往左遍历一遍,如果左边孩子的评分比右边的高,且左边孩子当前的糖果数不大于右边孩子的糖果数,则左边孩子的糖果数更新为右边孩子的糖果数加 1。通过这两次遍历,分配的糖果就可以满足题目要求了。这里的贪心策略即为,在每次遍历中,只考虑并更新相邻一侧的大小关系。 + +在样例中,我们初始化糖果分配为 [1,1,1],第一次遍历更新后的结果为 [1,1,2],第二次遍历更新后的结果为 [2,1,2]。 + + + + +```cpp +int candy(vector& ratings) { + int n = ratings.size(); + vector candies(n, 1); + for (int i = 1; i < n; ++i) { + if (ratings[i] > ratings[i - 1]) { + candies[i] = candies[i - 1] + 1; + } + } + for (int i = n - 1; i > 0; --i) { + if (ratings[i] < ratings[i - 1]) { + candies[i - 1] = max(candies[i - 1], candies[i] + 1); + } + } + return accumulate(candies.begin(), candies.end(), 0); +} +``` + + + + +```py +def candy(ratings_list: List[int]) -> int: + n = len(ratings_list) + candies = [1] * n + for i in range(1, n): + if ratings_list[i] > ratings_list[i - 1]: + candies[i] = candies[i - 1] + 1 + for i in range(n - 1, 0, -1): + if ratings_list[i] < ratings_list[i - 1]: + candies[i - 1] = max(candies[i - 1], candies[i] + 1) + return sum(candies) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/1-greedy-algorithms/1-3-interval-problems.mdx b/leetcode_101/docs/1-greedy-algorithms/1-3-interval-problems.mdx new file mode 100644 index 00000000..ad2ec4e4 --- /dev/null +++ b/leetcode_101/docs/1-greedy-algorithms/1-3-interval-problems.mdx @@ -0,0 +1,74 @@ +--- +sidebar_position: 3 +--- + +# 1.3 区间问题 + +## [435. Non-overlapping Intervals](https://leetcode.com/problems/non-overlapping-intervals/) + +### 题目描述 + +给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。 + +### 输入输出样例 + +输入是一个数组,包含多个长度固定为 2 的子数组,表示每个区间的开始和结尾。输出一个整数,表示需要移除的区间数量。 + +``` +Input: [[1,2], [2,4], [1,3]] +Output: 1 +``` +在这个样例中,我们可以移除区间 [1,3],使得剩余的区间 [[1,2], [2,4]] 互不重叠。 + + +### 题解 + +求最少的移除区间个数,等价于尽量多保留不重叠的区间。在选择要保留区间时,区间的结尾十分重要:选择的区间结尾越小,余留给其它区间的空间就越大,就越能保留更多的区间。因此,我们采取的贪心策略为,优先保留结尾小且不相交的区间。 + +具体实现方法为,先把区间按照结尾的大小进行增序排序(利用 lambda 函数),每次选择结尾最小且和前一个选择的区间不重叠的区间。 + +在样例中,排序后的数组为 [[1,2], [1,3], [2,4]]。按照我们的贪心策略,首先初始化为区间[1,2];由于 [1,3] 与 [1,2] 相交,我们跳过该区间;由于 [2,4] 与 [1,2] 不相交,我们将其保留。因此最终保留的区间为 [[1,2], [2,4]]。 + +:::warning + +需要根据实际情况判断按区间开头排序还是按区间结尾排序。 + +::: + + + + +```cpp +int eraseOverlapIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end(), + [](vector& a, vector& b) { return a[1] < b[1]; }); + int removed = 0, prev_end = intervals[0][1]; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i][0] < prev_end) { + ++removed; + } else { + prev_end = intervals[i][1]; + } + } + return removed; +} +``` + + + + +```py +def eraseOverlapIntervals(intervals: List[List[int]]) -> int: + intervals.sort(key=lambda x: x[1]) + removed, prev_end = 0, intervals[0][1] + for i in range(1, len(intervals)): + if prev_end > intervals[i][0]: + removed += 1 + else: + prev_end = intervals[i][1] + return removed +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/1-greedy-algorithms/1-4-exercises.md b/leetcode_101/docs/1-greedy-algorithms/1-4-exercises.md new file mode 100644 index 00000000..1d7b4a23 --- /dev/null +++ b/leetcode_101/docs/1-greedy-algorithms/1-4-exercises.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 4 +--- + +# 1.4 练习 + +## 基础难度 + +### [605. Can Place Flowers](https://leetcode.com/problems/can-place-flowers/) + +采取什么样的贪心策略,可以种植最多的花朵呢? + +--- + +### [452. Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) + +这道题和题目 435 十分类似,但是稍有不同,具体是哪里不同呢? + +--- + +### [763. Partition Labels](https://leetcode.com/problems/partition-labels/) + +为了满足你的贪心策略,是否需要一些预处理? + +:::warning + +在处理数组前,统计一遍信息(如频率、个数、第一次出现位置、最后一次出现位置等)可以使题目难度大幅降低。 + +::: + +--- + +### [122. Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) + +股票交易题型里比较简单的题目,在不限制交易次数的情况下,怎样可以获得最大利润呢? + +--- + +## 进阶难度 + + +### [406. Queue Reconstruction by Height](https://leetcode.com/problems/queue-reconstruction-by-height/) + +温馨提示,这道题可能同时需要排序和插入操作。 + + +--- + +### [665. Non-decreasing Array](https://leetcode.com/problems/non-decreasing-array/) + +需要仔细思考你的贪心策略在各种情况下,是否仍然是最优解。 \ No newline at end of file diff --git a/leetcode_101/docs/1-greedy-algorithms/_category_.json b/leetcode_101/docs/1-greedy-algorithms/_category_.json new file mode 100644 index 00000000..4119cb25 --- /dev/null +++ b/leetcode_101/docs/1-greedy-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "1. 最易懂的贪心算法", + "position": 1, + "link": { + "type": "generated-index", + "description": "第 1 章 最易懂的贪心算法" + } +} diff --git a/leetcode_101/docs/10-data-structures/10-1-cpp-stl.md b/leetcode_101/docs/10-data-structures/10-1-cpp-stl.md new file mode 100644 index 00000000..2ec42832 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-1-cpp-stl.md @@ -0,0 +1,30 @@ +--- +sidebar_position: 48 +--- + +# 10.1 C++ STL + +在刷题时,我们几乎一定会用到各种数据结构来辅助我们解决问题,因此我们必须熟悉各种数据结构的特点。C++ STL 提供的数据结构包括(实际底层细节可能因编译器而异): + +1. Sequence Containers:维持顺序的容器。 + 1. vector:`动态数组`,是我们最常使用的数据结构之一,用于 $O(1)$ 的随机读取。因为大部分算法的时间复杂度都会大于 $O(n)$,因此我们经常新建 vector 来存储各种数据或中间变量。因为在尾部增删的复杂度是 $O(1)$,我们也可以把它当作 stack 来用。 + 2. list:`双向链表`,也可以当作 stack 和 queue 来使用。由于 LeetCode 的题目多用 Node 来表示链表,且链表不支持快速随机读取,因此我们很少用到这个数据结构。一个例外是经典的 LRU 问题,我们需要利用链表的特性来解决,我们在后文会遇到这个问题。 + 3. deque:双端队列,这是一个非常强大的数据结构,既支持 $O(1)$ 随机读取,又支持 $O(1)$ 时间的头部增删和尾部增删(因此可以当作 stack 和 queue 来使用),不过有一定的额外开销。也可以用来近似一个双向链表来使用。 + 4. array:固定大小的数组,一般在刷题时我们不使用。 + 5. forward_list:单向链表,一般在刷题时我们不使用。 +2. Container Adaptors:基于其它容器实现的容器。 + 1. stack:`后入先出(LIFO)的数据结构`,默认基于 deque 实现。stack 常用于深度优先搜索、一些字符串匹配问题以及单调栈问题。 + 2. `先入先出(FIFO)的数据结构`,默认基于 deque 实现。queue 常用于广度优先搜索。 + 3. priority_queue:`优先队列(最大值先出的数据结构)`,默认基于 vector 实现堆结构。它可以在 $O(n \log n)$ 的时间排序数组,$O(\log n)$ 的时间插入任意值,$O(1)$ 的时间获得最大值,$O(\log n)$ 的时间删除最大值。priority_queue 常用于维护数据结构并快速获取最大值,并且可以自定义比较函数;比如通过存储负值或者更改比小函数为比大函数,即可实现最小值先出。 +3. Ordered Associative Containers:有序关联容器。 + 1. set:有序集合,元素不可重复,底层实现默认为红黑树,即一种特殊的二叉查找树(BST)。它可以在 $O(n \log n)$ 的时间排序数组,$O(\log n)$ 的时间插入、删除、查找任意值,$O(\log n)$ 的时间获得最小或最大值。这里注意,set 和 priority_queue 都可以用于维护数据结构并快速获取最大最小值,但是它们的时间复杂度和功能略有区别,如 priority_queue 默认不支持删除任意值,而 set 获得最大或最小值的时间复杂度略高,具体使用哪个根据需求而定。 + 2. multiset:支持重复元素的 set。 + 3. map:`有序映射或有序表`,在 set 的基础上加上映射关系,可以对每个元素 key 存一个值 value。 + 4. multimap:支持重复元素的 map。 +4. Unordered Associative Containers:无序关联容器。 + 1. unordered_set:`哈希集合`,可以在 $O(1)$ 的时间快速插入、查找、删除元素,常用于快速的查询一个元素是否在这个容器内。 + 2. unordered_multiset:支持重复元素的 unordered_set。 + 3. unordered_map:`哈希映射或哈希表`,在 unordered_set 的基础上加上映射关系,可以对每一个元素 key 存一个值 value。在某些情况下,如果 key 的范围已知且较小,我们也可以用 vector 代替 unordered_map,用位置表示 key,用每个位置的值表示 value。 + 4. unordered_multimap:支持重复元素的 unordered_map。 + +因为这并不是一本讲解 C++ 原理的书,更多的 STL 细节请读者自行搜索。只有理解了这些数据结构的原理和使用方法,才能够更加游刃有余地解决算法和数据结构问题。 diff --git a/leetcode_101/docs/10-data-structures/10-10-prefix-sum-integral-image.mdx b/leetcode_101/docs/10-data-structures/10-10-prefix-sum-integral-image.mdx new file mode 100644 index 00000000..16e8f7cd --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-10-prefix-sum-integral-image.mdx @@ -0,0 +1,226 @@ +--- +sidebar_position: 57 +--- + +# 10.10 前缀和与积分图 + +一维的前缀和(cumulative sum, cumsum),二维的积分图(summed-area table, image integral)都是把每个位置之前的一维线段或二维矩形预先存储,方便加速计算。如果需要对前缀和或积分图的值做寻址,则要存入哈希表;如果要对每个位置记录前缀和或积分图的值,则可以储存到一维或二维数组里,也常常伴随着动态规划。 + +## [303. Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable/) + +### 题目描述 + +设计一个数据结构,使得其能够快速查询给定数组中,任意两个位置间所有数字的和。 + +### 输入输出样例 + +以下是数据结构的调用样例。 + +``` +vector nums{-2,0,3,-5,2,-1}; +NumArray num_array = new NumArray(nums); +num_array.sumRange(0,2); // Result = -2+0+3 = 1. +num_array.sunRange(1,5); // Result = 0+3-5+2-1 = -1. +``` + +### 题解 + +对于一维的数组,我们可以使用前缀和来解决此类问题。先建立一个与数组 nums 长度相同的新数组 cumsum,表示 nums 每个位置之前前所有数字的和。cumsum 数组可以通过 C++ 自带的 partial_sum 函数建立,也可以直接遍历一遍 nums 数组,并利用状态转移方程 cumsum[i] = cumsum[i-1] + nums[i] 完成统计。如果我们需要获得位置 i 和 j 之间的数字和,只需计算 cum - sum[j+1] - cumsum[i] 即可。 + + + + +```cpp +class NumArray { + public: + NumArray(vector nums) : cumsum_(nums.size() + 1, 0) { + partial_sum(nums.begin(), nums.end(), cumsum_.begin() + 1); + } + + int sumRange(int left, int right) { + return cumsum_[right + 1] - cumsum_[left]; + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class NumArray: + def __init__(self, nums: List[int]): + self.cumsum = [0] + nums[:] + for i in range(2, len(self.cumsum)): + self.cumsum[i] += self.cumsum[i - 1] + + def sumRange(self, left: int, right: int) -> int: + return self.cumsum[right + 1] - self.cumsum[left] +``` + + + + + +## [304. Range Sum Query 2D - Immutable](https://leetcode.com/problems/range-sum-query-2d-immutable/) + +### 题目描述 + +设计一个数据结构,使得其能够快速查询给定矩阵中,任意两个位置包围的长方形中所有数字的和。 + +### 输入输出样例 + +以下是数据结构的调用样例。其中 sumRegion 函数的四个输入分别是第一个点的横、纵坐标,和第二个点的横、纵坐标。 + +``` +vector matrix{{3,0,1,4,2}, + {5,6,3,2,1}, + {1,2,0,1,5}, + {4,1,0,1,7}, + {1,0,3,0,5} +}; +NumMatrix num_matrix = new NumMatrix(matrix); +num_matrix.sumRegion(2,1,4,3); // Result = 8. +num_matrix.sumRegion(1,1,2,2); // Result = 11. +``` + +### 题解 + +类似于前缀和,我们可以把这种思想拓展到二维,即积分图(summed-area table, image integral)。我们可以先建立一个 sat 矩阵,sat[i][j] 表示以位置 (0, 0) 为左上角、位置 (i-1, j-1) 为右下角的长方形中所有数字的和。 + +
+ + ![](10.4.png) + +
图 10.4: 题目 304 - 图 1 - 左边为给定矩阵,右边为积分图结果,右下角位置的积分图值为 5+48+45− 40 =58
+
+ + +
+ + ![](10.5.png) + +
图 10.5: 题目 304 - 图 2 - 左边为给定矩阵,右边为积分图结果,长方形 E 的数字和等于 58 − 11 − 13 +3 =37
+
+ +如图 1 所示,我们可以用动态规划来计算 sat 矩阵:sat[i][j] = matrix[i-1][j-1] + sat[i-1][j] + sat[i][j-1] - sat[i-1][j-1],即当前坐标的数字 + 上面长方形的数字和 + 左边长方形的数字和 - 上面长方形和左边长方形重合面积(即左上一格的长方形)中的数字和。 + +如图 2 所示,假设我们要查询长方形 E 的数字和,因为 E = D − B − C + A,我们发现 E 其实可以由四个位置的积分图结果进行加减运算得到。因此这个算法在预处理时的时间复杂度为 $O(mn)$,而在查询时的时间复杂度仅为 $O(1)$。 + + + + +```cpp +class NumMatrix { + public: + NumMatrix(vector> matrix) { + int m = matrix.size(), n = matrix[0].size(); + sat_ = vector>(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + sat_[i][j] = matrix[i - 1][j - 1] + sat_[i - 1][j] + + sat_[i][j - 1] - sat_[i - 1][j - 1]; + } + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sat_[row2 + 1][col2 + 1] - sat_[row2 + 1][col1] - + sat_[row1][col2 + 1] + sat_[row1][col1]; + } + + private: + vector> sat_; +}; +``` + + + + +```py +class NumMatrix: + def __init__(self, matrix: List[List[int]]): + m, n = len(matrix), len(matrix[0]) + self.sat = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + self.sat[i][j] = ( + matrix[i - 1][j - 1] + + self.sat[i - 1][j] + + self.sat[i][j - 1] + - self.sat[i - 1][j - 1] + ) + + def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int: + return ( + self.sat[row2 + 1][col2 + 1] + - self.sat[row2 + 1][col1] + - self.sat[row1][col2 + 1] + + self.sat[row1][col1] + ) + +``` + + + + + +## [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) + +### 题目描述 + +给定一个数组,寻找和为 k 的连续区间个数。 + +### 输入输出样例 + +输入一个一维整数数组和一个整数值 k;输出一个整数,表示满足条件的连续区间个数。 + +``` +Input: nums = [1,1,1], k = 2 +Output: 2 +``` + +在这个样例中,我们可以找到两个 [1,1] 连续区间满足条件。 + +### 题解 + +本题同样是利用前缀和,不同的是这里我们使用一个哈希表 cache,其键是前缀和,而值是该前缀和出现的次数。在我们遍历到位置 i 时,假设当前的前缀和是 cumsum,那么 cache[cumsum-k] 即为以当前位置结尾、满足条件的区间个数。 + + + + +```cpp +int subarraySum(vector& nums, int k) { + int count = 0, cumsum = 0; + unordered_map cache; // + cache[0] = 1; + for (int num : nums) { + cumsum += num; + count += cache[cumsum - k]; + ++cache[cumsum]; + } + return count; +} +``` + + + + +```py +def subarraySum(nums: List[int], k: int) -> int: + count, cur_sum = 0, 0 + cache = {0: 1} # + for num in nums: + cur_sum += num + count += cache.get(cur_sum - k, 0) + cache[cur_sum] = cache.get(cur_sum, 0) + 1 + return count +``` + + + + + diff --git a/leetcode_101/docs/10-data-structures/10-11-exercises.md b/leetcode_101/docs/10-data-structures/10-11-exercises.md new file mode 100644 index 00000000..8ca0e841 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-11-exercises.md @@ -0,0 +1,73 @@ +--- +sidebar_position: 58 +--- + +# 10.11 练习 + +## 基础难度 + +### [566. Reshape the Matrix](https://leetcode.com/problems/reshape-the-matrix/) + +没有什么难度,只是需要一点耐心。 + +--- + +### [225. Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues/) + +利用相似的方法,我们也可以用 queue 实现 stack。 + +--- + +### [503. Next Greater Element II](https://leetcode.com/problems/next-greater-element-ii/) + +Daily Temperature 的变种题。 + +--- + +### [217. Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) + +使用什么数据结构可以快速判断重复呢? + +--- + +### [697. Degree of an Array](https://leetcode.com/problems/degree-of-an-array/) + +如何对数组进行预处理才能正确并快速地计算子数组的长度? + +--- + +### [594. Longest Harmonious Subsequence](https://leetcode.com/problems/longest-harmonious-subsequence/) + +最长连续序列的变种题。 + +--- + +### [15. 3Sum](https://leetcode.com/problems/3sum/) + +因为排序的复杂度是 $O(n \log n) < O(n^2)$,因此我们既可以排序后再进行 $O(n^2)$ 的指针搜索,也可以直接利用哈希表进行 $O(n^2)$ 的搜索。 + +--- + +## 进阶难度 + +### [287. Find the Duplicate Number](https://leetcode.com/problems/find-the-duplicate-number/) + +寻找丢失数字的变种题。除了标负位置,你还有没有其它算法可以解决这个问题? + +--- + +### [313. Super Ugly Number](https://leetcode.com/problems/super-ugly-number/) + +尝试使用优先队列解决这一问题。 + +--- + +### [870. Advantage Shuffle](https://leetcode.com/problems/advantage-shuffle/) + +如果我们需要比较大小关系,而且同一数字可能出现多次,那么应该用什么数据结构呢? + +--- + +### [307. Range Sum Query - Mutable](https://leetcode.com/problems/range-sum-query-mutable/) + +前缀和的变种题。好吧我承认,这道题可能有些超纲,你或许需要搜索一下什么是线段树。 \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-2-python-data-structures.md b/leetcode_101/docs/10-data-structures/10-2-python-data-structures.md new file mode 100644 index 00000000..906ce872 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-2-python-data-structures.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 49 +--- + +# 10.2 Python 常用数据结构 + +类似于 C++ STL,Python 也提供了类似的数据结构(实际底层细节可能因编译器而异): + +1. Sequence Containers:维持顺序的容器。 + 1. list:`动态数组`,是我们最常使用的数据结构之一,用于 $O(1)$ 的随机读取。因为大部分算法的时间复杂度都会大于 $O(n)$,因此我们经常新建 list 来存储各种数据或中间变量。因为在尾部增删的复杂度是 $O(1)$,我们也可以把它当作 stack 来用。 + 2. tuple: `元组`,immutable list,不可改变其中元素或总长度。 + 3. collections.deque:`双端队列`,这是一个非常强大的数据结构,既支持 $O(1)$ 随机读取,又支持 $O(1)$ 时间的头部增删和尾部增删(因此可以当作 stack 和 queue 来使用),不过有一定的额外开销。也可以用来近似一个双向链表来使用。 +2. Container Adaptors:基于其它容器实现的容器。 + 1. heapq:`最小堆(最小值先出的数据结构)`,默认基于 list 实现堆结构。它可以在 $O(n \log n)$ 的时间排序数组,$O(\log n)$ 的时间插入任意值,$O(1)$ 的时间获得最小值,$O(\log n)$ 的时间删除最小值。heapq 常用于维护数据结构并快速获取最小值,但不支持自定义比较函数。所以通常我们需要提前算好自定义值,再把 (自定义值,位置) 的 tuple 存进 heapq。这样进行比较时就会默认从左到右比较 tuple 中的元素,即先比较自定义值,再比较元素的插入次序。 +3. Ordered Associative Containers:有序关联容器。 + 1. collections.OrderedDict:`顺序映射或顺序表`,注意这里的 Ordered 不同于 C++ 中 map的按大小排序,而是按照插入的先后次序排序。OrderedDict 很适合用来做 LRU。 +4. Unordered Associative Containers:无序关联容器。 + 1. set:`哈希集合`,可以在 $O(1)$ 的时间快速插入、查找、删除元素,常用于快速的查询一个元素是否在这个容器内。 + 2. dict:`哈希映射或哈希表`,在 set 的基础上加上映射关系,可以对每一个元素 key 存一个值 value。在某些情况下,如果 key 的范围已知且较小,我们也可以用 list 代替 dict,用位置表示 key,用每个位置的值表示 value。 + 3. collections.Counter:`计数器`,是 dict 的一个特殊版本,可以直接传入一个 list,并对其中的每一个元素进行计数统计,key 是元素值,value 是元素出现的频次。可以用来当作多重集合。 + +同样的,因为这并不是一本讲解 Python 原理的书,更多的数据结构细节请读者自行搜索。只有理解了这些数据结构的原理和使用方法,才能够更加游刃有余地解决算法和数据结构问题。 \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-3-arrays.mdx b/leetcode_101/docs/10-data-structures/10-3-arrays.mdx new file mode 100644 index 00000000..11741a06 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-3-arrays.mdx @@ -0,0 +1,250 @@ +--- +sidebar_position: 50 +--- + +# 10.3 数组 + +## [448. Find All Numbers Disappeared in an Array](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/) + +### 题目描述 + +给定一个长度为 n 的数组,其中包含范围为 1 到 n 的整数,有些整数重复了多次,有些整数没有出现,求 1 到 n 中没有出现过的整数。 + +### 输入输出样例 + +输入是一个一维整数数组,输出也是一个一维整数数组,表示输入数组内没出现过的数字。 + +``` +Input: [4,3,2,7,8,2,3,1] +Output: [5,6] +``` + +利用数组这种数据结构建立 n 个桶,把所有重复出现的位置进行标记,然后再遍历一遍数组,即可找到没有出现过的数字。进一步地,我们可以直接对原数组进行标记:把重复出现的数字-1在原数组的位置设为负数(这里-1 的目的是把 1 到 n 的数字映射到 0 到 n-1 的位置),最后仍然为正数的位置 +1 即为没有出现过的数。 + +### 题解 + + + + + + +```cpp +vector findDisappearedNumbers(vector& nums) { + vector disappeared; + for (int num : nums) { + int pos = abs(num) - 1; + if (nums[pos] > 0) { + nums[pos] = -nums[pos]; + } + } + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] > 0) { + disappeared.push_back(i + 1); + } + } + return disappeared; +} +``` + + + + +```py +def findDisappearedNumbers(nums: List[int]) -> List[int]: + for num in nums: + pos = abs(num) - 1 + if nums[pos] > 0: + nums[pos] = -nums[pos] + return [i + 1 for i in range(len(nums)) if nums[i] > 0] +``` + + + + + +## [48. Rotate Image](https://leetcode.com/problems/rotate-image/) + +### 题目描述 + +给定一个 n × n 的矩阵,求它顺时针旋转 90 度的结果,且必须在原矩阵上修改(in-place)。怎样能够尽量不创建额外储存空间呢? + +### 输入输出样例 + +输入和输出都是一个二维整数矩阵。 + +``` +Input: +[[1,2,3], + [4,5,6], + [7,8,9]] +Output: +[[7,4,1], + [8,5,2], + [9,6,3]] +``` + +### 题解 + +每次只考虑四个间隔 90 度的位置,可以进行 O(1) 额外空间的旋转。 + +
+ + ![](10.1.png) + +
图 10.1: 题目 48 - $O(1)$ 空间旋转样例,相同颜色代表四个互相交换的位置
+
+ + + + +```cpp +void rotate(vector>& matrix) { + int pivot = 0, n = matrix.size() - 1; + for (int i = 0; i <= n / 2; ++i) { + for (int j = i; j < n - i; ++j) { + pivot = matrix[j][n - i]; + matrix[j][n - i] = matrix[i][j]; + matrix[i][j] = matrix[n - j][i]; + matrix[n - j][i] = matrix[n - i][n - j]; + matrix[n - i][n - j] = pivot; + } + } +} +``` + + + + +```py +def rotate(matrix: List[List[int]]) -> None: + n = len(matrix) - 1 + for i in range(n // 2 + 1): + for j in range(i, n - i): + pivot = matrix[j][n - i] + matrix[j][n - i] = matrix[i][j] + matrix[i][j] = matrix[n - j][i] + matrix[n - j][i] = matrix[n - i][n - j] + matrix[n - i][n - j] = pivot +``` + + + + + +## [240. Search a 2D Matrix II](https://leetcode.com/problems/search-a-2d-matrix-ii/) + +### 题目描述 + +给定一个二维矩阵,已知每行和每列都是增序的,尝试设计一个快速搜索一个数字是否在矩阵中存在的算法。 + +### 输入输出样例 + +输入是一个二维整数矩阵,和一个待搜索整数。输出是一个布尔值,表示这个整数是否存在于矩阵中。 + +``` +Input: matrix = +[ [1, 4, 7, 11, 15], + [2, 5, 8, 12, 19], + [3, 6, 9, 16, 22], + [10, 13, 14, 17, 24], + [18, 21, 23, 26, 30]], target = 5 +Output: true +``` + +### 题解 + +这道题有一个简单的技巧:我们可以从右上角开始查找,若当前值大于待搜索值,我们向左移动一位;若当前值小于待搜索值,我们向下移动一位。如果最终移动到左下角时仍不等于待搜索值,则说明待搜索值不存在于矩阵中。 + + + + +```cpp +bool searchMatrix(vector>& matrix, int target) { + int m = matrix.size(), n = matrix[0].size(); + int i = 0, j = n - 1; + while (i < m && j >= 0) { + if (matrix[i][j] == target) { + return true; + } else if (matrix[i][j] < target) { + ++i; + } else { + --j; + } + } + return false; +} +``` + + + + +```py +def searchMatrix(matrix: List[List[int]], target: int) -> bool: + m, n = len(matrix), len(matrix[0]) + i, j = 0, n - 1 + while i < m and j >= 0: + if matrix[i][j] == target: + return True + if matrix[i][j] < target: + i += 1 + else: + j -= 1 + return False +``` + + + + + +## [769. Max Chunks To Make Sorted](https://leetcode.com/problems/max-chunks-to-make-sorted/) + +### 题目描述 + +给定一个含有 0 到 n 整数的数组,每个整数只出现一次,求这个数组最多可以分割成多少个子数组,使得对每个子数组进行增序排序后,原数组也是增序的。 + +### 输入输出样例 + +输入一个一维整数数组,输出一个整数,表示最多的分割数。 + +``` +Input: [1,0,2,3,4] +Output: 4 +``` + +在这个样例中,最多分割是 [1, 0], [2], [3], [4]。 + +### 题解 + +从左往右遍历,同时记录当前的最大值,每当当前最大值等于数组位置时,我们可以多一次分割。 + +为什么可以通过这个算法解决问题呢?如果当前最大值大于数组位置,则说明右边一定有小于数组位置的数字,需要把它也加入待排序的子数组;又因为数组只包含不重复的 0 到 n,所以当前最大值一定不会小于数组位置。所以每当当前最大值等于数组位置时,假设为 p,我们可以成功完成一次分割,并且其与上一次分割位置 q 之间的值一定是 q +1 到 p 的所有数字。 + + + + +```cpp +int maxChunksToSorted(vector& arr) { + int chunks = 0, cur_max = 0; + for (int i = 0; i < arr.size(); ++i) { + cur_max = max(cur_max, arr[i]); + chunks += cur_max == i; + } + return chunks; +} +``` + + + + +```py +def maxChunksToSorted(arr: List[int]) -> int: + chunks, cur_max = 0, 0 + for i, num in enumerate(arr): + cur_max = max(cur_max, num) + chunks += cur_max == i + return chunks +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-4-stack-and-queue.mdx b/leetcode_101/docs/10-data-structures/10-4-stack-and-queue.mdx new file mode 100644 index 00000000..403a3c5a --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-4-stack-and-queue.mdx @@ -0,0 +1,257 @@ +--- +sidebar_position: 51 +--- + +# 10.4 栈和队列 + +## [232. Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks/) + +### 题目描述 + +尝试使用栈(stack)来实现队列(queue)。 + +### 输入输出样例 + +以下是数据结构的调用样例。 + +``` +MyQueue queue = new MyQueue(); +queue.push(1); +queue.push(2); +queue.peek(); // returns 1 +queue.pop(); // returns 1 +queue.empty(); // returns false +``` + +### 题解 + +我们可以用两个栈来实现一个队列:因为我们需要得到先入先出的结果,所以必定要通过一个额外栈翻转一次数组。这个翻转过程既可以在插入时完成,也可以在取值时完成。我们这里展示在取值时完成的写法。 + + + + +```cpp +class MyQueue { + public: + MyQueue() {} + + void push(int x) { s_in_.push(x); } + + int pop() { + in2out(); + int x = s_out_.top(); + s_out_.pop(); + return x; + } + + int peek() { + in2out(); + return s_out_.top(); + } + + bool empty() { return s_in_.empty() && s_out_.empty(); } + + private: + void in2out() { + if (!s_out_.empty()) { + return; + } + while (!s_in_.empty()) { + int x = s_in_.top(); + s_in_.pop(); + s_out_.push(x); + } + } + + stack s_in_, s_out_; +}; +``` + + + + +```py +class MyQueue: + def __init__(self): + self.s_in = [] + self.s_out = [] + + def _in2out(self): + if len(self.s_out) > 0: + return + while len(self.s_in) > 0: + self.s_out.append(self.s_in.pop()) + + def push(self, x: int) -> None: + self.s_in.append(x) + + def pop(self) -> int: + self._in2out() + return self.s_out.pop() + + def peek(self) -> int: + self._in2out() + return self.s_out[-1] + + def empty(self) -> bool: + return len(self.s_in) == 0 and len(self.s_out) == 0 +``` + + + + + +## [155. Min Stack](https://leetcode.com/problems/min-stack/) + +### 题目描述 + +设计一个最小栈,除了需要支持常规栈的操作外,还需要支持在 $O(1)$ 时间内查询栈内最小值的功能。 + +### 输入输出样例 + +以下是数据结构的调用样例。 + +``` +MinStack minStack = new MinStack(); +minStack.push(-2); +minStack.push(0); +minStack.push(-3); +minStack.getMin(); // Returns -3. +minStack.pop(); +minStack.top(); // Returns 0. +minStack.getMin(); // Returns -2. +``` + +### 题解 + +我们可以额外建立一个新栈,栈顶表示原栈里所有值的最小值。每当在原栈里插入一个数字时,若该数字小于等于新栈栈顶,则表示这个数字在原栈里是最小值,我们将其同时插入新栈内。每当从原栈里取出一个数字时,若该数字等于新栈栈顶,则表示这个数是原栈里的最小值之一,我们同时取出新栈栈顶的值。 + +一个写起来更简单但是时间复杂度略高的方法是,我们每次插入原栈时,都向新栈插入一次原栈里所有值的最小值(新栈栈顶和待插入值中小的那一个);每次从原栈里取出数字时,同样取出新栈的栈顶。这样可以避免判断,但是每次都要插入和取出。我们这里只展示第一种写法。 + + + + +```cpp +class MinStack { + public: + MinStack() {} + + void push(int x) { + s_.push(x); + if (min_s_.empty() || min_s_.top() >= x) { + min_s_.push(x); + } + } + + void pop() { + if (!min_s_.empty() && min_s_.top() == s_.top()) { + min_s_.pop(); + } + s_.pop(); + } + + int top() { return s_.top(); } + + int getMin() { return min_s_.top(); } + + private: + stack s_, min_s_; +}; +``` + + + + +```py +class MinStack: + def __init__(self): + self.s = [] + self.min_s = [] + + def push(self, x: int) -> None: + self.s.append(x) + if len(self.min_s) == 0 or self.min_s[-1] >= x: + self.min_s.append(x) + + def pop(self) -> None: + if len(self.min_s) != 0 and self.s[-1] == self.min_s[-1]: + self.min_s.pop() + self.s.pop() + + def top(self) -> int: + return self.s[-1] + + def getMin(self) -> int: + return self.min_s[-1] +``` + + + + + + +## [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) + +### 题目描述 + +给定一个只由左右圆括号、花括号和方括号组成的字符串,求这个字符串是否合法。合法的定义是每一个类型的左括号都有一个右括号一一对应,且括号内的字符串也满足此要求。 + +### 输入输出样例 + +输入是一个字符串,输出是一个布尔值,表示字符串是否合法。 + +``` +Input: "{[]}()" +Output: true +``` + +### 题解 + +括号匹配是典型的使用栈来解决的问题。我们从左往右遍历,每当遇到左括号便放入栈内,遇到右括号则判断其和栈顶的括号是否是统一类型,是则从栈内取出左括号,否则说明字符串不合法。 + + + + +```cpp +bool isValid(string s) { + stack parsed; + unordered_map matches{{’(’, ’)’}, {’{’, ’}’}, {’[’, ’]’}}; + for (char c : s) { + if (matches.contains(c)) { + parsed.push(c); + continue; + } + if (parsed.empty()) { + return false; + } + if (c != matches[parsed.top()]) { + return false; + } + parsed.pop(); + } + return parsed.empty(); +} +``` + + + + +```py +def isValid(s: str) -> bool: + parsed = [] + matches = {"{": "}", "(": ")", "[": "]"} + for c in s: + if c in matches.keys(): + parsed.append(c) + continue + if len(parsed) == 0: + return False + if c != matches[parsed[-1]]: + return False + parsed.pop() + return len(parsed) == 0 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-5-monotonic-stack.mdx b/leetcode_101/docs/10-data-structures/10-5-monotonic-stack.mdx new file mode 100644 index 00000000..a9dc695b --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-5-monotonic-stack.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 52 +--- + +# 10.5 单调栈 + +`单调栈`通过维持栈内值的单调递增(递减)性,在整体 $O(n)$ 的时间内处理需要大小比较的问题。 + +## [739. Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) + +### 题目描述 + +给定每天的温度,求对于每一天需要等几天才可以等到更暖和的一天。如果该天之后不存在更暖和的天气,则记为 0。 + +### 输入输出样例 + +输入是一个一维整数数组,输出是同样长度的整数数组,表示对于每天需要等待多少天。 + +``` +Input: [73, 74, 75, 71, 69, 72, 76, 73] +Output: [1, 1, 4, 2, 1, 1, 0, 0] +``` + +### 题解 + +我们可以维持一个单调递减的栈,表示每天的温度;为了方便计算天数差,我们这里存放位置(即日期)而非温度本身。我们从左向右遍历温度数组,对于每个日期 p,如果 p 的温度比栈顶存储位置 q 的温度高,则我们取出 q,并记录 q 需要等待的天数为 p − q;我们重复这一过程,直到 p 的温度小于等于栈顶存储位置的温度(或空栈)时,我们将 p 插入栈顶,然后考虑下一天。在这个过程中,栈内数组永远保持单调递减,避免了使用排序进行比较。最后若栈内剩余一些日期,则说明它们之后都没有出现更暖和的日期。 + + + + +```cpp +vector dailyTemperatures(vector& temperatures) { + int n = temperatures.size(); + vector days_to_wait(n, 0); + stack mono_stack; + for (int i = 0; i < n; ++i) { + while (!mono_stack.empty()) { + int j = mono_stack.top(); + if (temperatures[i] <= temperatures[j]) { + break; + } + mono_stack.pop(); + days_to_wait[j] = i - j; + } + mono_stack.push(i); + } + return days_to_wait; +} +``` + + + + +```py +def dailyTemperatures(temperatures: List[int]) -> List[int]: + n = len(temperatures) + days_to_wait = [0] * n + mono_stack = [] + for i in range(n): + while len(mono_stack) > 0: + j = mono_stack[-1] + if temperatures[i] <= temperatures[j]: + break + mono_stack.pop() + days_to_wait[j] = i - j + mono_stack.append(i) + return days_to_wait +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-6-priority-queue.mdx b/leetcode_101/docs/10-data-structures/10-6-priority-queue.mdx new file mode 100644 index 00000000..8abab8ef --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-6-priority-queue.mdx @@ -0,0 +1,295 @@ +--- +sidebar_position: 53 +--- + +# 10.6 优先队列 + +`优先队列`(priority queue)可以在 $O(1)$ 时间内获得最大值,并且可以在 O(log n) 时间内取出最大值或插入任意值。 + +
+ + ![](10.2.png) + +
图 10.2: (最大)堆,维护的是数据结构中的大于关系
+
+ +优先队列常常用堆(heap)来实现。堆是一个完全二叉树,其每个节点的值总是大于等于子节点的值。实际实现堆时,我们通常用一个数组而不是用指针建立一个树。这是因为堆是完全二叉树,所以用数组表示时,位置 i 的节点的父节点位置一定为 (i-1)/2,而它的两个子节点的位置又一定分别为 2i+1 和 2i+2。 + +以下是堆的实现方法,其中最核心的两个操作是上浮和下沉:如果一个节点比父节点大,那么需要交换这个两个节点;交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操作,我们称之为上浮;类似地,如果一个节点比父节小,也需要不断地向下进行比较和交换操作我们称之为下沉。如果一个节点有两个子节点,我们总是交换最大的子节点。 + + + + + +```cpp +class Heap { + public: + Heap() {} + // 上浮。 + void swim(int pos) { + int next_pos = (pos - 1) / 2; + while (pos > 0 && heap_[next_pos] < heap_[pos]) { + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = (pos - 1) / 2; + } + } + // 下沉。 + void sink(int pos) { + int n = heap_.size(); + int next_pos = 2 * pos + 1; + while (next_pos < n) { + if (next_pos < n - 1 && heap_[next_pos] < heap_[next_pos + 1]) { + ++next_pos; + } + if (heap_[pos] >= heap_[next_pos]) { + break; + } + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = 2 * pos + 1; + } + } + // 插入任意值:把新的数字放在最后一位,然后上浮。 + void push(int k) { + heap_.push_back(k); + swim(heap_.size() - 1); + } + // 删除最大值:把最后一个数字挪到开头,然后下沉。 + void pop() { + heap_[0] = heap_.back(); + heap_.pop_back(); + sink(0); + } + // 获得最大值。 + int top() { return heap_[0]; } + + private: + vector heap_; +}; +``` + + + + +```py +class Heap: + def __init__(self): + self.heap = [] + + # 上浮。 + def swim(self, pos: int): + next_pos = (pos - 1) // 2 + while pos > 0 and self.heap[next_pos] < self.heap[pos]: + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = (pos - 1) // 2 + + # 下沉。 + def sink(self, pos: int): + n = len(self.heap) + next_pos = 2 * pos + 1 + while next_pos < n: + if next_pos < n - 1 and self.heap[next_pos] < self.heap[next_pos + 1]: + next_pos += 1 + if self.heap[pos] >= self.heap[next_pos]: + break + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = 2 * pos + 1 + + # 插入任意值:把新的数字放在最后一位,然后上浮。 + def push(self, k: int): + self.heap.append(k) + self.swim(len(self.heap) - 1) + + # 删除最大值:把最后一个数字挪到开头,然后下沉。 + def pop(self): + self.heap[0] = self.heap.pop() + self.sink(0) + + # 获得最大值。 + def top(self) -> int: + return self.heap[0] + +``` + + + + + +通过将算法中的大于号和小于号互换,我们也可以得到一个快速获得最小值的优先队列。 + +## [23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) + +### 题目描述 + +给定 k 个增序的链表,试将它们合并成一条增序链表。 + +### 输入输出样例 + +输入是一个一维数组,每个位置存储链表的头节点;输出是一条链表。 + +``` +Input: +[1->4->5, + 1->3->4, + 2->6] +Output: 1->1->2->3->4->4->5->6 +``` + +### 题解 + +本题可以有很多中解法,比如类似于归并排序进行两两合并。我们这里展示一个速度比较快的方法,即把所有的链表存储在一个优先队列中,每次提取所有链表头部节点值最小的那个节点,直到所有链表都被提取完为止。 + +因为 C++ priority_queue 的比较函数默认是对最大堆进行比较并维持递增关系,如果我们想要获取最小的节点值,我们则需要实现一个最小堆。因此堆的比较函数应该维持递减关系,即 lambda 函数中返回时用大于号而不是递增关系时的小于号进行比较。 + + + + +```cpp +ListNode* mergeKLists(vector& lists) { + auto comp = [](ListNode* l1, ListNode* l2) { return l1->val > l2->val; }; + priority_queue, decltype(comp)> pq; + for (ListNode* l : lists) { + if (l) { + pq.push(l); + } + } + ListNode *dummy = new ListNode(0), *cur = dummy; + while (!pq.empty()) { + cur->next = pq.top(); + pq.pop(); + cur = cur->next; + if (cur->next) { + pq.push(cur->next); + } + } + return dummy->next; +} +``` + + + + +```py +def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]: + pq = [] + for idx, l in enumerate(lists): + if l is not None: + # ListNode不可被哈希,所以这里我们直接记录它在lists中的位置。 + pq.append((l.val, idx)) + heapq.heapify(pq) + + dummy = ListNode() + cur = dummy + + while len(pq) > 0: + _, l_idx = heapq.heappop(pq) + cur.next = lists[l_idx] + cur = cur.next + if cur.next is not None: + lists[l_idx] = lists[l_idx].next + heapq.heappush(pq, (cur.next.val, l_idx)) + + return dummy.next + +``` + + + + + +## [218. The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) + +### 题目描述 + +给定建筑物的起止位置和高度,返回建筑物轮廓(天际线)的拐点。 + +### 输入输出样例 + +输入是一个二维整数数组,表示每个建筑物的 [左端, 右端, 高度];输出是一个二维整数数组,表示每个拐点的横纵坐标。 + +
+ + ![](10.3.png) + +
图 10.3: 题目 218 - 建筑物及其天际线样例
+
+ +``` +Input: [[2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8]] +Output: [[2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0]] +``` + +### 题解 + +我们可以使用优先队列储存每个建筑物的高度和右端(这里使用 pair,其默认比较函数是先比较第一个值,如果相等则再比较第二个值),从而获取目前会拔高天际线、且妨碍到前一个建筑物(的右端端点)的下一个建筑物。 + +因为 Python 中 heapq 是最小堆,所以我们在存值的时候可以存负值,这样就变成了最大堆。 + +这道题比较复杂,如果实在难以理解,建议读者暂时跳过此题,或者在纸上举例子画一画。 + + + + +```cpp +vector> getSkyline(vector>& buildings) { + vector> skyline; + priority_queue> pq; // <高度, 右端> + int i = 0, n = buildings.size(); + int cur_x, cur_h; + while (i < n || !pq.empty()) { + if (pq.empty() || (i < n && buildings[i][0] <= pq.top().second)) { + cur_x = buildings[i][0]; + while (i < n && cur_x == buildings[i][0]) { + pq.emplace(buildings[i][2], buildings[i][1]); + ++i; + } + } else { + cur_x = pq.top().second; + while (!pq.empty() && cur_x >= pq.top().second) { + pq.pop(); + } + } + cur_h = pq.empty() ? 0 : pq.top().first; + if (skyline.empty() || cur_h != skyline.back()[1]) { + skyline.push_back({cur_x, cur_h}); + } + } + return skyline; +} +``` + + + + +```py +def getSkyline(buildings: List[List[int]]) -> List[List[int]]: + skyline = [] + pq = [] # <负高度,右端> + heapq.heapify(pq) + i, n = 0, len(buildings) + + while i < n or len(pq) > 0: + if len(pq) == 0 or (i < n and buildings[i][0] <= pq[0][1]): + cur_x = buildings[i][0] + while i < n and cur_x == buildings[i][0]: + heapq.heappush(pq, (-buildings[i][2], buildings[i][1])) + i += 1 + else: + cur_x = pq[0][1] + while len(pq) > 0 and cur_x >= pq[0][1]: + heapq.heappop(pq) + + cur_h = -pq[0][0] if len(pq) > 0 else 0 + if len(skyline) == 0 or cur_h != skyline[-1][1]: + skyline.append([cur_x, cur_h]) + + return skyline + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-7-deque.mdx b/leetcode_101/docs/10-data-structures/10-7-deque.mdx new file mode 100644 index 00000000..7b9091a4 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-7-deque.mdx @@ -0,0 +1,82 @@ +--- +sidebar_position: 54 +--- + +# 10.7 双端队列 + +## [239. Sliding Window Maximum](https://leetcode.com/problems/sliding-window-maximum/) + +### 题目描述 + +给定一个整数数组和一个滑动窗口大小,求在这个窗口的滑动过程中,每个时刻其包含的最大值。 + +### 输入输出样例 + +输入是一个一维整数数组,和一个表示滑动窗口大小的整数;输出是一个一维整数数组,表示每个时刻时的窗口内最大值。 + +``` +Input: nums = [1,3,-1,-3,5,3,6,7], k = 3 +Output: [3,3,5,5,6,7] +``` + +在这个样例中,滑动窗口在每个位置的最大包含值取法如下: + +``` + Window position Max +------------------------- ----- +[1 3 -1] -3 5 3 6 7 3 + 1 [3 -1 -3] 5 3 6 7 3 + 1 3 [-1 -3 5] 3 6 7 5 + 1 3 -1 [-3 5 3] 6 7 5 + 1 3 -1 -3 [5 3 6] 7 6 + 1 3 -1 -3 5 [3 6 7] 7 +``` + +### 题解 + +我们可以利用双端队列进行操作:每当向右移动时,把窗口左端的值从双端队列左端剔除,把双端队列右边小于窗口右端的值全部剔除。这样双端队列的最左端永远是当前窗口内的最大值。另外,这道题也是单调栈的一种延申:该双端队列利用从左到右递减来维持大小关系。 + + + + +```cpp +vector maxSlidingWindow(vector& nums, int k) { + deque dq; + vector swm; + for (int i = 0; i < nums.size(); ++i) { + if (!dq.empty() && dq.front() == i - k) { + dq.pop_front(); + } + while (!dq.empty() && nums[dq.back()] < nums[i]) { + dq.pop_back(); + } + dq.push_back(i); + if (i >= k - 1) { + swm.push_back(nums[dq.front()]); + } + } + return swm; +} +``` + + + + +```py +def maxSlidingWindow(nums: List[int], k: int) -> List[int]: + dq = collections.deque() + swm = [] + for i, num in enumerate(nums): + if len(dq) > 0 and dq[0] == i - k: + dq.popleft() + while len(dq) > 0 and nums[dq[-1]] < num: + dq.pop() + dq.append(i) + if i >= k - 1: + swm.append(nums[dq[0]]) + return swm +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-8-hash-table.mdx b/leetcode_101/docs/10-data-structures/10-8-hash-table.mdx new file mode 100644 index 00000000..7053facd --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-8-hash-table.mdx @@ -0,0 +1,232 @@ +--- +sidebar_position: 55 +--- + +# 10.8 哈希表 + +`哈希表(hash table, hash map)`,又称散列表,使用 $O(n)$ 空间复杂度存储数据,通过哈希函数(hash function)映射位置,从而实现近似 $O(1)$ 时间复杂度的插入、查找、删除等操作。哈希表可以用来统计频率,记录内容等等。 + +如果元素有穷,并且范围不大,那么可以用一个固定大小的数组来存储或统计元素。例如我们需要统计一个字符串中所有字母的出现次数,则可以用一个长度为 26 的数组来进行统计,其哈希函数即为字母在字母表的位置,这样空间复杂度就可以降低为常数。 + +## [1. Two Sum](https://leetcode.com/problems/two-sum/) + +### 题目描述 + +给定一个(未排序的)整数数组,已知有且只有两个数的和等于给定值,求这两个数的位置。 + +### 输入输出样例 + +输入一个一维整数数组和一个目标值,输出是一个大小为 2 的一维数组,表示满足条件的两个数字的位置。 + +``` +Input: nums = [2, 7, 15, 11], target = 9 +Output: [0, 1] +``` + +在这个样例中,第 0 个位置的值 2 和第 1 个位置的值 7 的和为 9。 + +### 题解 + +我们可以利用哈希表存储遍历过的值以及它们的位置,每次遍历到位置 i 的时候,查找哈希表里是否存在 target - nums[i],若存在,则说明这两个值的和为 target。 + + + + +```cpp +vector twoSum(vector& nums, int target) { + unordered_map cache; // <值,位置> + for (int i = 0; i < nums.size(); ++i) { + int num1 = nums[i], num2 = target - num1; + if (cache.contains(num2)) { + return vector{cache[num2], i}; + } + cache[num1] = i; + } + return {}; +} +``` + + + + +```py +def twoSum(nums: List[int], target: int) -> List[int]: + cache = dict() # <值,位置> + for i, num1 in enumerate(nums): + num2 = target - num1 + if num2 in cache: + return [cache[num2], i] + cache[num1] = i + return [] +``` + + + + + +## [128. Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) + +### 题目描述 + +给定一个整数数组,求这个数组中的数字可以组成的最长连续序列有多长。 + +### 输入输出样例 + +输入一个整数数组,输出一个整数,表示连续序列的长度。 + +``` +Input: [100, 4, 200, 1, 3, 2] +Output: 4 +``` + +在这个样例中,最长连续序列是 [1,2,3,4]。 + +### 题解 + +我们可以把所有数字放到一个哈希表,然后不断地从哈希表中任意取一个值,并删除掉其之前之后的所有连续数字,然后更新目前的最长连续序列长度。重复这一过程,我们就可以找到所有的连续数字序列。 + + + + +```cpp +int longestConsecutive(vector& nums) { + unordered_set cache(nums.begin(), nums.end()); + int max_len = 0; + while (!cache.empty()) { + int cur = *(cache.begin()); + cache.erase(cur); + int l = cur - 1, r = cur + 1; + while (cache.contains(l)) { + cache.erase(l--); + } + while (cache.contains(r)) { + cache.erase(r++); + } + max_len = max(max_len, r - l - 1); + } + return max_len; +} +``` + + + + +```py +def longestConsecutive(nums: List[int]) -> int: + cache = set(nums) + max_len = 0 + + while len(cache) > 0: + cur = next(iter(cache)) + cache.remove(cur) + + l, r = cur - 1, cur + 1 + while l in cache: + cache.remove(l) + l -= 1 + while r in cache: + cache.remove(r) + r += 1 + + max_len = max(max_len, r - l - 1) + + return max_len + +``` + + + + + +## [149. Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) + +### 题目描述 + +给定一些二维坐标中的点,求同一条线上最多有多少点。 + +### 输入输出样例 + +输入是一个二维整数数组,表示每个点的横纵坐标;输出是一个整数,表示满足条件的最多点数。 + +``` +Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] +^ +| +| o +| o o +| o +| o o ++-------------------> +0 1 2 3 4 5 6 +Output: 4 +``` + +这个样例中,$y =5 − x$ 上有四个点。 + +### 题解 + +对于每个点,我们对其它点建立哈希表,统计同一斜率的点一共有多少个。这里利用的原理是,一条线可以由一个点和斜率而唯一确定。另外也要考虑斜率不存在和重复坐标的情况。 + +本题也利用了一个小技巧:在遍历每个点时,对于数组中位置 i 的点,我们只需要考虑 i 之后的点即可,因为 i 之前的点已经考虑过 i 了。 + + + + +```cpp +int maxPoints(vector>& points) { + int max_count = 0, n = points.size(); + for (int i = 0; i < n; ++i) { + unordered_map cache; // <斜率, 点个数> + int same_xy = 1, same_y = 1; + for (int j = i + 1; j < n; ++j) { + if (points[i][1] == points[j][1]) { + ++same_y; + if (points[i][0] == points[j][0]) { + ++same_xy; + } + } else { + double dx = points[i][0] - points[j][0], + dy = points[i][1] - points[j][1]; + ++cache[dx / dy]; + } + } + max_count = max(max_count, same_y); + for (auto item : cache) { + max_count = max(max_count, same_xy + item.second); + } + } + return max_count; +} +``` + + + + +```py +def maxPoints(points: List[List[int]]) -> int: + max_count, n = 0, len(points) + + for i, point1 in enumerate(points): + cache = dict() # <斜率, 点个数> + same_xy, same_y = 1, 1 + + for point2 in points[i + 1:]: + if point1[1] == point2[1]: + same_y += 1 + if point1[0] == point2[0]: + same_xy += 1 + else: + dx, dy = point1[0] - point2[0], point1[1] - point2[1] + cache[dx / dy] = cache.get(dx / dy, 0) + 1 + + max_count = max(max_count, same_y) + for count in cache.values(): + max_count = max(max_count, same_xy + count) + + return max_count + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10-9-multisets-and-maps.mdx b/leetcode_101/docs/10-data-structures/10-9-multisets-and-maps.mdx new file mode 100644 index 00000000..b0b85827 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/10-9-multisets-and-maps.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 56 +--- + +# 10.9 多重集合和映射 + +## [332. Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) + +### 题目描述 + +给定一个人坐过的一些飞机的起止机场,已知这个人从 JFK 起飞,那么这个人是按什么顺序飞的;如果存在多种可能性,返回字母序最小的那种。 + +### 输入输出样例 + +输入是一个二维字符串数组,表示多个起止机场对子;输出是一个一维字符串数组,表示飞行顺序。 + +``` +Input: [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]] +Output: ["JFK", "MUC", "LHR", "SFO", "SJC"] +``` + +### 题解 + +本题可以先用哈希表记录起止机场,其中键是起始机场,值是一个多重(有序)集合,表示对应的终止机场。因为一个人可能坐过重复的线路,所以我们需要使用多重集合储存重复值。储存完成之后,我们可以利用栈/DFS 来恢复从终点到起点飞行的顺序,再将结果逆序得到从起点到终点的顺序。 + +因为 Python 没有默认的多重(有序)集合实现,我们可以直接存储一个数组,然后进行排序。也可以使用 Counter 结构,每次查找下一个机场时,返回 key 值最小的那个。 + + + + +```cpp +vector findItinerary(vector>& tickets) { + vector itinerary; + unordered_map> cache; + for (const auto& ticket : tickets) { + cache[ticket[0]].insert(ticket[1]); + } + stack s; + s.push("JFK"); + while (!s.empty()) { + string t = s.top(); + if (cache[t].empty()) { + itinerary.push_back(t); + s.pop(); + } else { + s.push(*cache[t].begin()); + cache[t].erase(cache[t].begin()); + } + } + reverse(itinerary.begin(), itinerary.end()); + return itinerary; +} +``` + + + + +```py +def findItinerary(tickets: List[List[str]]) -> List[str]: + itinerary = [] + cache = dict() + + for ticket in tickets: + if ticket[0] not in cache: + cache[ticket[0]] = [] + cache[ticket[0]].append(ticket[1]) + + for ticket in cache.keys(): + cache[ticket].sort(reverse=True) + + s = ["JFK"] + while len(s) > 0: + t = s[-1] + if t not in cache or len(cache[t]) == 0: + itinerary.append(t) + s.pop() + else: + t_next = cache[t].pop() + s.append(t_next) + + return list(reversed(itinerary)) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/10-data-structures/10.1.png b/leetcode_101/docs/10-data-structures/10.1.png new file mode 100644 index 00000000..a0f0fc51 Binary files /dev/null and b/leetcode_101/docs/10-data-structures/10.1.png differ diff --git a/leetcode_101/docs/10-data-structures/10.2.png b/leetcode_101/docs/10-data-structures/10.2.png new file mode 100644 index 00000000..9a10d41c Binary files /dev/null and b/leetcode_101/docs/10-data-structures/10.2.png differ diff --git a/leetcode_101/docs/10-data-structures/10.3.png b/leetcode_101/docs/10-data-structures/10.3.png new file mode 100644 index 00000000..bc65f388 Binary files /dev/null and b/leetcode_101/docs/10-data-structures/10.3.png differ diff --git a/leetcode_101/docs/10-data-structures/10.4.png b/leetcode_101/docs/10-data-structures/10.4.png new file mode 100644 index 00000000..84c2f60e Binary files /dev/null and b/leetcode_101/docs/10-data-structures/10.4.png differ diff --git a/leetcode_101/docs/10-data-structures/10.5.png b/leetcode_101/docs/10-data-structures/10.5.png new file mode 100644 index 00000000..310069c9 Binary files /dev/null and b/leetcode_101/docs/10-data-structures/10.5.png differ diff --git a/leetcode_101/docs/10-data-structures/_category_.json b/leetcode_101/docs/10-data-structures/_category_.json new file mode 100644 index 00000000..1e241891 --- /dev/null +++ b/leetcode_101/docs/10-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "10. 妙用数据结构", + "position": 10, + "link": { + "type": "generated-index", + "description": "第 10 章 妙用数据结构" + } +} diff --git a/leetcode_101/docs/11-string-manipulation/11-1-introduction.md b/leetcode_101/docs/11-string-manipulation/11-1-introduction.md new file mode 100644 index 00000000..9cd88891 --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/11-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 59 +--- + +# 11.1 引言 + +字符串可以看成是字符组成的数组。由于字符串是程序里经常需要处理的数据类型,因此有很多针对字符串处理的题目,以下是一些常见的类型。 \ No newline at end of file diff --git a/leetcode_101/docs/11-string-manipulation/11-2-string-comparison.mdx b/leetcode_101/docs/11-string-manipulation/11-2-string-comparison.mdx new file mode 100644 index 00000000..c9daac80 --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/11-2-string-comparison.mdx @@ -0,0 +1,339 @@ +--- +sidebar_position: 60 +--- + +# 11.2 字符串比较 + +## [242. Valid Anagram](https://leetcode.com/problems/valid-anagram/) + +### 题目描述 + +判断两个字符串包含的字符是否完全相同。 + +### 输入输出样例 + +输入两个字符串,输出一个布尔值,表示两个字符串是否满足条件。 + +``` +Input: s = "anagram", t = "nagaram" +Output: true +``` + +### 题解 + +我们可以利用哈希表或者数组统计两个数组中每个数字出现的频次,若频次相同,则说明它们包含的字符完全相同。 + + + + +```cpp +bool isAnagram(string s, string t) { + if (s.length() != t.length()) { + return false; + } + vector counts(26, 0); + for (int i = 0; i < s.length(); ++i) { + ++counts[s[i] - ’a’]; + --counts[t[i] - ’a’]; + } + return all_of(counts.begin(), counts.end(), [](int c) { return c == 0; }); +} +``` + + + + +```py +def isAnagram(s: str, t: str) -> bool: + if len(s) != len(t): + return False + counter = Counter(s) + counter.subtract(t) + return all(v == 0 for v in counter.values()) +``` + + + + + +## [205. Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) + +### 题目描述 + +判断两个字符串是否同构。同构的定义是,可以通过把一个字符串的某些相同的字符转换成另一些相同的字符,使得两个字符串相同,且两种不同的字符不能够被转换成同一种字符。 + +### 输入输出样例 + +输入两个字符串,输出一个布尔值,表示两个字符串是否满足条件。 + +``` +Input: s = "paper", t = "title" +Output: true +``` + +在这个样例中,通过把 s 中的 p、a、e、r 字符转换成 t、i、l、e 字符,可以使得两个字符串相同。 + +### 题解 + +我们可以将问题转化一下:记录两个字符串每个位置的字符第一次出现的位置,如果两个字符串中相同位置的字符与它们第一次出现的位置一样,那么这两个字符串同构。举例来说,对于“paper”和“title”,假设我们现在遍历到第三个字符“p”和“t”,发现它们第一次出现的位置都在第一个字符,则说明目前位置满足同构。同样的,我们可以用哈希表存储,也可以用一个长度为 128 的数组(ASCII 定义下字符的总数量)。 + + + + +```cpp +bool isIsomorphic(string s, string t) { + vector s_init(128, 0), t_init(128, 0); + for (int i = 0; i < s.length(); ++i) { + if (s_init[s[i]] != t_init[t[i]]) { + return false; + } + s_init[s[i]] = t_init[t[i]] = i + 1; + } + return true; +} +``` + + + + +```py +def isIsomorphic(s: str, t: str) -> bool: + s_init, t_init = [0] * 128, [0] * 128 + + for i in range(len(s)): + if s_init[ord(s[i])] != t_init[ord(t[i])]: + return False + s_init[ord(s[i])] = t_init[ord(t[i])] = i + 1 + + return True + +``` + + + + + +## [647. Palindromic Substrings](https://leetcode.com/problems/palindromic-substrings/) + +### 题目描述 + +给定一个字符,求其有多少个回文子字符串。回文的定义是左右对称。 + +### 输入输出样例 + +输入是一个字符串,输出一个整数,表示回文子字符串的数量。 + +``` +Input: "aaa" +Output: 6 +``` + +六个回文子字符串分别是 ["a","a","a","aa","aa","aaa"]。 + +### 题解 + +我们可以从字符串的每个位置开始,向左向右延长,判断存在多少以当前位置为中轴的回文子字符串。 + + + + +```cpp +// 辅函数。 +int extendSubstrings(string s, int l, int r) { + int count = 0, n = s.length(); + while (l >= 0 && r < n && s[l] == s[r]) { + --l; + ++r; + ++count; + } + return count; +} +// 主函数。 +int countSubstrings(string s) { + int count = 0; + for (int i = 0; i < s.length(); ++i) { + count += extendSubstrings(s, i, i); // 奇数长度 + count += extendSubstrings(s, i, i + 1); // 偶数长度 + } + return count; +} +``` + + + + +```py +# 辅函数。 +def extendSubstrings(s: str, l: int, r: int) -> int: + count, n = 0, len(s) + while l >= 0 and r < n and s[l] == s[r]: + count += 1 + l -= 1 + r += 1 + return count + +# 主函数。 +def countSubstrings(s: str) -> int: + return sum( + # 奇数长度 + 偶数长度。 + extendSubstrings(s, i, i) + extendSubstrings(s, i, i + 1) + for i in range(len(s)) + ) + +``` + + + + + +## [696. Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/) + +### 题目描述 + +给定一个 0-1 字符串,求有多少非空子字符串的 0 和 1 数量相同,且 0 和 1 必须连续出现(比如 0011、1100;0101 不算)。 + +### 输入输出样例 + +输入是一个字符串,输出一个整数,表示满足条件的子字符串的数量。 + +``` +Input: "00110011" +Output: 6 +``` + +在这个样例中,六个 0 和 1 数量相同的子字符串是 ["0011","01","1100","10","0011","01"]。 + +### 题解 + +从左往右遍历数组,记录和当前位置数字相同且连续的长度,以及其之前连续的不同数字的长度。举例来说,对于 00110 的最后一位,我们记录的相同数字长度是 1,因为只有一个连续 0;我们记录的不同数字长度是 2,因为在 0 之前有两个连续的 1。若不同数字的连续长度大于等于当前数字的连续长度,则说明存在一个且只存在一个以当前数字结尾的满足条件的子字符串。 + + + + +```cpp +int countBinarySubstrings(string s) { + int prev = 0, cur = 1, count = 0; + for (int i = 1; i < s.length(); ++i) { + if (s[i] == s[i - 1]) { + ++cur; + } else { + prev = cur; + cur = 1; + } + if (prev >= cur) { + ++count; + } + } + return count; +} +``` + + + + +```py +def countBinarySubstrings(s: str) -> int: + prev, cur, count = 0, 1, 0 + + for i in range(1, len(s)): + if s[i] == s[i - 1]: + cur += 1 + else: + prev = cur + cur = 1 + if prev >= cur: + count += 1 + + return count + +``` + + + + + +## [1249. Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/) + +### 题目描述 + +给定一个包括字母和左右括号的字符串,求最少要移除多少个括号才能使其合法。 + +### 输入输出样例 + +输入是一个字符串,输出是合法且长度最长的移除结果。 + +``` +Input: s = "lee(t(c)o)de)" +Output: "lee(t(c)o)de" +``` + +返回 lee(t(co)de) 或 lee(t(c)ode) 也算正确。 + +### 题解 + +因为只有一种括号,所以我们并不一定利用栈来统计,可以直接用一个临时变量统计在当前位置时,左括号比右括号多出现多少次。如果在遍历过程中出现负数,则需要移除多余的右括号。如果遍历结束时临时变量为正数,则需要从右到左移除多余的左括号。这里我们使用了一个小技巧,先标记待删除位置,最后一起移除。 + + + + +```cpp +string minRemoveToMakeValid(string s) { + int count = 0, n = s.length(); + char to_delete = '#'; + for (char& c : s) { + if (c == '(') { + ++count; + } else if (c == ')') { + if (count > 0) { + --count; + } else { + c = to_delete; + } + } + } + for (int i = n - 1; i >= 0; --i) { + if (count == 0) break; + if (s[i] == '(') { + s[i] = to_delete; + --count; + } + } + s.erase(remove_if(s.begin(), s.end(), + [to_delete](char c) { return c == to_delete; }), + s.end()); + return s; +} + +``` + + + + +```py +def minRemoveToMakeValid(s: str) -> str: + count, n = 0, len(s) + to_delete = set() + + for i in range(n): + if s[i] == "(": + count += 1 + elif s[i] == ")": + if count > 0: + count -= 1 + else: + to_delete.add(i) + + for i in range(n - 1, -1, -1): + if count == 0: + break + if s[i] == "(": + to_delete.add(i) + count -= 1 + + return "".join(s[i] for i in range(n) if i not in to_delete) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/11-string-manipulation/11-3-string-interpretation.mdx b/leetcode_101/docs/11-string-manipulation/11-3-string-interpretation.mdx new file mode 100644 index 00000000..30d8f2ab --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/11-3-string-interpretation.mdx @@ -0,0 +1,129 @@ +--- +sidebar_position: 61 +--- + +# 11.3 字符串理解 + +## [227. Basic Calculator II](https://leetcode.com/problems/basic-calculator-ii/) + +### 题目描述 + +给定一个包含加减乘除整数运算的字符串,求其运算的整数值结果。如果除不尽则向 0 取整。 + +### 输入输出样例 + +输入是一个合法的运算字符串,输出是一个整数,表示其运算结果。 + +``` +Input: " 3+5 / 2 " +Output: 5 +``` + +在这个样例中,因为除法的优先度高于加法,所以结果是 5 而非 4。 + +### 题解 + +如果我们在字符串左边加上一个加号,可以证明其并不改变运算结果,且字符串可以分割成多个 < 一个运算符,一个数字 > 对子的形式;这样一来我们就可以从左往右处理了。由于乘除的优先级高于加减,因此我们需要使用一个中间变量来存储高优先度的运算结果。 + +此类型题也考察很多细节处理,如无运算符的情况,和多个空格的情况等等。 + + + + +```cpp +// 辅函数 - parse从位置i开始的一个数字。 +int parseNum(const string& s, int& i) { + int num = 0, n = s.length(); + while (i < n && isdigit(s[i])) { + num = 10 * num + (s[i++] - '0'); + } + return num; +} + +// 主函数。 +int calculate(string s) { + char op = '+'; + long global_num = 0, local_num = 0; + int i = -1, n = s.length(); + while (++i < n) { + if (s[i] == ' ') { + continue; + } + long num = parseNum(s, i); + switch (op) { + case '+': + global_num += local_num; + local_num = num; + break; + case '-': + global_num += local_num; + local_num = -num; + break; + case '*': + local_num *= num; + break; + case '/': + local_num /= num; + break; + } + if (i < n) { + op = s[i]; + } + } + return global_num + local_num; +} + +``` + + + + +```py +from typing import Tuple + +# 辅函数 - parse从位置i开始的一个数字。 +# 返回(数字, 下一个i位置) +def parseNum(s: str, i: int) -> Tuple[int, int]: + num, n = 0, len(s) + while i < n and s[i].isdigit(): + num = 10 * num + int(s[i]) + i += 1 + return (num, i) + +# 主函数。 +def calculate(s: str) -> int: + op = "+" + global_num, local_num = 0, 0 + i, n = 0, len(s) + + while i < n: + if s[i] == " ": + i += 1 + continue + + num, i = parseNum(s, i) + + match op: + case "+": + global_num += local_num + local_num = num + case "-": + global_num += local_num + local_num = -num + case "*": + local_num *= num + case "/": + # int()会实现向0取整,而//对负数会远离0取整。 + local_num = int(local_num / num) + + if i < n: + op = s[i] + i += 1 + + return global_num + local_num + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/11-string-manipulation/11-4-string-matching.mdx b/leetcode_101/docs/11-string-manipulation/11-4-string-matching.mdx new file mode 100644 index 00000000..8797d9de --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/11-4-string-matching.mdx @@ -0,0 +1,106 @@ +--- +sidebar_position: 62 +--- + +# 11.4 字符串匹配 + +## [28. Implement strStr()](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/) + +### 题目描述 + +判断一个字符串是不是另一个字符串的子字符串,并返回其位置。 + +### 输入输出样例 + +输入一个母字符串和一个子字符串,输出一个整数,表示子字符串在母字符串的位置,若不存在则返回-1。 + +``` +Input: haystack = "hello", needle = "ll" +Output: 2 +``` + +### 题解 + +使用著名的Knuth-Morris-Pratt(KMP)算法,可以在 $O(m +n)$ 时间利用动态规划完成匹配。这里我们定义 dp 数组为,dp[i] 表示 needle 中以 i 位置截止的片段(即后缀),最长可以匹配到needle 从头开始的哪个位置(即前缀)。例如,ababaca 的 dp 数组是 [-1,-1,0,1,2,-1,0],表示每个位置最长可以匹配 [无, 无, a, ab, aba, 无, a]。 + +这道题比较复杂,初学者可以暂时跳过。 + + + + +```cpp +// 辅函数。 +vector computeDp(const string &needle) { + int n = needle.length(); + vector dp(n, -1); + for (int j = 1, k = -1; j < n; ++j) { + while (k > -1 && needle[k + 1] != needle[j]) { + k = dp[k]; // 如果下一位不同,回溯到前一个前缀片段 + } + if (needle[k + 1] == needle[j]) { + ++k; // 前缀和后缀片段相同,匹配长度加1 + } + dp[j] = k; // 更新前缀匹配位置 + } + return dp; +} +// 主函数。 +int strStr(const string &haystack, const string &needle) { + int m = haystack.length(), n = needle.length(); + vector dp = computeDp(needle); + for (int i = 0, k = -1; i < m; ++i) { + while (k > -1 && needle[k + 1] != haystack[i]) { + k = dp[k]; // 如果下一位不同,回溯到前一个相同片段 + } + if (needle[k + 1] == haystack[i]) { + ++k; // 片段相同,匹配长度加1 + } + if (k == n - 1) { + return i - n + 1; // 匹配结束 + } + } + return -1; +} +``` + + + + +```py +from typing import List + +# 辅函数。 +def computeDp(needle: str) -> List[int]: + n = len(needle) + dp = [-1] * n + k = -1 + for j in range(1, n): + while k > -1 and needle[k + 1] != needle[j]: + k = dp[k] # 如果下一位不同,回溯到前一个前缀片段 + if needle[k + 1] == needle[j]: + k += 1 # 前缀和后缀片段相同,匹配长度加1 + dp[j] = k # 更新前缀匹配位置 + return dp + +# 主函数。 +def strStr(haystack: str, needle: str) -> int: + m, n = len(haystack), len(needle) + if n == 0: + return 0 # Edge case for an empty needle + + dp = computeDp(needle) + k = -1 + for i in range(m): + while k > -1 and needle[k + 1] != haystack[i]: + k = dp[k] # 如果下一位不同,回溯到前一个相同片段 + if needle[k + 1] == haystack[i]: + k += 1 # 片段相同,匹配长度加1 + if k == n - 1: + return i - n + 1 # 匹配结束 + return -1 + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/11-string-manipulation/11-5-exercises.md b/leetcode_101/docs/11-string-manipulation/11-5-exercises.md new file mode 100644 index 00000000..92025cb3 --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/11-5-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 63 +--- + +# 11.5 练习 + +## 基础难度 + +### [409. Longest Palindrome](https://leetcode.com/problems/longest-palindrome/) + +计算一组字符可以构成的回文字符串的最大长度,可以利用其它数据结构进行辅助统计。 + +--- + +### [3. Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) + +计算最长无重复子字符串,同样的,可以利用其它数据结构进行辅助统计。 + +--- + +## 进阶难度 + +### [772. Basic Calculator III](https://leetcode.com/problems/basic-calculator-iii/) + +题目 227 的 follow-up,十分推荐练习。 + +--- + +### [5. Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/) + +类似于我们讲过的子序列问题,子数组或子字符串问题常常也可以用动态规划来解决。先使用动态规划写出一个 $O(n^2)$ 时间复杂度的算法,再搜索一下 Manacher’s Algorithm,它可以在 $O(n)$ 时间解决这一问题。 \ No newline at end of file diff --git a/leetcode_101/docs/11-string-manipulation/_category_.json b/leetcode_101/docs/11-string-manipulation/_category_.json new file mode 100644 index 00000000..084ef32f --- /dev/null +++ b/leetcode_101/docs/11-string-manipulation/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "11. 令人头大的字符串", + "position": 11, + "link": { + "type": "generated-index", + "description": "第 11 章 令人头大的字符串" + } +} diff --git a/leetcode_101/docs/12-linked-lists/12-1-data-structure-introduction.md b/leetcode_101/docs/12-linked-lists/12-1-data-structure-introduction.md new file mode 100644 index 00000000..b298b78e --- /dev/null +++ b/leetcode_101/docs/12-linked-lists/12-1-data-structure-introduction.md @@ -0,0 +1,40 @@ +--- +sidebar_position: 64 +--- + +# 12.1 数据结构介绍 + +(单向)`链表`是由节点和指针构成的数据结构,每个节点存有一个值,和一个指向下一个节点的指针,因此很多链表问题可以用递归来处理。不同于数组,链表并不能直接获取任意节点的值,必须要通过指针找到该节点后才能获取其值。同理,在未遍历到链表结尾时,我们也无法知道链表的长度,除非依赖其他数据结构储存长度。LeetCode 默认的链表表示方法如下。 + + + + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + + + + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + + + + + +由于在进行链表操作时,尤其是删除节点时,经常会因为对当前节点进行操作而导致内存或指针出现问题。有两个小技巧可以解决这个问题:一是尽量处理当前节点的下一个节点而非当前节点本身,二是建立一个虚拟节点 (dummy node),使其指向当前链表的头节点,这样即使原链表所有节点全被删除,也会有一个 dummy 存在,返回 dummy->next 即可。 + +:::warning + + 一般来说,算法题不需要删除内存。在刷 LeetCode 的时候,如果想要删除一个节点,可以直接进行指针操作而无需回收内存。实际做软件工程时,对于无用的内存,笔者建议尽量显式回收,或利用智能指针。 + +::: \ No newline at end of file diff --git a/leetcode_101/docs/12-linked-lists/12-2-basic-linked-list-operations.mdx b/leetcode_101/docs/12-linked-lists/12-2-basic-linked-list-operations.mdx new file mode 100644 index 00000000..b63e43bf --- /dev/null +++ b/leetcode_101/docs/12-linked-lists/12-2-basic-linked-list-operations.mdx @@ -0,0 +1,270 @@ +--- +sidebar_position: 65 +--- + +# 12.2 链表的基本操作 + +## [206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) + +### 题目描述 + +翻转一个链表。 + +### 输入输出样例 + +输入一个链表,输出该链表翻转后的结果。 + +``` +Input: 1->2->3->4->5->nullptr +Output: 5->4->3->2->1->nullptr +``` + +### 题解 + +链表翻转是非常基础也一定要掌握的技能。我们提供了两种写法——递归和非递归。建议你同时掌握这两种写法。 + +递归的写法为: + + + + +```cpp +ListNode* reverseList(ListNode* head, ListNode* head_prev = nullptr) { + if (head == nullptr) { + return head_prev; + } + ListNode* head_next = head->next; + head->next = head_prev; + return reverseList(head_next, head); +} +``` + + + + +```py +def reverseList( + head: Optional[ListNode], head_prev: Optional[ListNode] = None +) -> Optional[ListNode]: + if head is None: + return head_prev + head_next = head.next + head.next = head_prev + return reverseList(head_next, head) +``` + + + + + +非递归的写法为: + + + + +```cpp +ListNode* reverseList(ListNode* head) { + ListNode *head_prev = nullptr, *head_next; + while (head) { + head_next = head->next; + head->next = head_prev; + head_prev = head; + head = head_next; + } + return head_prev; +} +``` + + + + +```py +def reverseList(head: Optional[ListNode]) -> Optional[ListNode]: + head_prev = None + while head is not None: + head_next = head.next + head.next = head_prev + head_prev = head + head = head_next + return head_prev +``` + + + + + +## [21. Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) + +### 题目描述 + +给定两个增序的链表,试将其合并成一个增序的链表。 + +### 输入输出样例 + +输入两个链表,输出一个链表,表示两个链表合并的结果。 + +``` +Input: 1->2->4, 1->3->4 +Output: 1->1->2->3->4->4 +``` + +### 题解 + +我们提供了递归和非递归,共两种写法。递归的写法为: + + + + +```cpp +ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (l2 == nullptr) { + return l1; + } + if (l1 == nullptr) { + return l2; + } + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } + l2->next = mergeTwoLists(l1, l2->next); + return l2; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + if l1 is None or l2 is None: + return l1 or l2 + if l1.val < l2.val: + l1.next = mergeTwoLists(l1.next, l2) + return l1 + l2.next = mergeTwoLists(l1, l2.next) + return l2 +``` + + + + + +非递归的写法为: + + + + +```cpp +ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode *dummy = new ListNode(0), *node = dummy; + while (l1 && l2) { + if (l1->val < l2->val) { + node->next = l1; + l1 = l1->next; + } else { + node->next = l2; + l2 = l2->next; + } + node = node->next; + } + node->next = l1 == nullptr ? l2 : l1; + return dummy->next; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + dummy = ListNode() + head = dummy + + while l1 and l2: + if l1.val < l2.val: + dummy.next = l1 + l1 = l1.next + else: + dummy.next = l2 + l2 = l2.next + dummy = dummy.next + + dummy.next = l1 or l2 + return head.next + +``` + + + + + +## [24. Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) + +### 题目描述 + +给定一个矩阵,交换每个相邻的一对节点。 + +### 输入输出样例 + +输入一个链表,输出该链表交换后的结果。 + +``` +Input: 1->2->3->4 +Output: 2->1->4->3 +``` + +### 题解 + +利用指针进行交换操作,没有太大难度,但一定要细心。 + + + + +```cpp +ListNode* swapPairs(ListNode* head) { + ListNode *node1 = head, *node2; + if (node1 && node1->next) { + node2 = node1->next; + node1->next = node2->next; + node2->next = node1; + head = node2; + while (node1->next && node1->next->next) { + node2 = node1->next->next; + node1->next->next = node2->next; + node2->next = node1->next; + node1->next = node2; + node1 = node2->next; + } + } + return head; +} +``` + + + + +```py +def swapPairs(head: Optional[ListNode]) -> Optional[ListNode]: + node1 = head + if node1 is not None and node1.next is not None: + node2 = node1.next + node1.next = node2.next + node2.next = node1 + head = node2 + while node1.next is not None and node1.next.next is not None: + node2 = node1.next.next + node1.next.next = node2.next + node2.next = node1.next + node1.next = node2 + node1 = node2.next + return head +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/12-linked-lists/12-3-other-linked-list-techniques.mdx b/leetcode_101/docs/12-linked-lists/12-3-other-linked-list-techniques.mdx new file mode 100644 index 00000000..0b473281 --- /dev/null +++ b/leetcode_101/docs/12-linked-lists/12-3-other-linked-list-techniques.mdx @@ -0,0 +1,140 @@ +--- +sidebar_position: 66 +--- + +# 12.3 其它链表技巧 + +## [160. Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists/) + +### 题目描述 + +给定两个链表,判断它们是否相交于一点,并求这个相交节点。 + +### 输入输出样例 + +输入是两条链表,输出是一个节点。如无相交节点,则返回一个空节点。 + +``` +Input: +A: a1 -> a2 + | + v + c1 -> c2 -> c3 + ^ + | +B: b1 -> b2 -> b3 +Output: c1 +``` + +### 题解 + +假设链表 A 的头节点到相交点的距离是 a,链表 B 的头节点到相交点的距离是 b,相交点到链表终点的距离为 c。我们使用两个指针,分别指向两个链表的头节点,并以相同的速度前进,若到达链表结尾,则移动到另一条链表的头节点继续前进。按照这种前进方法,两个指针会在 a + b + c 次前进后同时到达相交节点。 + + + + +```cpp +ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + ListNode *l1 = headA, *l2 = headB; + while (l1 != l2) { + l1 = l1 != nullptr ? l1->next : headB; + l2 = l2 != nullptr ? l2->next : headA; + } + return l1; +} +``` + + + + +```py +def getIntersectionNode( + headA: ListNode, headB: ListNode +) -> Optional[ListNode]: + l1 = headA + l2 = headB + while l1 != l2: + l1 = l1.next if l1 is not None else headB + l2 = l2.next if l2 is not None else headA + return l1 +``` + + + + + +## [234. Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/) + +### 题目描述 + +以 $O(1)$ 的空间复杂度,判断链表是否回文。 + +### 输入输出样例 + +输入是一个链表,输出是一个布尔值,表示链表是否回文。 + +``` +Input: 1->2->3->2->1 +Output: true +``` + +### 题解 + +先使用快慢指针找到链表中点,再把链表切成两半;然后把后半段翻转;最后比较两半是否相等。 + + + + +```cpp +bool isPalindrome(ListNode* head) { + if (head == nullptr || head->next == nullptr) { + return true; + } + ListNode *slow = head, *fast = head; + while (fast->next && fast->next->next) { + slow = slow->next; + fast = fast->next->next; + } + slow->next = reverseList(slow->next); // 见题目206 + slow = slow->next; + while (slow != nullptr) { + if (head->val != slow->val) { + return false; + } + head = head->next; + slow = slow->next; + } + return true; +} +``` + + + + +```py +def isPalindrome(head: Optional[ListNode]) -> bool: + if head is None or head.next is None: + return True + + slow, fast = head, head + + while fast.next is not None and fast.next.next is not None: + slow = slow.next + fast = fast.next.next + + slow.next = reverseList(slow.next) # 见题目206 + slow = slow.next + + while slow is not None: + if head.val != slow.val: + return False + head = head.next + slow = slow.next + + return True + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/12-linked-lists/12-4-exercises.md b/leetcode_101/docs/12-linked-lists/12-4-exercises.md new file mode 100644 index 00000000..c5f3b2db --- /dev/null +++ b/leetcode_101/docs/12-linked-lists/12-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 67 +--- + +# 12.4 练习 + +## 基础难度 + +### [83. Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) + +虽然 LeetCode 没有强制要求,但是我们仍然建议你回收内存,尤其当题目要求你删除的时候。 + +--- + +### [328. Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/) + +这道题其实很简单,千万不要把题目复杂化。 + +--- + +### [19. Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/) + +既然我们可以使用快慢指针找到中点,也可以利用类似的方法找到倒数第 n 个节点,无需遍历第二遍。 + +--- + +## 进阶难度 + +### [148. Sort List](https://leetcode.com/problems/sort-list/) + +利用快慢指针找到链表中点后,可以对链表进行归并排序。 \ No newline at end of file diff --git a/leetcode_101/docs/12-linked-lists/_category_.json b/leetcode_101/docs/12-linked-lists/_category_.json new file mode 100644 index 00000000..184a7911 --- /dev/null +++ b/leetcode_101/docs/12-linked-lists/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "12. 指针三剑客之一:链表", + "position": 12, + "link": { + "type": "generated-index", + "description": "第 12 章 指针三剑客之一:链表" + } +} diff --git a/leetcode_101/docs/13-trees/13-1-data-structure-introduction.mdx b/leetcode_101/docs/13-trees/13-1-data-structure-introduction.mdx new file mode 100644 index 00000000..3d50814f --- /dev/null +++ b/leetcode_101/docs/13-trees/13-1-data-structure-introduction.mdx @@ -0,0 +1,37 @@ +--- +sidebar_position: 68 +--- + +# 13.1 数据结构介绍 + +作为(单)链表的升级版,我们通常接触的树都是`二叉树`(binary tree),即每个节点最多有两个子节点;且除非题目说明,默认树中不存在循环结构。LeetCode 默认的树表示方法如下。 + + + + + +```cpp +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode(int x) : val(x), left(NULL), right(NULL) {} +}; +``` + + + + +```py +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right +``` + + + + + +可以看出,其与链表的主要差别就是多了一个子节点的指针。 \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-2-tree-recursion.mdx b/leetcode_101/docs/13-trees/13-2-tree-recursion.mdx new file mode 100644 index 00000000..d88f751c --- /dev/null +++ b/leetcode_101/docs/13-trees/13-2-tree-recursion.mdx @@ -0,0 +1,469 @@ +--- +sidebar_position: 69 +--- + +# 13.2 树的递归 + +对于一些简单的递归题,某些 LeetCode 达人喜欢写 one-line code,即用一行代码解决问题。我们也会展示一些这样的代码,但是对于新手,笔者仍然建议您使用多行的 if-else 判断语句。 + +在很多时候,树递归的写法与深度优先搜索的递归写法相同,因此本书不会区分二者。 + +## [104. Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) + +### 题目描述 + +求一个二叉树的最大深度。 + +### 输入输出样例 + +输入是一个二叉树,输出是一个整数,表示该树的最大深度。 + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: 3 +``` + +### 题解 + +利用递归,我们可以很方便地求得最大深度。 + + + + +```cpp +int maxDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + return max(maxDepth(root->left), maxDepth(root->right)) + 1; +} +``` + + + + +```py +def maxDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + return max(maxDepth(root.left), maxDepth(root.right)) + 1 +``` + + + + + +## [110. Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) + +### 题目描述 + +判断一个二叉树是否平衡。树平衡的定义是,对于树上的任意节点,其两侧节点的最大深度的差值不得大于 1。 + +### 输入输出样例 + +输入是一个二叉树,输出一个布尔值,表示树是否平衡。 + +``` +Input: + 1 + / \ + 2 2 + / \ + 3 3 + / \ +4 4 +Output: false +``` + +### 题解 + +解法类似于求树的最大深度,但有两个不同的地方:一是我们需要先处理子树的深度再进行比较,二是如果我们在处理子树时发现其已经不平衡了,则可以返回一个-1,使得所有其长辈节点可以避免多余的判断(本题的判断比较简单,做差后取绝对值即可;但如果此处是一个开销较大的比较过程,则避免重复判断可以节省大量的计算时间)。 + + + + +```cpp +// 辅函数。 +int balancedDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + int left = balancedDepth(root->left); + int right = balancedDepth(root->right); + if (left == -1 || right == -1 || abs(left - right) > 1) { + return -1; + } + return max(left, right) + 1; +} +// 主函数。 +bool isBalanced(TreeNode* root) { return balancedDepth(root) != -1; } +``` + + + + +```py +# 辅函数。 +def balancedDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + left = balancedDepth(root.left) + right = balancedDepth(root.right) + if left == -1 or right == -1 or abs(left - right) > 1: + return -1 + return max(left, right) + 1 + +# 主函数。 +def isBalanced(root: Optional[TreeNode]) -> bool: + return balancedDepth(root) != -1 + +``` + + + + + +## [543. Diameter of Binary Tree](https://leetcode.com/problems/diameter-of-binary-tree/) + +### 题目描述 + +求一个二叉树的最长直径。直径的定义是二叉树上任意两节点之间的无向距离。 + +### 输入输出样例 + +输入是一个二叉树,输出一个整数,表示最长直径。 + +``` +Input: + 1 + / \ + 2 3 + / \ + 4 5 +Output: 3 +``` + +在这个样例中,最长直径是 [4,2,1,3] 和 [5,2,1,3]。 + +### 题解 + +同样的,我们可以利用递归来处理树。解题时要注意,在我们处理某个子树时,我们更新的最长直径值和递归返回的值是不同的。这是因为待更新的最长直径值是经过该子树根节点的最长直径(即两侧长度);而函数返回值是以该子树根节点为端点的最长直径值(即一侧长度),使用这样的返回值才可以通过递归更新父节点的最长直径值)。 + + + + +```cpp +// 辅函数。 +int updateDiameter(TreeNode* node, int& diameter) { + if (node == nullptr) { + return 0; + } + int left = updateDiameter(node->left, diameter); + int right = updateDiameter(node->right, diameter); + diameter = max(diameter, left + right); + return max(left, right) + 1; +} +// 主函数。 +int diameterOfBinaryTree(TreeNode* root) { + int diameter = 0; + updateDiameter(root, diameter); + return diameter; +} +``` + + + + +```py +# 辅函数。 +def updateDiameter(node: Optional[TreeNode], diameter: List[int]) -> int: + if node is None: + return 0 + left = updateDiameter(node.left, diameter) + right = updateDiameter(node.right, diameter) + diameter[0] = max(diameter[0], left + right) + return max(left, right) + 1 + +# 主函数。 +def diameterOfBinaryTree(root: Optional[TreeNode]) -> int: + diameter = [0] + updateDiameter(root, diameter) + return diameter[0] + +``` + + + + + +## [437. Path Sum III](https://leetcode.com/problems/path-sum-iii/) + +### 题目描述 + +给定一个整数二叉树,求有多少条路径节点值的和等于给定值。 + +### 输入输出样例 + +输入一个二叉树和一个给定整数,输出一个整数,表示有多少条满足条件的路径。 + +``` +Input: sum = 8, tree = + 10 + / \ + 5 -3 + / \ \ + 3 2 11 + / \ \ + 3 -2 1 +Output: 3 +``` + +在这个样例中,和为 8 的路径一共有三个:[[5,3],[5,2,1],[-3,11]]。 + +### 题解 + +递归每个节点时,需要分情况考虑:(1)如果选取该节点加入路径,则之后必须继续加入连续节点,或停止加入节点(2)如果不选取该节点加入路径,则对其左右节点进行重新进行考虑。因此一个方便的方法是我们创建一个辅函数,专门用来计算连续加入节点的路径。 + + + + +```cpp +// 辅函数。 +// long long防止test case中大数溢出,一般情况下用int即可。 +long long pathSumStartWithRoot(TreeNode* root, long long targetSum) { + if (root == nullptr) { + return 0; + } + return (root->val == targetSum) + + pathSumStartWithRoot(root->left, targetSum - root->val) + + pathSumStartWithRoot(root->right, targetSum - root->val); +} +// 主函数。 +int pathSum(TreeNode* root, int targetSum) { + if (root == nullptr) { + return 0; + } + return pathSumStartWithRoot(root, targetSum) + + pathSum(root->left, targetSum) + pathSum(root->right, targetSum); +} +``` + + + + +```py +# 辅函数。 +def pathSumStartWithRoot(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + int(root.val == targetSum) + + pathSumStartWithRoot(root.left, targetSum - root.val) + + pathSumStartWithRoot(root.right, targetSum - root.val) + ) + +# 主函数。 +def pathSum(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + pathSumStartWithRoot(root, targetSum) + + pathSum(root.left, targetSum) + + pathSum(root.right, targetSum) + ) + +``` + + + + + +## [101. Symmetric Tree](https://leetcode.com/problems/symmetric-tree/) + +### 题目描述 + +判断一个二叉树是否对称。 + +### 输入输出样例 + +输入一个二叉树,输出一个布尔值,表示该树是否对称。 + +``` +Input: + 1 + / \ + 2 2 + / \ / \ +3 4 4 3 +Output: true +``` + +### 题解 + +判断一个树是否对称等价于判断左右子树是否对称。笔者一般习惯将判断两个子树是否相等或对称类型的题的解法叫做“四步法”:(1)如果两个子树都为空指针,则它们相等或对称(2)如果两个子树只有一个为空指针,则它们不相等或不对称(3)如果两个子树根节点的值不相等,则它们不相等或不对称(4)根据相等或对称要求,进行递归处理。 + + + + + +```cpp +// 辅函数。 +bool isLeftRightSymmetric(TreeNode* left, TreeNode* right) { + if (left == nullptr && right == nullptr) { + return true; + } + if (left == nullptr or right == nullptr) { + return false; + } + if (left->val != right->val) { + return false; + } + return isLeftRightSymmetric(left->left, right->right) && + isLeftRightSymmetric(left->right, right->left); +} +// 主函数。 +bool isSymmetric(TreeNode* root) { + if (root == nullptr) { + return true; + } + return isLeftRightSymmetric(root->left, root->right); +} +``` + + + + +```py +# 辅函数。 +def isLeftRightSymmetric( + left: Optional[TreeNode], right: Optional[TreeNode] +) -> bool: + if left is None and right is None: + return True + if left is None or right is None: + return False + if left.val != right.val: + return False + return ( + isLeftRightSymmetric(left.left, right.right) and + isLeftRightSymmetric(left.right, right.left) + ) + +# 主函数。 +def isSymmetric(root: Optional[TreeNode]) -> bool: + if root is None: + return True + return isLeftRightSymmetric(root.left, root.right) + +``` + + + + + +## [1110. Delete Nodes And Return Forest](https://leetcode.com/problems/delete-nodes-and-return-forest/) + +### 题目描述 + +给定一个整数二叉树和一些整数,求删掉这些整数对应的节点后,剩余的子树。 + +### 输入输出样例 + +输入是一个整数二叉树和一个一维整数数组,输出一个数组,每个位置存储一个子树(的根节点)。 + +``` +Input: to_delete = [3,5], tree = + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 +Output: [ + 1 + / + 2 + / +4 ,6 ,7] +``` + +### 题解 + +这道题最主要需要注意的细节是如果通过递归处理原树,以及需要在什么时候断开指针。同时,为了便于寻找待删除节点,可以建立一个哈希表方便查找。笔者强烈建议读者在看完题解后,自己写一遍本题,加深对于递归的理解和运用能力。 + + + + +```cpp +// 辅函数。 +TreeNode* moveNodesToForest(TreeNode* root, unordered_set& undeleted, + vector& forest) { + if (root == nullptr) { + return nullptr; + } + root->left = moveNodesToForest(root->left, undeleted, forest); + root->right = moveNodesToForest(root->right, undeleted, forest); + if (undeleted.contains(root->val)) { + if (root->left != nullptr) { + forest.push_back(root->left); + } + if (root->right != nullptr) { + forest.push_back(root->right); + } + root = nullptr; + } + return root; +} +// 主函数。 +vector delNodes(TreeNode* root, vector& to_delete) { + vector forest; + unordered_set undeleted(to_delete.begin(), to_delete.end()); + root = moveNodesToForest(root, undeleted, forest); + if (root != nullptr) { + forest.push_back(root); + } + return forest; +} +``` + + + + +```py +# 辅函数。 +def moveNodesToForest( + root: Optional[TreeNode], undeleted: Set[int], forest: List[TreeNode] +) -> Optional[TreeNode]: + if root is None: + return None + + root.left = moveNodesToForest(root.left, undeleted, forest) + root.right = moveNodesToForest(root.right, undeleted, forest) + + if root.val in undeleted: + if root.left is not None: + forest.append(root.left) + if root.right is not None: + forest.append(root.right) + root = None + + return root + +# 主函数。 +def delNodes(root: Optional[TreeNode], to_delete: List[int]) -> List[TreeNode]: + forest = [] + undeleted = set(to_delete) + root = moveNodesToForest(root, undeleted, forest) + if root is not None: + forest.append(root) + return forest + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-3-level-order-traversal.mdx b/leetcode_101/docs/13-trees/13-3-level-order-traversal.mdx new file mode 100644 index 00000000..3c2e80ea --- /dev/null +++ b/leetcode_101/docs/13-trees/13-3-level-order-traversal.mdx @@ -0,0 +1,92 @@ +--- +sidebar_position: 70 +--- + +# 13.3 层次遍历 + +我们可以使用广度优先搜索进行层次遍历。注意,不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。 + +## [637. Average of Levels in Binary Tree](https://leetcode.com/problems/average-of-levels-in-binary-tree/) + +### 题目描述 + +给定一个二叉树,求每一层的节点值的平均数。 + +### 输入输出样例 + +输入是一个二叉树,输出是一个一维数组,表示每层节点值的平均数。 + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: [3, 14.5, 11] +``` + +### 题解 + +利用广度优先搜索,我们可以很方便地求取每层的平均值。 + + + + +```cpp +vector averageOfLevels(TreeNode* root) { + vector level_avg; + if (root == nullptr) { + return level_avg; + } + queue q; + q.push(root); + int count = q.size(); + while (count > 0) { + double level_sum = 0; + for (int i = 0; i < count; ++i) { + TreeNode* node = q.front(); + q.pop(); + level_sum += node->val; + if (node->left != nullptr) { + q.push(node->left); + } + if (node->right != nullptr) { + q.push(node->right); + } + } + level_avg.push_back(level_sum / count); + count = q.size(); + } + return level_avg; +} +``` + + + + +```py +def averageOfLevels(root: Optional[TreeNode]) -> List[float]: + level_avg = [] + if root is None: + return level_avg + q = collections.deque() + q.append(root) + count = len(q) + while count > 0: + level_sum = 0 + for _ in range(count): + node = q.popleft() + level_sum += node.val + if node.left is not None: + q.append(node.left) + if node.right is not None: + q.append(node.right) + level_avg.append(level_sum / count) + count = len(q) + return level_avg +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-4-preorder-inorder-postorder-traversal.mdx b/leetcode_101/docs/13-trees/13-4-preorder-inorder-postorder-traversal.mdx new file mode 100644 index 00000000..a2ae00d2 --- /dev/null +++ b/leetcode_101/docs/13-trees/13-4-preorder-inorder-postorder-traversal.mdx @@ -0,0 +1,250 @@ +--- +sidebar_position: 71 +--- + +# 13.4 前中后序遍历 + +前序遍历、中序遍历和后序遍历是三种利用深度优先搜索遍历二叉树的方式。它们是在对节点访问的顺序有一点不同,其它完全相同。考虑如下一棵树, + +``` + 1 + / \ + 2 3 + / \ \ +4 5 6 +``` + +前序遍历先遍历父结点,再遍历左结点,最后遍历右节点,我们得到的遍历顺序是 [1 2 4 5 3 6]。 + + + + +```cpp +void preorder(TreeNode* root) { + visit(root); + preorder(root->left); + preorder(root->right); +} +``` + + + + +```py +def preorder(root: TreeNode): + visit(root) + preorder(root.left) + preorder(root.right) +``` + + + + + +中序遍历先遍历左节点,再遍历父结点,最后遍历右节点,我们得到的遍历顺序是 [4 2 5 1 3 6]。 + + + + +```cpp +void inorder(TreeNode* root) { + inorder(root->left); + visit(root); + inorder(root->right); +} +``` + + + + +```py +def inorder(root: TreeNode): + inorder(root.left) + visit(root) + inorder(root.right) +``` + + + + + +后序遍历先遍历左节点,再遍历右结点,最后遍历父节点,我们得到的遍历顺序是 [4 5 2 6 3 1]。 + + + + +```cpp +void postorder(TreeNode* root) { + postorder(root->left); + postorder(root->right); + visit(root); +} +``` + + + + +```py +def postorder(root: TreeNode): + postorder(root.left) + postorder(root.right) + visit(root) +``` + + + + + +## [105. Construct Binary Tree from Preorder and Inorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) + +### 题目描述 + +给定一个二叉树的前序遍历和中序遍历结果,尝试复原这个树。已知树里不存在重复值的节点。 + +### 输入输出样例 + +输入是两个一维数组,分别表示树的前序遍历和中序遍历结果;输出是一个二叉树。 + +``` +Input: preorder = [4,9,20,15,7], inorder = [9,4,15,20,7] +Output: + 4 + / \ + 9 20 + / \ + 15 7 +``` + +### 题解 + +我们通过本题的样例讲解一下本题的思路。前序遍历的第一个节点是 4,意味着 4 是根节点。我们在中序遍历结果里找到 4 这个节点,根据中序遍历的性质可以得出,4 在中序遍历数组位置的左子数组为左子树,节点数为 1,对应的是前序排列数组里 4 之后的 1 个数字(9);4 在中序遍历数组位置的右子数组为右子树,节点数为 3,对应的是前序排列数组里最后的 3 个数字。有了这些信息,我们就可以对左子树和右子树进行递归复原了。为了方便查找数字的位置,我们可以用哈希表预处理中序遍历的结果。 + + + + +```cpp +// 辅函数。 +TreeNode* reconstruct(unordered_map& io_map, vector& po, int l, + int r, int mid_po) { + if (l > r) { + return nullptr; + } + int mid_val = po[mid_po]; + int mid_io = io_map[mid_val]; + int left_len = mid_io - l + 1; + TreeNode* node = new TreeNode(mid_val); + node->left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1); + node->right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len); + return node; +} +// 主函数。 +TreeNode* buildTree(vector& preorder, vector& inorder) { + unordered_map io_map; + for (int i = 0; i < inorder.size(); ++i) { + io_map[inorder[i]] = i; + } + return reconstruct(io_map, preorder, 0, preorder.size() - 1, 0); +} +``` + + + + +```py +# 辅函数。 +def reconstruct( + io_map: Dict[int, int], po: List[int], l: int, r: int, mid_po: int +) -> Optional[TreeNode]: + if l > r: + return None + mid_val = po[mid_po] + mid_io = io_map[mid_val] + left_len = mid_io - l + 1 + node = TreeNode(mid_val) + node.left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1) + node.right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len) + return node + +# 主函数。 +def buildTree(preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + io_map = {val: i for i, val in enumerate(inorder)} + return reconstruct(io_map, preorder, 0, len(preorder) - 1, 0) + +``` + + + + + +## [144. Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) + +### 题目描述 + +不使用递归,实现二叉树的前序遍历。 + +### 输入输出样例 + +输入一个二叉树,输出一个数组,为二叉树前序遍历的结果, + +``` +Input: + 1 + \ + 2 + / + 3 +Output: [1,2,3] +``` + +### 题解 + +因为递归的本质是栈调用,因此我们可以通过栈来实现前序遍历。注意入栈的顺序。 + + + + +```cpp +vector preorderTraversal(TreeNode* root) { + vector po; + if (root == nullptr) { + return po; + } + stack s; + s.push(root); + while (!s.empty()) { + TreeNode* node = s.top(); + s.pop(); + po.push_back(node->val); + if (node->right) { + s.push(node->right); // 先右后左,保证左子树先遍历 + } + if (node->left) { + s.push(node->left); + } + } + return po; +} +``` + + + + +```py +def preorderTraversal(root: Optional[TreeNode]) -> List[int]: + po = [] + if root is None: + return po + s = [root] + while len(s) > 0: + node = s.pop() + po.append(node.val) + if node.right is not None: + s.append(node.right) # 先右后左,保证左子树先遍历 + if node.left is not None: + s.append(node.left) + return po +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-5-binary-search-tree.mdx b/leetcode_101/docs/13-trees/13-5-binary-search-tree.mdx new file mode 100644 index 00000000..b3e9b709 --- /dev/null +++ b/leetcode_101/docs/13-trees/13-5-binary-search-tree.mdx @@ -0,0 +1,185 @@ +--- +sidebar_position: 72 +--- + +# 13.5 二叉查找树 + +`二叉查找树`(Binary Search Tree, BST)是一种特殊的二叉树:对于每个父节点,其左子树中所有节点的值小于等于父结点的值,其右子树中所有节点的值大于等于父结点的值。因此对于一个二叉查找树,我们可以在 O(log n) 的时间内查找一个值是否存在:从根节点开始,若当前节点的值大于查找值则向左下走,若当前节点的值小于查找值则向右下走。同时因为二叉查找树是有序的,对其中序遍历的结果即为排好序的数组。 + +例如下面这棵树即为二叉查找树,其中序遍历结果为 [1 2 3 4 5 6]。 + +``` + 4 + / \ + 2 5 + / \ \ +1 3 6 +``` + +## [99. Recover Binary Search Tree](https://leetcode.com/problems/recover-binary-search-tree/) + +### 题目描述 + +给定一个二叉查找树,已知有两个节点被不小心交换了,试复原此树。 + +### 输入输出样例 + +输入是一个被误交换两个节点的二叉查找树,输出是改正后的二叉查找树。 + +``` +Input: + 3 + / \ +1 4 + / + 2 +Output: + 2 + / \ +1 4 + / + 3 +``` + +在这个样例中,2 和 3 被不小心交换了。 + +### 题解 + +我们可以使用中序遍历这个二叉查找树,同时设置一个 prev 指针,记录当前节点中序遍历时的前节点。如果当前节点大于 prev 节点的值,说明需要调整次序。有一个技巧是如果遍历整个序列过程中只出现了一次次序错误,说明就是这两个相邻节点需要被交换;如果出现了两次次序错误,那就需要交换这两个节点。 + + + + +```cpp +// 辅函数。 +void inorder(TreeNode* root, TreeNode*& mistake1, TreeNode*& mistake2, + TreeNode*& prev) { + if (root == nullptr) { + return; + } + inorder(root->left, mistake1, mistake2, prev); + if (prev != nullptr && root->val < prev->val) { + if (mistake1 == nullptr) { + mistake1 = prev; + } + mistake2 = root; + } + prev = root; + inorder(root->right, mistake1, mistake2, prev); +} +// 主函数。 +void recoverTree(TreeNode* root) { + TreeNode *mistake1 = nullptr, *mistake2 = nullptr, *prev = nullptr; + inorder(root, mistake1, mistake2, prev); + if (mistake1 != nullptr && mistake2 != nullptr) { + swap(mistake1->val, mistake2->val); + } +} +``` + + + + +```py +# 辅函数。 +# 注意,Python中并不方便在辅函数中直接传指针,因此我们建造长度为1的list进行传引用。 +def inorder( + root: Optional[TreeNode], + mistake1=List[Optional[TreeNode]], + mistake2=List[Optional[TreeNode]], + prev=List[Optional[TreeNode]], +): + if root is None: + return + inorder(root.left, mistake1, mistake2, prev) + if prev[0] is not None and root.val < prev[0].val: + if mistake1[0] is None: + mistake1[0] = prev[0] + mistake2[0] = root + prev[0] = root + inorder(root.right, mistake1, mistake2, prev) + +# 主函数。 +def recoverTree(root: Optional[TreeNode]) -> None: + mistake1, mistake2, prev = [None], [None], [None] + inorder(root, mistake1, mistake2, prev) + if mistake1[0] is not None and mistake2[0] is not None: + mistake1[0].val, mistake2[0].val = mistake2[0].val, mistake1[0].val +``` + + + + + +## [669. Trim a Binary Search Tree](https://leetcode.com/problems/trim-a-binary-search-tree/) + +### 题目描述 + +给定一个二叉查找树和两个整数 L 和 R,且 L < R,试修剪此二叉查找树,使得修剪后所有节点的值都在 [L, R] 的范围内。 + +### 输入输出样例 + +输入是一个二叉查找树和两个整数 L 和 R,输出一个被修剪好的二叉查找树。 + +``` +Input: L = 1, R = 3, tree = + 3 + / \ + 0 4 + \ + 2 + / + 1 +Output: + 3 + / + 2 + / +1 +``` + +### 题解 + +利用二叉查找树的大小关系,我们可以很容易地利用递归进行树的处理。 + + + + +```cpp +TreeNode* trimBST(TreeNode* root, int low, int high) { + if (root == nullptr) { + return root; + } + if (root->val > high) { + return trimBST(root->left, low, high); + } + if (root->val < low) { + return trimBST(root->right, low, high); + } + root->left = trimBST(root->left, low, high); + root->right = trimBST(root->right, low, high); + return root; +} +``` + + + + +```py +def trimBST( + root: Optional[TreeNode], low: int, high: int +) -> Optional[TreeNode]: + if root is None: + return None + if root.val > high: + return trimBST(root.left, low, high) + if root.val < low: + return trimBST(root.right, low, high) + root.left = trimBST(root.left, low, high) + root.right = trimBST(root.right, low, high) + return root +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-6-trie.mdx b/leetcode_101/docs/13-trees/13-6-trie.mdx new file mode 100644 index 00000000..2e1f7e9d --- /dev/null +++ b/leetcode_101/docs/13-trees/13-6-trie.mdx @@ -0,0 +1,137 @@ +--- +sidebar_position: 73 +--- + +# 13.6 字典树 + +字典树(Trie)用于判断字符串是否存在或者是否具有某种字符串前缀。 + +
+ + ![](13.1.png) + +
图 13.1: 字典树,存储了单词 A、to、tea、ted、ten、i、in 和 inn,以及它们的频率
+
+ +为什么需要用字典树解决这类问题呢?假如我们有一个储存了近万个单词的字典,即使我们使用哈希,在其中搜索一个单词的实际开销也是非常大的,且无法轻易支持搜索单词前缀。然而由于一个英文单词的长度 n 通常在 10 以内,如果我们使用字典树,则可以在 $O(n)$——近似 $O(1)$ 的时间内完成搜索,且额外开销非常小。 + +## [208. Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) + +### 题目描述 + +尝试建立一个字典树,支持快速插入单词、查找单词、查找单词前缀的功能。 + +### 输入输出样例 + +以下是数据结构的调用样例。 + +``` +Trie trie = new Trie(); +trie.insert("apple"); +trie.search("apple"); // true +trie.search("app"); // false +trie.startsWith("app"); // true +trie.insert("app"); +trie.search("app"); // true +``` + +### 题解 + +以下是字典树的典型实现方法。 + + + + +```cpp +struct TrieNode { + bool word_ends; + vector children; + TrieNode() : word_ends(false), children(26, nullptr) {} +}; + +class Trie { + public: + Trie() : root_(new TrieNode()) {} + + void insert(string word) { + TrieNode* node = root_; + for (char c : word) { + int pos = c - ’a’; + if (node->children[pos] == nullptr) { + node->children[pos] = new TrieNode(); + } + node = node->children[pos]; + } + node->word_ends = true; + } + + bool search(string word) { + TrieNode* node = root_; + for (char c : word) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr && node->word_ends; + } + + bool startsWith(string prefix) { + TrieNode* node = root_; + for (char c : prefix) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr; + } + + private: + TrieNode* root_; +}; +``` + + + + +```py +class TrieNode: + def __init__(self): + self.word_ends = False + self.children = [None] * 26 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word: str) -> None: + node = self.root + for c in word: + pos = ord(c) - ord("a") + if node.children[pos] is None: + node.children[pos] = TrieNode() + node = node.children[pos] + node.word_ends = True + + def search(self, word: str) -> bool: + node = self.root + for c in word: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None and node.word_ends + + def startsWith(self, prefix: str) -> bool: + node = self.root + for c in prefix: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13-7-exercises.md b/leetcode_101/docs/13-trees/13-7-exercises.md new file mode 100644 index 00000000..d002c2c0 --- /dev/null +++ b/leetcode_101/docs/13-trees/13-7-exercises.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 74 +--- + +# 13.7 练习 + +## 基础难度 + +### [226. Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) + +巧用递归,你可以在五行内完成这道题。 + +--- + +### [617. Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees/) + +同样的,利用递归可以轻松搞定。 + +--- + +### [572. Subtree of Another Tree](https://leetcode.com/problems/subtree-of-another-tree/) + +子树是对称树的姊妹题,写法也十分类似。 + +--- + +### [404. Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) + +怎么判断一个节点是不是左节点呢?一种可行的方法是,在辅函数里多传一个参数,表示当前节点是不是父节点的左节点。 + +--- + +### [513. Find Bottom Left Tree Value](https://leetcode.com/problems/find-bottom-left-tree-value/) + +最左下角的节点满足什么条件?针对这种条件,我们该如何找到它? + +--- + +### [538. Convert BST to Greater Tree](https://leetcode.com/problems/convert-bst-to-greater-tree/) + +尝试利用某种遍历方式来解决此题,每个节点只需遍历一次。 + +--- + +### [235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) + +利用 BST 的独特性质,这道题可以很轻松完成。 + +--- + +### [530. Minimum Absolute Difference in BST](https://leetcode.com/problems/minimum-absolute-difference-in-bst/) + +还记得我们所说的,对于 BST 应该利用哪种遍历吗? + +--- + +## 进阶难度 + +### [1530. Number of Good Leaf Nodes Pairs](https://leetcode.com/problems/number-of-good-leaf-nodes-pairs/) + +题目 543 的变种题,注意在辅函数中,每次更新的全局变量是左右两边距离之和满足条件的数量,而返回的是左右两边所有(长度不溢出的)子节点的高度 +1。 + +--- + +### [889. Construct Binary Tree from Preorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) + +给定任意两种遍历结果,我们都可以重建树的结构。 + +--- + +### [106. Construct Binary Tree from Inorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) + +给定任意两种遍历结果,我们都可以重建树的结构。 + +--- + +### [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) + +因为前中序后遍历是用递归实现的,而递归的底层实现是栈操作,因此我们总能用栈实现。 + +--- + +### [145. Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) + +因为前中序后遍历是用递归实现的,而递归的底层实现是栈操作,因此我们总能用栈实现。 + +--- + +### [236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) + +现在不是 BST,而是普通的二叉树了,该怎么办? + +--- + +### [109. Convert Sorted List to Binary Search Tree](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) + +把排好序的链表变成 BST。为了使得 BST 尽量平衡,我们需要寻找链表的中点。 + +--- + +### [897. Increasing Order Search Tree](https://leetcode.com/problems/increasing-order-search-tree/) + +把 BST 压成一个链表,务必考虑清楚指针操作的顺序,否则可能会出现环路。 + +--- + +### [653. Two Sum IV - Input is a BST](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/) + +啊哈,这道题可能会把你骗到。 + +--- + +### [450. Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/) + +当寻找到待删节点时,你可以分情况考虑——当前节点是叶节点、只有一个子节点和有两个子节点。建议同时回收内存。 \ No newline at end of file diff --git a/leetcode_101/docs/13-trees/13.1.png b/leetcode_101/docs/13-trees/13.1.png new file mode 100644 index 00000000..06c168c6 Binary files /dev/null and b/leetcode_101/docs/13-trees/13.1.png differ diff --git a/leetcode_101/docs/13-trees/_category_.json b/leetcode_101/docs/13-trees/_category_.json new file mode 100644 index 00000000..db81316e --- /dev/null +++ b/leetcode_101/docs/13-trees/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "13. 指针三剑客之二:树", + "position": 13, + "link": { + "type": "generated-index", + "description": "第 13 章 指针三剑客之二:树" + } +} diff --git a/leetcode_101/docs/14-graphs/14-1-data-structure-introduction.mdx b/leetcode_101/docs/14-graphs/14-1-data-structure-introduction.mdx new file mode 100644 index 00000000..8e592d82 --- /dev/null +++ b/leetcode_101/docs/14-graphs/14-1-data-structure-introduction.mdx @@ -0,0 +1,16 @@ +--- +sidebar_position: 75 +--- + +# 14.1 数据结构介绍 + +作为指针三剑客之三,图是树的升级版。`图`通常分为有向(directed)或无向(undirected),有循环(cyclic)或无循环(acyclic),所有节点相连(connected)或不相连(disconnected)。树即是一个相连的无向无环图,而另一种很常见的图是`有向无环图`(Directed Acyclic Graph,DAG)。 + +
+ + ![](14.1.png) + +
图 14.1: 有向无环图样例
+
+ +图通常有两种表示方法。假设图中一共有 n 个节点、m 条边。第一种表示方法是`邻接矩阵`(adjacency matrix):我们可以建立一个 n × n 的矩阵 G,如果第 i 个节点连向第 j 个节点,则 G[i][j] = 1,反之为 0;如果图是无向的,则这个矩阵一定是对称矩阵,即 G[i][j] = G[j][i]。第二种表示方法是`邻接链表`(adjacency list):我们可以建立一个大小为 n 的数组,每个位置 i 储存一个数组或者链表,表示第 i 个节点连向的其它节点。邻接矩阵空间开销比邻接链表大,但是邻接链表不支持快速查找 i 和 j 是否相连,因此两种表示方法可以根据题目需要适当选择。除此之外,我们也可以直接用一个 m × 2 的矩阵储存所有的边。 \ No newline at end of file diff --git a/leetcode_101/docs/14-graphs/14-2-bipartite-graph.mdx b/leetcode_101/docs/14-graphs/14-2-bipartite-graph.mdx new file mode 100644 index 00000000..27ce77fd --- /dev/null +++ b/leetcode_101/docs/14-graphs/14-2-bipartite-graph.mdx @@ -0,0 +1,90 @@ +--- +sidebar_position: 76 +--- + +# 14.2 二分图 + +`二分图`算法也称为`染色法`,是一种广度优先搜索。如果可以用两种颜色对图中的节点进行着色,并且保证相邻的节点颜色不同,那么图为二分。 + +## [785. Is Graph Bipartite?](https://leetcode.com/problems/is-graph-bipartite/) + +### 题目描述 + +给定一个图,判断其是否可以二分。 + +### 输入输出样例 + +输入是邻接链表表示的图(如位置 0 的邻接链表为 [1,3],表示 0 与 1、0 与 3 相连);输出是一个布尔值,表示图是否二分。 + +``` +Input: [[1,3], [0,2], [1,3], [0,2]] +0----1 +| | +| | +3----2 +Output: true +``` + +在这个样例中,我们可以把 {0,2} 分为一组,把 {1,3} 分为另一组。 + +### 题解 + +利用队列和广度优先搜索,我们可以对未染色的节点进行染色,并且检查是否有颜色相同的相邻节点存在。注意在代码中,我们用 0 表示未检查的节点,用 1 和 2 表示两种不同的颜色。 + + + + +```cpp +bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n, 0); + queue q; + for (int i = 0; i < n; ++i) { + if (color[i] == 0) { + q.push(i); + color[i] = 1; + } + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int j : graph[node]) { + if (color[j] == 0) { + q.push(j); + color[j] = color[node] == 2 ? 1 : 2; + } else if (color[j] == color[node]) { + return false; + } + } + } + } + return true; +} +``` + + + + +```py +def isBipartite(graph: List[List[int]]) -> bool: + n = len(graph) + color = [0] * n + q = collections.deque() + + for i in range(n): + if color[i] == 0: + q.append(i) + color[i] = 1 + while len(q) > 0: + node = q.popleft() + for j in graph[node]: + if color[j] == 0: + q.append(j) + color[j] = 1 if color[node] == 2 else 2 + elif color[j] == color[node]: + return False + return True +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/14-graphs/14-3-topological-sorting.mdx b/leetcode_101/docs/14-graphs/14-3-topological-sorting.mdx new file mode 100644 index 00000000..02473beb --- /dev/null +++ b/leetcode_101/docs/14-graphs/14-3-topological-sorting.mdx @@ -0,0 +1,97 @@ +--- +sidebar_position: 77 +--- + +# 14.3 拓扑排序 + +`拓扑排序`(topological sort)是一种常见的,对有向无环图排序的算法。给定有向无环图中的 $N$ 个节点,我们把它们排序成一个线性序列;若原图中节点 i 指向节点 j,则排序结果中 i 一定在 j 之前。拓扑排序的结果不是唯一的,只要满足以上条件即可。 + +## [210. Course Schedule II](https://leetcode.com/problems/course-schedule-ii/) + +### 题目描述 + +给定 N 个课程和这些课程的前置必修课,求可以一次性上完所有课的顺序。 + +### 输入输出样例 + +输入是一个正整数,表示课程数量,和一个二维矩阵,表示所有的有向边(如 [1,0] 表示上课程 1 之前必须先上课程 0)。输出是一个一维数组,表示拓扑排序结果。 + +``` +Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] +Output: [0,1,2,3] +``` + +在这个样例中,另一种可行的顺序是 [0,2,1,3]。 + +### 题解 + +我们可以先建立一个邻接矩阵表示图,方便进行直接查找。这里注意我们将所有的边反向,使得如果课程 i 指向课程 j,那么课程 i 需要在课程 j 前面先修完。这样更符合我们的直观理解。 + +拓扑排序也可以被看成是广度优先搜索的一种情况:我们先遍历一遍所有节点,把入度为 0 的节点(即没有前置课程要求)放在队列中。在每次从队列中获得节点时,我们将该节点放在目前排序的末尾,并且把它指向的课程的入度各减 1;如果在这个过程中有课程的所有前置必修课都已修完(即入度为 0),我们把这个节点加入队列中。当队列的节点都被处理完时,说明所有的节点都已排好序,或因图中存在循环而无法上完所有课程。 + + + + +```cpp +vector findOrder(int numCourses, vector>& prerequisites) { + vector> graph(numCourses, vector()); + vector indegree(numCourses, 0), schedule; + for (const auto& pr : prerequisites) { + graph[pr[1]].push_back(pr[0]); + ++indegree[pr[0]]; + } + queue q; + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] == 0) { + q.push(i); + } + } + while (!q.empty()) { + int u = q.front(); + q.pop(); + schedule.push_back(u); + for (int v : graph[u]) { + --indegree[v]; + if (indegree[v] == 0) { + q.push(v); + } + } + } + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] != 0) { + return vector(); + } + } + return schedule; +} +``` + + + + +```py +def findOrder(numCourses: int, prerequisites: List[List[int]]) -> List[int]: + graph = [[] for _ in range(numCourses)] + indegree = [0] * numCourses + schedule = [] + + for pr_from, pr_to in prerequisites: + graph[pr_to].append(pr_from) + indegree[pr_from] += 1 + + q = collections.deque([i for i, deg in enumerate(indegree) if deg == 0]) + + while len(q) > 0: + u = q.popleft() + schedule.append(u) + for v in graph[u]: + indegree[v] -= 1 + if indegree[v] == 0: + q.append(v) + + return schedule if all(deg == 0 for deg in indegree) else [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/14-graphs/14-4-exercises.md b/leetcode_101/docs/14-graphs/14-4-exercises.md new file mode 100644 index 00000000..88b9166e --- /dev/null +++ b/leetcode_101/docs/14-graphs/14-4-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 78 +--- + +# 14.4 练习 + +## 基础难度 + +### [1059. All Paths from Source Lead to Destination](https://leetcode.com/problems/all-paths-from-source-lead-to-destination/) + +虽然使用深度优先搜索可以解决大部分的图遍历问题,但是注意判断是否陷入了环路。 + +--- + +## 进阶难度 + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +笔者其实已经把这道题的题解写好了,才发现这道题是需要解锁才可以看的题目。为了避免版权纠纷,故将其移至练习题内。本题考察最小生成树(minimum spanning tree, MST)的求法,通常可以用两种方式求得:Prim’s Algorithm,利用优先队列选择最小的消耗;以及 Kruskal’s Algorithm,排序后使用并查集。 + +--- + +### [882. Reachable Nodes In Subdivided Graph](https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/) + +这道题笔者考虑了很久,最终决定把它放在练习题而非详细讲解。本题是经典的节点最短距离问题,常用的算法有 Bellman-Ford 单源最短路算法,以及 Dijkstra 无负边单源最短路算法。虽然经典,但是 LeetCode 很少有相关的题型,因此这里仅供读者自行深入学习。 \ No newline at end of file diff --git a/leetcode_101/docs/14-graphs/14.1.png b/leetcode_101/docs/14-graphs/14.1.png new file mode 100644 index 00000000..46ebed1b Binary files /dev/null and b/leetcode_101/docs/14-graphs/14.1.png differ diff --git a/leetcode_101/docs/14-graphs/_category_.json b/leetcode_101/docs/14-graphs/_category_.json new file mode 100644 index 00000000..7a36d4cd --- /dev/null +++ b/leetcode_101/docs/14-graphs/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "14. 指针三剑客之三:图", + "position": 14, + "link": { + "type": "generated-index", + "description": "第 14 章 指针三剑客之三:图" + } +} diff --git a/leetcode_101/docs/15-advanced-data-structures/15-1-introduction.md b/leetcode_101/docs/15-advanced-data-structures/15-1-introduction.md new file mode 100644 index 00000000..26e5cdac --- /dev/null +++ b/leetcode_101/docs/15-advanced-data-structures/15-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 75 +--- + +# 15.1 引言 + +目前为止,我们接触了大量的数据结构,包括利用指针实现的三剑客和 C++ 自带的 STL 等。对于一些题目,我们不仅需要利用多个数据结果解决问题,还需要把这些数据结构进行嵌套和联动,进行更为复杂、更为快速的操作。 \ No newline at end of file diff --git a/leetcode_101/docs/15-advanced-data-structures/15-2-union-find.mdx b/leetcode_101/docs/15-advanced-data-structures/15-2-union-find.mdx new file mode 100644 index 00000000..5034a49a --- /dev/null +++ b/leetcode_101/docs/15-advanced-data-structures/15-2-union-find.mdx @@ -0,0 +1,140 @@ +--- +sidebar_position: 76 +--- + +# 15.2 并查集 + +`并查集`(union-find, disjoint set)可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。假设存在 n 个节点,我们先将所有节点的父节点标为自己;每次要连接节点 i 和 j 时,我们可以将秩较小一方的父节点标为另一方(按秩合并);每次要查询两个节点是否相连时,我们可以查找 i 和 j 的祖先是否最终为同一个人,并减少祖先层级(路径压缩)。 + +
+ + ![](15.1.png) + +
图 15.1: 并查集样例,其中 union 操作可以将两个集合按秩合并,find 操作可以查找节点的祖先并压缩路径。
+
+ +## [684. Redundant Connection](https://leetcode.com/problems/redundant-connection/) + +### 题目描述 + +在无向图找出一条边,移除它之后该图能够成为一棵树(即无向无环图)。如果有多个解,返回在原数组中位置最靠后的那条边。 + +### 输入输出样例 + +输入是一个二维数组,表示所有的边(对应的两个节点);输出是一个一维数组,表示需要移除的边(对应的两个节点)。 + +``` +Input: [[1,2], [1,3], [2,3]] + 1 + / \ +2 - 3 +Output: [2,3] +``` + +### 题解 + +因为需要判断是否两个节点被重复连通,所以我们可以使用并查集来解决此类问题。具体实现算法如下所示。 + + + + +```cpp +class Solution { + public: + vector findRedundantConnection(vector>& edges) { + n_ = edges.size(); + id_ = vector(n_); + depth_ = vector(n_, 1); + for (int i = 0; i < n_; ++i) { + id_[i] = i; + } + for (auto& edge : edges) { + int i = edge[0], j = edge[1]; + if (linked(i - 1, j - 1)) { + return vector{i, j}; + } + connect(i - 1, j - 1); + } + return vector(); + } + + private: + int find(int i) { + // 路径压缩。 + while (i != id_[i]) { + id_[i] = id_[id_[i]]; + i = id_[i]; + } + return i; + } + + void connect(int i, int j) { + i = find(i), j = find(j); + if (i == j) { + return; + } + // 按秩合并。 + if (depth_[i] <= depth_[j]) { + id_[i] = j; + depth_[j] = max(depth_[j], depth_[i] + 1); + } else { + id_[j] = i; + depth_[i] = max(depth_[i], depth_[j] + 1); + } + } + + bool linked(int i, int j) { return find(i) == find(j); } + + int n_; + vector id_; + vector depth_; +}; +``` + + + + +```py +class Solution: + def __init__(self): + self.n = 0 + self.id = None + self.depth = None + + def find(self, i: int) -> int: + # 路径压缩。 + while i != self.id[i]: + self.id[i] = self.id[self.id[i]] + i = self.id[i] + return i + + def connect(self, i: int, j: int): + i = self.find(i) + j = self.find(j) + if i == j: + return + # 按秩合并。 + if self.depth[i] <= self.depth[j]: + self.id[i] = j + self.depth[j] = max(self.depth[j], self.depth[i] + 1) + else: + self.id[j] = i + self.depth[i] = max(self.depth[i], self.depth[j] + 1) + + def linked(self, i: int, j: int) -> bool: + return self.find(i) == self.find(j) + + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + self.n = len(edges) + self.id = list(range(self.n)) + self.depth = [1] * self.n + for i, j in edges: + if self.linked(i - 1, j - 1): + return [i, j] + self.connect(i - 1, j - 1) + return [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/15-advanced-data-structures/15-3-composite-data-structures.mdx b/leetcode_101/docs/15-advanced-data-structures/15-3-composite-data-structures.mdx new file mode 100644 index 00000000..bada3aea --- /dev/null +++ b/leetcode_101/docs/15-advanced-data-structures/15-3-composite-data-structures.mdx @@ -0,0 +1,257 @@ +--- +sidebar_position: 77 +--- + +# 15.3 复合数据结构 + +这一类题通常采用哈希表或有序表辅助记录,从而加速寻址;再配上数组或者链表进行连续的数据储存,从而加速连续选址或删除值。 + +## [146. LRU Cache](https://leetcode.com/problems/lru-cache/) + +### 题目描述 + +设计一个固定大小的,最近最少使用缓存 (least recently used cache, LRU)。每次将信息插入未满的缓存的时候,以及更新或查找一个缓存内存在的信息的时候,将该信息标为最近使用。在缓存满的情况下将一个新信息插入的时候,需要移除最旧的信息,插入新信息,并将该新信息标为最近使用。 + +### 输入输出样例 + +以下是数据结构的调用样例。给定一个大小为 n 的缓存,利用最近最少使用策略储存数据。 + +``` +LRUCache cache = new LRUCache( 2 /* capacity */ ); +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // 输出 value 1 +cache.put(3, 3); // 移除 key 2 +cache.get(2); // 输出 value -1 (未找到) +cache.put(4, 4); // 移除 key 1 +cache.get(1); // 输出 value -1 (未找到) +cache.get(3); // 输出 value 3 +cache.get(4); // 输出 value 4 +``` + +### 题解 + +我们采用一个链表来储存信息的 key 和 value,链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点。同时我们需要一个哈希表进行查找,键是信息的 key,值是其在链表中的对应指针/迭代器。每次查找成功(cache hit)时,需要把指针/迭代器对应的节点移动到链表的头节点。 + + + + +```cpp +class LRUCache { + public: + LRUCache(int capacity) : n_(capacity) {} + + int get(int key) { + auto it = key_to_cache_it_.find(key); + if (it == key_to_cache_it_.end()) { + return -1; + } + cache_.splice(cache_.begin(), cache_, it->second); + return it->second->second; + } + + void put(int key, int value) { + auto it = key_to_cache_it_.find(key); + if (it != key_to_cache_it_.end()) { + it->second->second = value; + return cache_.splice(cache_.begin(), cache_, it->second); + } + cache_.insert(cache_.begin(), make_pair(key, value)); + key_to_cache_it_[key] = cache_.begin(); + if (cache_.size() > n_) { + key_to_cache_it_.erase(cache_.back().first); + cache_.pop_back(); + } + } + + private: + list> cache_; + unordered_map>::iterator> key_to_cache_it_; + int n_; +}; +``` + + + + +```py +class Node: + def __init__(self, key=-1, val=-1): + self.key = key + self.val = val + self.prev = None + self.next = None + +class LinkedList: + def __init__(self): + self.dummy_start = Node() + self.dummy_end = Node() + self.dummy_start.next = self.dummy_end + self.dummy_end.prev = self.dummy_start + + def appendleft(self, node) -> Node: + left, right = self.dummy_start, self.dummy_start.next + node.next = right + right.prev = node + left.next = node + node.prev = left + return node + + def remove(self, node) -> Node: + left, right = node.prev, node.next + left.next = right + right.prev = left + return node + + def move_to_start(self, node): + return self.appendleft(self.remove(node)) + + def pop(self): + return self.remove(self.dummy_end.prev) + + def peek(self): + return self.dummy_end.prev.val + +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.key_to_node = dict() + self.cache_nodes = LinkedList() + + def get(self, key: int) -> int: + if key not in self.key_to_node: + return -1 + node = self.key_to_node[key] + self.cache_nodes.move_to_start(node) + return node.val + + def put(self, key: int, value: int) -> None: + if key in self.key_to_node: + node = self.cache_nodes.remove(self.key_to_node[key]) + node.val = value + else: + node = Node(key, value) + self.key_to_node[key] = node + self.cache_nodes.appendleft(node) + if len(self.key_to_node) > self.n: + self.key_to_node.pop(self.cache_nodes.pop().key) +``` + + + + + +对于 Python 而言,我们还可以直接利用 OrderedDict 函数实现 LRU,这将大大简化题目难度。这里笔者希望读者还是仔细研读一下以上题解,了解 LRU 实现的核心原理。 + + +```py +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.cache = {} + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + self.cache[key] = self.cache.pop(key) + return self.cache[key] + + def put(self, key: int, value: int) -> None: + if key in self.cache: + self.cache.pop(key) + self.cache[key] = value + if len(self.cache) > self.n: + self.cache.pop(next(iter(self.cache))) +``` + +## [380. Insert Delete GetRandom O(1)](https://leetcode.com/problems/insert-delete-getrandom-o1/) + +### 题目描述 + +设计一个插入、删除和随机取值均为 $O(1)$ 时间复杂度的数据结构。 + +### 输入输出样例 + +以下是数据结构的调用样例。 + +``` +RandomizedSet randomizedSet = new RandomizedSet(); +randomizedSet.insert(1); +randomizedSet.remove(2); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 50% 1, 50% 2 +randomizedSet.remove(1); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 100% 2 +``` + +### 题解 + +我们采用一个数组存储插入的数字,同时利用一个哈希表查找位置。每次插入数字时,直接加入数组,且将位置记录在哈希表中。每次删除数字时,将当前数组最后一位与删除位互换,并更新哈希表。随机取值时,则可以在数组内任意选取位置。 + + + + +```cpp +class RandomizedSet { + public: + bool insert(int val) { + if (v_to_k_.contains(val)) { + return false; + } + v_to_k_[val] = nums_.size(); + nums_.push_back(val); + return true; + } + + bool remove(int val) { + if (!v_to_k_.contains(val)) { + return false; + } + v_to_k_[nums_.back()] = v_to_k_[val]; + nums_[v_to_k_[val]] = nums_.back(); + v_to_k_.erase(val); + nums_.pop_back(); + return true; + } + + int getRandom() { return nums_[rand() % nums_.size()]; } + + private: + unordered_map v_to_k_; + vector nums_; +}; +``` + + + + +```py +class RandomizedSet: + def __init__(self): + self.nums = [] + self.v_to_k = {} + + def insert(self, val: int) -> bool: + if val in self.v_to_k: + return False + self.v_to_k[val] = len(self.nums) + self.nums.append(val) + return True + + def remove(self, val: int) -> bool: + if val not in self.v_to_k: + return False + self.v_to_k[self.nums[-1]] = self.v_to_k[val] + self.nums[self.v_to_k[val]] = self.nums[-1] + del self.v_to_k[val] + self.nums.pop() + return True + + def getRandom(self) -> int: + return self.nums[random.randint(0, len(self.nums) - 1)] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/15-advanced-data-structures/15-4-exercises.md b/leetcode_101/docs/15-advanced-data-structures/15-4-exercises.md new file mode 100644 index 00000000..53d544da --- /dev/null +++ b/leetcode_101/docs/15-advanced-data-structures/15-4-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 78 +--- + +# 15.4 练习 + +## 基础难度 + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +使用并查集,按照 Kruskal’s Algorithm 把这道题再解决一次吧。 + +--- + +## 进阶难度 + +### [432. All O`one Data Structure](https://leetcode.com/problems/all-oone-data-structure/) + +设计一个 increaseKey,decreaseKey,getMaxKey,getMinKey 均为 $O(1)$ 时间复杂度的数据结构。 + +--- + +### [716. Max Stack](https://leetcode.com/problems/max-stack/) + +设计一个支持 push,pop,top,getMax 和 popMax 的 stack。可以用类似 LRU 的方法降低时间复杂度,但是因为想要获得的是最大值,我们应该把 unordered_map 换成哪一种数据结构呢? \ No newline at end of file diff --git a/leetcode_101/docs/15-advanced-data-structures/15.1.png b/leetcode_101/docs/15-advanced-data-structures/15.1.png new file mode 100644 index 00000000..6a2df359 Binary files /dev/null and b/leetcode_101/docs/15-advanced-data-structures/15.1.png differ diff --git a/leetcode_101/docs/15-advanced-data-structures/_category_.json b/leetcode_101/docs/15-advanced-data-structures/_category_.json new file mode 100644 index 00000000..dc11e088 --- /dev/null +++ b/leetcode_101/docs/15-advanced-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "15. 更加复杂的数据结构", + "position": 15, + "link": { + "type": "generated-index", + "description": "第 15 章 更加复杂的数据结构" + } +} diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-1-algorithm-explanation.md b/leetcode_101/docs/2-two-pointer-techniques/2-1-algorithm-explanation.md new file mode 100644 index 00000000..5c853023 --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-1-algorithm-explanation.md @@ -0,0 +1,21 @@ +--- +sidebar_position: 5 +--- + +# 2.1 算法解释 + +双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针。 + +若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。 + +若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。 + +在 C++ 中,要注意 const 的位置对指针效果的影响: + +```cpp +int x; +int * p1 = &x; // 指针可以被修改,值也可以被修改 +const int * p2 = &x; // 指针可以被修改,值不可以被修改(const int) +int * const p3 = &x; // 指针不可以被修改(* const),值可以被修改 +const int * const p4 = &x; // 指针不可以被修改,值也不可以被修改 +``` diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-2-two-sum.mdx b/leetcode_101/docs/2-two-pointer-techniques/2-2-two-sum.mdx new file mode 100644 index 00000000..f9a8eecc --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-2-two-sum.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 6 +--- + +# 2.2 Two Sum + +## [167. Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) + +### 题目描述 + +在一个增序的整数数组里找到两个数,使它们的和为给定值。已知有且只有一对解。 + +### 输入输出样例 + +输入是一个数组(numbers)和一个给定值(target)。输出是两个数的位置,从 1 开始计数。 + +``` +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +``` + +在这个样例中,第一个数字(2)和第二个数字(7)的和等于给定值(9)。 + +### 题解 + +因为数组已经排好序,我们可以采用方向相反的双指针来寻找这两个数字,一个初始指向最小的元素,即数组最左边,向右遍历;一个初始指向最大的元素,即数组最右边,向左遍历。 + +如果两个指针指向元素的和等于给定值,那么它们就是我们要的结果。如果两个指针指向元素的和小于给定值,我们把左边的指针右移一位,使得当前的和增加一点。如果两个指针指向元素的和大于给定值,我们把右边的指针左移一位,使得当前的和减少一点。 + +可以证明,对于排好序且有解的数组,双指针一定能遍历到最优解。证明方法如下:假设最优解的两个数的位置分别是 l 和 r。我们假设在左指针在 l 左边的时候,右指针已经移动到了 r;此时两个指针指向值的和小于给定值,因此左指针会一直右移直到到达 l。同理,如果我们假设在右指针在 r 右边的时候,左指针已经移动到了 l;此时两个指针指向值的和大于给定值,因此右指针会一直左移直到到达 r。所以双指针在任何时候都不可能处于 (l,r) 之间,又因为不满足条件时指针必须移动一个,所以最终一定会收敛在 l 和 r。 + + + + +```cpp +vector twoSum(vector& numbers, int target) { + int l = 0, r = numbers.size() - 1, two_sum; + while (l < r) { + two_sum = numbers[l] + numbers[r]; + if (two_sum == target) { + break; + } + if (two_sum < target) { + ++l; + } else { + --r; + } + } + return vector{l + 1, r + 1}; +} +``` + + + + +```py +def twoSum(numbers: List[int], target: int) -> List[int]: + l, r = 0, len(numbers) - 1 + while l < r: + two_sum = numbers[l] + numbers[r] + if two_sum == target: + break + if two_sum < target: + l += 1 + else: + r -= 1 + return [l + 1, r + 1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx b/leetcode_101/docs/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx new file mode 100644 index 00000000..29969e7f --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx @@ -0,0 +1,68 @@ +--- +sidebar_position: 7 +--- + +# 2.3 归并两个有序数组 + +## [88. Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) + +### 题目描述 + +给定两个有序数组,把两个数组合并为一个。 + +### 输入输出样例 + +输入是两个数组和它们分别的长度 m 和 n。其中第一个数组的长度被延长至 m +n,多出的 n 位被 0 填补。题目要求把第二个数组归并到第一个数组上,不需要开辟额外空间。 + +``` +Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 +Output: nums1 = [1,2,2,3,5,6] +``` + +### 题解 + +因为这两个数组已经排好序,我们可以把两个指针分别放在两个数组的末尾,即 nums1 的 m − 1 位和 nums2 的 n − 1 位。每次将较大的那个数字复制到 nums1 的后边,然后向前移动一位。 +因为我们也要定位 nums1 的末尾,所以我们还需要第三个指针,以便复制。 + +在以下的代码里,我们直接利用 m 和 n 当作两个数组的指针,再额外创立一个 pos 指针,起始位置为 m +n − 1。每次向左移动 m 或 n 的时候,也要向左移动 pos。这里需要注意,如果 nums1 +的数字已经复制完,不要忘记把 nums2 的数字继续复制;如果 nums2 的数字已经复制完,剩余 nums1 的数字不需要改变,因为它们已经被排好序。 + +在 C++ 题解里我们使用了 ++和--的小技巧:a++和 ++a都是将 a加 1,但是 a++返回值为 a,而 ++a返回值为 a+1。如果只是希望增加 a的值,而不需要返回值,则两个写法都可以(++a在未经编译器优化的情况下运行速度会略快一些)。 + + + + +```cpp +void merge(vector& nums1, int m, vector& nums2, int n) { + int pos = m-- + n-- - 1; + while (m >= 0 && n >= 0) { + nums1[pos--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; + } + while (n >= 0) { + nums1[pos--] = nums2[n--]; + } +} +``` + + + + +```py +def merge(nums1: List[int], m: int, nums2: List[int], n: int) -> None: + pos = m + n - 1 + m -= 1 + n -= 1 + while m >= 0 and n >= 0: + if nums1[m] > nums2[n]: + nums1[pos] = nums1[m] + m -= 1 + else: + nums1[pos] = nums2[n] + n -= 1 + pos -= 1 + nums1[: n + 1] = nums2[: n + 1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-4-sliding-window.mdx b/leetcode_101/docs/2-two-pointer-techniques/2-4-sliding-window.mdx new file mode 100644 index 00000000..c9d26f59 --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-4-sliding-window.mdx @@ -0,0 +1,108 @@ +--- +sidebar_position: 8 +--- + +# 2.4 滑动窗口 + +## [76. Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) + +### 题目描述 + +给定两个字符串 s 和 t,求 s 中包含 t 所有字符的最短连续子字符串的长度,同时要求时间复杂度不得超过 $O(n)$。 + +### 输入输出样例 + +输入是两个字符串 s 和 t,输出是一个 S 字符串的子串。如果不存在解,则输出一个空字符串。 + +``` +Input: s = "ADOBECODEBANC", t = "ABC" +Output: "BANC" +``` + +在这个样例中,s 中同时包含一个 A、一个 B、一个 C 的最短子字符串是“BANC”。 + +### 题解 + +本题使用滑动窗口求解,即两个指针 l 和 r 都是从最左端向最右端移动,且 l 的位置一定在 r 的左边或重合。C++ 题解中使用了两个长度为 128 的数组,valid 和 freq,来映射字符(ASCII +只包含 128 个字符)。其中 valid 表示每个字符在 t 中是否存在,而 freq 表示目前 t 中每个字符在 s 的滑动窗口中缺少的数量:如果为正,则说明还缺少;如果为负,则说明有盈余。Python 题解 +则直接使用 Counter 数据结构同时统计 t 中存在的字符和其缺少的数量(也可以用 dict 替代)。注意本题虽然在 for 循环里出现了一个 while 循环,但是因为 while 循环负责移动 l 指针,且 l 只会 +从左到右移动一次,因此总时间复杂度仍然是 $O(n)$。 + + + + +```cpp +string minWindow(string s, string t) { + vector valid(128, false); + vector freq(128, 0); + // 统计t中的字符情况。 + for (int i = 0; i < t.length(); ++i) { + valid[t[i]] = true; + ++freq[t[i]]; + } + // 移动滑动窗口,不断更改统计数据。 + int count = 0; + int min_l = -1, min_length = -1; + for (int l = 0, r = 0; r < s.length(); ++r) { + if (!valid[s[r]]) { + continue; + } + // 把r位置的字符加入频率统计,并检查是否补充了t中缺失的字符。 + if (--freq[s[r]] >= 0) { + ++count; + } + // 滑动窗口已包含t中全部字符,尝试右移l,在不影响结果的情况下寻找最短串。 + while (count == t.length()) { + if (min_length == -1 || r - l + 1 < min_length) { + min_l = l; + min_length = r - l + 1; + } + // 把l位置的字符移除频率统计,并检查t中对应字符是否重新缺失。 + if (valid[s[l]] && ++freq[s[l]] > 0) { + --count; + } + ++l; + } + } + return min_length == -1 ? "" : s.substr(min_l, min_length); +} +``` + + + + +```py +def minWindow(s: str, t: str) -> str: + # 统计t中的字符情况,等价于: + # freq = dict() + # for c in t: + # freq[c] = freq.get(c, 0) + 1 + freq = Counter(t) + # 移动滑动窗口,不断更改统计数据。 + count = 0 + min_l, min_length = None, None + l = 0 + for r in range(len(s)): + if s[r] not in freq: + continue + # 把r位置的字符加入频率统计,并检查是否补充了t中缺失的字符。 + freq[s[r]] -= 1 + if freq[s[r]] >= 0: + count += 1 + # 滑动窗口已包含t中全部字符,尝试右移l,在不影响结果的情况下寻找最短串。 + while count == len(t): + if min_length == None or r - l + 1 < min_length: + min_l = l + min_length = r - l + 1 + # 把l位置的字符移除频率统计,并检查t中对应字符是否重新缺失。 + if s[l] in freq: + freq[s[l]] += 1 + if freq[s[l]] > 0: + count -= 1 + l += 1 + return "" if min_length is None else s[min_l: min_l + min_length] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx b/leetcode_101/docs/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx new file mode 100644 index 00000000..26de16b5 --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx @@ -0,0 +1,100 @@ +--- +sidebar_position: 9 +--- + +# 2.5 快慢指针 + +## [142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/) + +### 题目描述 + +给定一个链表,如果有环路,找出环路的开始点。 + +### 输入输出样例 + +输入是一个链表,输出是链表的一个节点。如果没有环路,返回一个空指针。 +在这个样例中,值为 2 的节点即为环路的开始点。 +如果没有特殊说明,LeetCode 采用如下的数据结构表示链表。 + +![alt](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png) + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + +### 题解 + +对于链表找环路的问题,有一个通用的解法——快慢指针(Floyd 判圈法)。给定两个指针,分别命名为 slow 和 fast,起始位置在链表的开头。每次 fast 前进两步,slow 前进一步。如果 fast +可以走到尽头,那么说明没有环路;如果 fast 可以无限走下去,那么说明一定有环路,且一定存在一个时刻 slow 和 fast 相遇。当 slow 和 fast 第一次相遇时,我们将 fast 重新移动到链表开头,并 +让 slow 和 fast 每次都前进一步。当 slow 和 fast 第二次相遇时,相遇的节点即为环路的开始点。 + +:::warning + +对于某些只需要判断是否存在环路的题目,也可以通过建造哈希表来查重。 + +::: + + + + + +```cpp +ListNode *detectCycle(ListNode *head) { + ListNode *slow = head, *fast = head; + bool is_first_cycle = true; + // 检查环路。 + while (fast != slow || is_first_cycle) { + if (fast == nullptr || fast->next == nullptr) { + return nullptr; + } + fast = fast->next->next; + slow = slow->next; + is_first_cycle = false; + } + // 寻找节点。 + fast = head; + while (fast != slow) { + slow = slow->next; + fast = fast->next; + } + return fast; +} +``` + + + + +```py +def detectCycle(head: Optional[ListNode]) -> Optional[ListNode]: + slow = head + fast = head + is_first_cycle = True + # 检查环路。 + while fast != slow or is_first_cycle: + if fast is None or fast.next is None: + return None + fast = fast.next.next + slow = slow.next + is_first_cycle = False + # 寻找节点。 + fast = head + while fast != slow: + fast = fast.next + slow = slow.next + return fast +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/2-two-pointer-techniques/2-6-exercises.md b/leetcode_101/docs/2-two-pointer-techniques/2-6-exercises.md new file mode 100644 index 00000000..e97b5cf4 --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/2-6-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 10 +--- + +# 2.6 练习 + +## 基础难度 + +### [633. Sum of Square Numbers](https://leetcode.com/problems/sum-of-square-numbers/) + +Two Sum 题目的变形题之一。 + +--- + +### [680. Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) + +Two Sum 题目的变形题之二。 + +--- + +### [524. Longest Word in Dictionary through Deleting](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/) + +归并两个有序数组的变形题。 + +--- + +## 进阶难度 + +### [340. Longest Substring with At Most K Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/) + +需要利用其它数据结构方便统计当前的字符状态。 \ No newline at end of file diff --git a/leetcode_101/docs/2-two-pointer-techniques/_category_.json b/leetcode_101/docs/2-two-pointer-techniques/_category_.json new file mode 100644 index 00000000..23d4e78a --- /dev/null +++ b/leetcode_101/docs/2-two-pointer-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "2. 玩转双指针", + "position": 2, + "link": { + "type": "generated-index", + "description": "第 2 章 玩转双指针" + } +} diff --git a/leetcode_101/docs/3-binary-search-techniques/3-1-algorithm-explanation.md b/leetcode_101/docs/3-binary-search-techniques/3-1-algorithm-explanation.md new file mode 100644 index 00000000..7a908171 --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-1-algorithm-explanation.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 11 +--- + +# 3.1 算法解释 + +`二分查找`也常被称为`二分法`或者`折半查找` (binary search, bisect),每次查找时通过将待查找的单调区间分成两部分并只取一部分继续查找,将查找的复杂度大大减少。对于一个长度为 $O(n)$ 的数组,二分查找的时间复杂度为 $O(\log n)$。 + +举例来说,给定一个排好序的数组 $\{3,4,5,6,7\}$,我们希望查找 4 在不在这个数组内。第一次折半时考虑中位数 5,因为 5 大于 4, 所以如果 4 存在于这个数组,那么其必定存在于 5 左边这一半。于是我们的查找区间变成了 $\{3,4,5\}$。(注意,根据具体情况和您的刷题习惯,这里的 5 可以保留也可以不保留,并不影响时间复杂度的级别。)第二次折半时考虑新的中位数 4,正好是我们需要查找的数字。于是我们发现,对于一个长度为 5 的数组,我们只进行了 2 次查找。如果是遍历数组,最坏的情况则需要查找 5 次。 + +我们也可以用更加数学的方式定义二分查找。给定一个在 $[a, b]$ 区间内的单调函数 $f(t)$,若 $f(a)$ 和 $f(b)$ 正负性相反,那么必定存在一个解 $c$,使得 $f(c) = 0$。在上个例子中,$f(t)$ 是离散函数 $f(t) = t + 2$,查找 4 是否存在等价于求 $f(t) - 4 = 0$ 是否有离散解。因为 $f(1) - 4 = 3 - 4 = -1 < 0$、$f(5) - 4 = 7 - 4 = 3 > 0$,且函数在区间内单调递增,因此我们可以利用二分查找求解。如果最后二分到了不能再分的情况,如只剩一个数字,且剩余区间里不存在满足条件的解,则说明不存在离散解,即 4 不在这个数组内。 + +具体到代码上,二分查找时区间的左右端取开区间还是闭区间在绝大多数时候都可以,因此有些初学者会容易搞不清楚如何定义区间开闭性。这里笔者提供两个小诀窍,第一是尝试熟练使用一种写法,比如左闭右开(满足 C++、Python 等语言的习惯)或左闭右闭(便于处理边界条件),尽量只保持这一种写法;第二是在刷题时思考如果最后区间只剩下一个数或者两个数,自己的写法是否会陷入死循环,如果某种写法无法跳出死循环,则考虑尝试另一种写法。 + +二分查找也可以看作双指针的一种特殊情况,但我们一般会将二者区分。双指针类型的题,指针通常是一步一步移动的,而在二分查找里,指针通常每次移动半个区间长度。 diff --git a/leetcode_101/docs/3-binary-search-techniques/3-2-square-root.mdx b/leetcode_101/docs/3-binary-search-techniques/3-2-square-root.mdx new file mode 100644 index 00000000..8d0f4aab --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-2-square-root.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 12 +--- + +# 3.2 求开方 + +## [69. Sqrt(x)](https://leetcode.com/problems/sqrtx/) + +### 题目描述 + +给定一个非负整数 x,求它的开方,向下取整。 + +### 输入输出样例 + +输入一个整数,输出一个整数。 + +``` +Input: 8 +Output: 2 +``` + +8 的开方结果是 2.82842...,向下取整即是 2。 + + +### 题解 + +我们可以把这道题想象成,给定一个非负整数 x,求 $f (t) =t^2 − x =0$ 的解。因为我们只考虑 $t ≥ 0$,所以 $f (t)$ 在定义域上是单调递增的。考虑到 $f (0) =−x ≤ 0$, $f (x) = x^2 − x ≥ 0$,我们可以对 $[0, x]$ 区间使用二分法找到 $f (t) =0$ 的解。这里笔者使用了左闭右闭的写法。 + +在 C++ 题解中,$mid = (l +r)/2$ 可能会因为 $l +r$ 溢出而错误,因而采用 $mid = l +(r − l)/2$的写法;直接计算 $mid ∗ mid$ 也有可能溢出,因此我们比较 $mid$ 和 $x/mid$。 + + + + +```cpp +int mySqrt(int x) { + int l = 1, r = x, mid, x_div_mid; + while (l <= r) { + mid = l + (r - l) / 2; + x_div_mid = x / mid; + if (mid == x_div_mid) { + return mid; + } + if (mid < x_div_mid) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return r; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + l, r = 1, x + while l <= r: + mid = (l + r) // 2 + mid_sqr = mid**2 + if mid_sqr == x: + return mid + if mid_sqr < x: + l = mid + 1 + else: + r = mid - 1 + return r +``` + + + + + +另外,这道题还有一种更快的算法——`牛顿迭代法`,其公式为 $t_{n+1} = t_n - \frac{f(t_n)}{f'(t_n)} +$。给定$f (t) =t2 − x =0$,这里的迭代公式为 $t_{n+1} = \frac{t_n + \frac{x}{t_n}}{2}$。 + + + + +```cpp +int mySqrt(int x) { + long t = x; + while (t * t > x) { + t = (t + x / t) / 2; + } + return t; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + t = x + while t**2 > x: + t = (t + x // t) // 2 + return t +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/3-binary-search-techniques/3-3-interval-search.mdx b/leetcode_101/docs/3-binary-search-techniques/3-3-interval-search.mdx new file mode 100644 index 00000000..e1a28794 --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-3-interval-search.mdx @@ -0,0 +1,107 @@ +--- +sidebar_position: 13 +--- + +# 3.3 查找区间 + +## [34. Find First and Last Position of Element in Sorted Array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/) + +### 题目描述 + +给定一个增序的整数数组和一个值,查找该值第一次和最后一次出现的位置。 + +### 输入输出样例 + +输入是一个数组和一个值,输出为该值第一次出现的位置和最后一次出现的位置(从 0 开始);如果不存在该值,则两个返回值都设为-1。 + +``` +Input: nums = [5,7,7,8,8,10], target = 8 +Output: [3,4] +``` + +数字 8 在第 3 位第一次出现,在第 4 位最后一次出现。 + +### 题解 + +这道题可以看作是自己实现 C++ 里的 lower_bound和 upper_bound函数,或者 Python 里的 bisect_left 和 bisect_right 函数。这里我们尝试使用左闭右开的写法,当然左闭右闭也可以。 + + + + +```cpp +int lowerBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] < target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +int upperBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +vector searchRange(vector &nums, int target) { + if (nums.empty()) { + return vector{-1, -1}; + } + int lower = lowerBound(nums, target); + int upper = upperBound(nums, target) - 1; + if (lower == nums.size() || nums[lower] != target) { + return vector{-1, -1}; + } + return vector{lower, upper}; +} +``` + + + + +```py +def lowerBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] < target: + l = mid + 1 + else: + r = mid + return l + +def upperBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] <= target: + l = mid + 1 + else: + r = mid + return l + +def searchRange(nums: List[int], target: int) -> List[int]: + if not nums: + return [-1, -1] + lower = lowerBound(nums, target) + upper = upperBound(nums, target) - 1 + if lower == len(nums) or nums[lower] != target: + return [-1, -1] + return [lower, upper] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/3-binary-search-techniques/3-4-peak-finding.mdx b/leetcode_101/docs/3-binary-search-techniques/3-4-peak-finding.mdx new file mode 100644 index 00000000..0baa1256 --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-4-peak-finding.mdx @@ -0,0 +1,85 @@ +--- +sidebar_position: 14 +--- + +# 3.4 查找峰值 + +## [162. Find Peak Element](https://leetcode.com/problems/find-peak-element/) + +### 题目描述 + +给定一个数组,定义峰值为比所有两边都大的数字,求峰值的位置。一个数组里可能存在多个峰值,返回任意一个即可。时间复杂度要求为 $O(\log n)$。 + +### 输入输出样例 + +输入是一个数组,输出为峰值的位置。 + +``` +Input: nums = [1,2,3,1] +Output: 2 +``` + +峰值 3 出现在位置 2。 + + +### 题解 + +要实现 $O(\log n)$ 时间复杂度,我们可以对数组进行二分查找。在确保两端不是峰值后,若当前中点不是峰值,那么其左右一侧一定有一个峰值。 + + + + +```cpp +int findPeakElement(vector& nums) { + int n = nums.size(); + if (n == 1) { + return 0; + } + if (nums[0] > nums[1]) { + return 0; + } + if (nums[n - 1] > nums[n - 2]) { + return n - 1; + } + int l = 1, r = n - 2, mid; + while (l <= r) { + mid = l + (r - l) / 2; + if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1]) { + return mid; + } else if (nums[mid] > nums[mid - 1]) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return -1; +} +``` + + + + +```py +def findPeakElement(self, nums: List[int]) -> int: + n = len(nums) + if n == 1: + return 0 + if nums[0] > nums[1]: + return 0 + if nums[n - 1] > nums[n - 2]: + return n - 1 + l, r = 1, n - 2 + while l <= r: + mid = (l + r) // 2 + if nums[mid] > nums[mid + 1] and nums[mid] > nums[mid - 1]: + return mid + elif nums[mid] > nums[mid - 1]: + l = mid + 1 + else: + r = mid - 1 + return -1 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/3-binary-search-techniques/3-5-rotated-array-search.mdx b/leetcode_101/docs/3-binary-search-techniques/3-5-rotated-array-search.mdx new file mode 100644 index 00000000..c7b7b413 --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-5-rotated-array-search.mdx @@ -0,0 +1,99 @@ +--- +sidebar_position: 15 +--- + +# 3.5 旋转数组查找数字 + +## [81. Search in Rotated Sorted Array II](https://leetcode.com/problems/search-in-rotated-sorted-array-ii/) + +### 题目描述 + +一个原本增序的数组被首尾相连后按某个位置断开(如 [1,2,2,3,4,5] → [2,3,4,5,1,2],在第一位和第二位断开),我们称其为旋转数组。给定一个值,判断这个值是否存在于这个旋转数组中。 + +### 输入输出样例 + +输入是一个数组和一个值,输出是一个布尔值,表示数组中是否存在该值。 + +``` +Input: nums = [2,5,6,0,0,1,2], target = 0 +Output: true +``` + +即使数组被旋转过,我们仍然可以利用这个数组的递增性,使用二分查找。对于当前的中点,如果它指向的值小于等于右端,那么说明右区间是排好序的;反之,那么说明左区间是排好序的。如果目标值位于排好序的区间内,我们可以对这个区间继续二分查找;反之,我们对于另一半区 +间继续二分查找。本题我们采用左闭右闭的写法。 + +### 题解 + + + + + + +```cpp +bool search(vector& nums, int target) { + int l = 0, r = nums.size() - 1; + while (l <= r) { + int mid = l + (r - l) / 2; + if (nums[mid] == target) { + return true; + } + if (nums[mid] == nums[l]) { + // 无法判断哪个区间是增序的,但l位置一定不是target。 + ++l; + } else if (nums[mid] == nums[r]) { + // 无法判断哪个区间是增序的,但r位置一定不是target。 + --r; + } else if (nums[mid] < nums[r]) { + // 右区间是增序的。 + if (target > nums[mid] && target <= nums[r]) { + l = mid + 1; + } else { + r = mid - 1; + } + } else { + // 左区间是增序的。 + if (target >= nums[l] && target < nums[mid]) { + r = mid - 1; + } else { + l = mid + 1; + } + } + } + return false; +} +``` + + + + +```py +def search(nums: List[int], target: int) -> bool: + l, r = 0, len(nums) - 1 + while l <= r: + mid = (l + r) // 2 + if nums[mid] == target: + return True + if nums[mid] == nums[l]: + # 无法判断哪个区间是增序的,但l位置一定不是target。 + l += 1 + elif nums[mid] == nums[r]: + # 无法判断哪个区间是增序的,但r位置一定不是target。 + r -= 1 + elif nums[mid] < nums[r]: + # 右区间是增序的。 + if nums[mid] < target <= nums[r]: + l = mid + 1 + else: + r = mid - 1 + else: + # 左区间是增序的。 + if nums[l] <= target < nums[mid]: + r = mid - 1 + else: + l = mid + 1 + return False +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/3-binary-search-techniques/3-6-exercises.md b/leetcode_101/docs/3-binary-search-techniques/3-6-exercises.md new file mode 100644 index 00000000..bba38092 --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/3-6-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 16 +--- + +# 3.6 练习 + +## 基础难度 + +### [154. Find Minimum in Rotated Sorted Array II](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/) + +旋转数组的变形题之一。 + +--- + +### [540. Single Element in a Sorted Array](https://leetcode.com/problems/single-element-in-a-sorted-array/) + +在出现独立数之前和之后,奇偶位数的值发生了什么变化? + +--- + +## 进阶难度 + +### [4. Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) + +需要对两个数组同时进行二分搜索。 \ No newline at end of file diff --git a/leetcode_101/docs/3-binary-search-techniques/_category_.json b/leetcode_101/docs/3-binary-search-techniques/_category_.json new file mode 100644 index 00000000..89e9fd2f --- /dev/null +++ b/leetcode_101/docs/3-binary-search-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "3. 居合斩!二分查找", + "position": 3, + "link": { + "type": "generated-index", + "description": "第 3 章 居合斩!二分查找" + } +} diff --git a/leetcode_101/docs/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx b/leetcode_101/docs/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx new file mode 100644 index 00000000..439287d5 --- /dev/null +++ b/leetcode_101/docs/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx @@ -0,0 +1,147 @@ +--- +sidebar_position: 17 +--- + +# 4.1 常用排序算法 + +虽然在 C++ 和 Python 里都可以通过 sort 函数排序,而且刷题时很少需要自己手写排序算法,但是熟习各种排序算法可以加深自己对算法的基本理解,以及解出由这些排序算法引申出来的题目。这里我们展示两种复杂度为 $O(n \log n)$ 的排序算法:`快速排序`和`归并排序`,其中前者实际速度较快,后者可以保证相同值的元素在数组中的相对位置不变(即“稳定排序”)。 + +## 快速排序(Quicksort) + +快速排序的原理并不复杂:对于当前一个未排序片段,我们先随机选择一个位置当作中枢点,然后通过遍历操作,将所有比中枢点小的数字移动到其左侧,再将所有比中枢点大的数字移动到其右侧。操作完成后,我们再次对中枢点左右侧的片段再次进行快速排序即可。可证明,如果中枢点选取是随机的,那么该算法的平均复杂度可以达到 $O(n \log n)$,最差情况下复杂度则为 $O(n^2)$。 + +我们采用左闭右闭的二分写法,初始化条件为 $l =0,r =n − 1$。 + + + + +```cpp +void quickSort(vector &nums, int l, int r) { + if (l >= r) { + return; + } + // 在当前的[l, r]区间中,随机选择一个位置当作pivot。 + int pivot = l + (rand() % (r - l + 1)); + int pivot_val = nums[pivot]; + // 将pivot与l交换。 + swap(nums[l], nums[pivot]); + // 从[l+1, r]两端向内遍历,查找是否有位置不满足递增关系。 + int i = l + 1, j = r; + while (true) { + while (i < j && nums[j] >= pivot_val) { + --j; + } + while (i < j && nums[i] <= pivot_val) { + ++i; + } + if (i == j) { + break; + } + // i位置的值大于pivot值,j位置的值小于pivot值,将二者交换。 + swap(nums[i], nums[j]); + } + // i和j相遇的位置即为新的pivot,我们将pivot与l重新换回来。 + // 此时相遇位置左侧一定比pivot值小,右侧一定比pivot值大。 + int new_pivot = nums[i] <= nums[l] ? i : i - 1; + swap(nums[l], nums[new_pivot]); + quickSort(nums, l, new_pivot - 1); + quickSort(nums, new_pivot + 1, r); +} +``` + + + + +```py +def quickSort(nums: List[int], l: int, r: int) -> bool: + if l >= r: + return + # 在当前的[l, r]区间中,随机选择一个位置当作pivot。 + pivot = random.randint(l, r) + pivot_val = nums[pivot] + # 将pivot与l交换。 + nums[l], nums[pivot] = nums[pivot], nums[l] + # 从[l+1, r]两端向内遍历,查找是否有位置不满足递增关系。 + i, j = l + 1, r + while True: + while i < j and nums[j] >= pivot_val: + j -= 1 + while i < j and nums[i] <= pivot_val: + i += 1 + if i == j: + break + # i位置的值大于pivot值,j位置的值小于pivot值,将二者交换。 + nums[i], nums[j] = nums[j], nums[i] + # i和j相遇的位置即为新的pivot,我们将pivot与l重新换回来。 + # 此时相遇位置左侧一定比pivot值小,右侧一定比pivot值大。 + new_pivot = i if nums[i] <= nums[l] else i - 1 + nums[l], nums[new_pivot] = nums[new_pivot], nums[l] + quickSort(nums, l, new_pivot - 1) + quickSort(nums, new_pivot + 1, r) +``` + + + + + +## 归并排序(Merge Sort) + +归并排序是典型的分治法,我们在之后的章节会展开讲解。简单来讲,对于一个未排序片段,我们可以先分别排序其左半侧和右半侧,然后将两侧重新组合(“治”);排序每个半侧时可以通过递归再次把它切分成两侧(“分”)。 + +我们采用左闭右闭的二分写法,初始化条件为 $l =0,r = n − 1$,另外提前建立一个和 nums 大小相同的数组 cache,用来存储临时结果。 + + + + +```cpp +void mergeSort(vector &nums, vector &cache, int l, int r) { + if (l >= r) { + return; + } + // 分。 + int mid = l + (r - l) / 2; + mergeSort(nums, cache, l, mid); + mergeSort(nums, cache, mid + 1, r); + // 治。 + // i和j同时向右前进,i的范围是[l, mid],j的范围是[mid+1, r]。 + int i = l, j = mid + 1; + for (int pos = l; pos <= r; ++pos) { + if (j > r || (i <= mid && nums[i] <= nums[j])) { + cache[pos] = nums[i++]; + } else { + cache[pos] = nums[j++]; + } + } + for (int pos = l; pos <= r; ++pos) { + nums[pos] = cache[pos]; + } +} +``` + + + + +```py +def mergeSort(nums: List[int], cache: List[int], l: int, r: int) -> bool: + if l >= r: + return + # 分。 + mid = (l + r) // 2 + mergeSort(nums, cache, l, mid) + mergeSort(nums, cache, mid + 1, r) + # 治。 + # i和j同时向右前进,i的范围是[l, mid],j的范围是[mid+1, r]。 + i, j = l, mid + 1 + for pos in range(l, r + 1): + if j > r or (i <= mid and nums[i] <= nums[j]): + cache[pos] = nums[i] + i += 1 + else: + cache[pos] = nums[j] + j += 1 + nums[l:r+1] = cache[l:r+1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/4-sorting-algorithms/4-2-quick-select.mdx b/leetcode_101/docs/4-sorting-algorithms/4-2-quick-select.mdx new file mode 100644 index 00000000..f6927984 --- /dev/null +++ b/leetcode_101/docs/4-sorting-algorithms/4-2-quick-select.mdx @@ -0,0 +1,80 @@ +--- +sidebar_position: 18 +--- + +# 4.2 快速选择 + +## [215. Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) + +### 题目描述 + +在一个未排序的数组中,找到第 $k$ 大的数字。 + +### 输入输出样例 + +输入一个数组和一个目标值 $k$,输出第 $k$ 大的数字。题目默认一定有解。 + +``` +Input: [3,2,1,5,6,4] and k = 2 +Output: 5 +``` + + + +### 题解 + +`快速选择`一般用于求解 k-th Element 问题,可以在平均 $O(n)$ 时间复杂度,$O(1)$ 空间复杂度完成求解工作。快速选择的实现和快速排序相似,不过只需要找到第 $k$ 大的枢(pivot)即可,不需要对其左右再进行排序。与快速排序一样,快速选择一般需要先打乱数组,否则最坏情况下时间复杂度为 $O(n^2)$。 + +这道题如果直接用上面的快速排序原代码运行,会导致在 LeetCode 上接近超时。我们可以用空间换取时间,直接存储比中枢点小和大的值,尽量避免进行交换位置的操作。 + + + + +```cpp +int findKthLargest(vector nums, int k) { + int pivot = rand() % nums.size(); + int pivot_val = nums[pivot]; + vector larger, equal, smaller; + for (int num : nums) { + if (num > pivot_val) { + larger.push_back(num); + } else if (num < pivot_val) { + smaller.push_back(num); + } else { + equal.push_back(num); + } + } + if (k <= larger.size()) { + return findKthLargest(larger, k); + } + if (k > larger.size() + equal.size()) { + return findKthLargest(smaller, k - larger.size() - equal.size()); + } + return pivot_val; +} +``` + + + + +```py +def findKthLargest(nums: List[int], k: int) -> int: + pivot_val = random.choice(nums) + larger, equal, smaller = [], [], [] + for num in nums: + if num > pivot_val: + larger.append(num) + elif num < pivot_val: + smaller.append(num) + else: + equal.append(num) + if k <= len(larger): + return findKthLargest(larger, k) + if k > len(larger) + len(equal): + return findKthLargest(smaller, k - len(larger) - len(equal)) + return pivot_val +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/4-sorting-algorithms/4-3-bucket-sort.mdx b/leetcode_101/docs/4-sorting-algorithms/4-3-bucket-sort.mdx new file mode 100644 index 00000000..180d2d6f --- /dev/null +++ b/leetcode_101/docs/4-sorting-algorithms/4-3-bucket-sort.mdx @@ -0,0 +1,84 @@ +--- +sidebar_position: 19 +--- + +# 4.3 桶排序 + +## [347. Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) + +### 题目描述 + +给定一个数组,求前 $k$ 个最频繁的数字。 + +### 输入输出样例 + +输入是一个数组和一个目标值 $k$。输出是一个长度为 $k$ 的数组。 + +``` +Input: nums = [1,1,1,1,2,2,3,4], k = 2 +Output: [1,2] +``` + +在这个样例中,最频繁的两个数是 1 和 2。 + +### 题解 + +顾名思义,`桶排序`的意思是为每个值设立一个桶,桶内记录这个值出现的次数(或其它属性),然后对桶进行排序。针对样例来说,我们先通过桶排序得到四个桶 [1,2,3,4],它们的值分别 +为 [4,2,1,1],表示每个数字出现的次数。 + +紧接着,我们对桶的频次进行排序,前 $k$ 大个桶即是前 $k$ 个频繁的数。这里我们可以使用各种排序算法,甚至可以再进行一次桶排序,把每个旧桶根据频次放在不同的新桶内。针对样例来说,因为目前最大的频次是 4,我们建立 [1,2,3,4] 四个新桶,它们分别放入的旧桶为 [[3,4],[2],[],[1]],表示不同数字出现的频率。最后,我们从后往前遍历,直到找到 k 个旧桶。 + +我们可以使用 C++ 中的 unordered_map 或 Python 中的 dict 实现哈希表。 + + + + +```cpp +vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (int num : nums) { + ++counts[num]; + } + unordered_map> buckets; + for (auto [num, count] : counts) { + buckets[count].push_back(num); + } + vector top_k; + for (int count = nums.size(); count >= 0; --count) { + if (buckets.contains(count)) { + for (int num : buckets[count]) { + top_k.push_back(num); + if (top_k.size() == k) { + return top_k; + } + } + } + } + return top_k; +} +``` + + + + +```py +def topKFrequent(nums: List[int], k: int) -> List[int]: + counts = Counter(nums) + buckets = dict() + for num, count in counts.items(): + if count in buckets: + buckets[count].append(num) + else: + buckets[count] = [num] + top_k = [] + for count in range(len(nums), 0, -1): + if count in buckets: + top_k += buckets[count] + if len(top_k) >= k: + return top_k[:k] + return top_k[:k] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/4-sorting-algorithms/4-4-exercises.md b/leetcode_101/docs/4-sorting-algorithms/4-4-exercises.md new file mode 100644 index 00000000..321e6463 --- /dev/null +++ b/leetcode_101/docs/4-sorting-algorithms/4-4-exercises.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 20 +--- + +# 4.4 练习 + +## 基础难度 + +### [451. Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) + +桶排序的变形题。 + +--- + +## 进阶难度 + +### [75. Sort Colors](https://leetcode.com/problems/sort-colors/) + +很经典的荷兰国旗问题,考察如何对三个重复且打乱的值进行排序。 \ No newline at end of file diff --git a/leetcode_101/docs/4-sorting-algorithms/_category_.json b/leetcode_101/docs/4-sorting-algorithms/_category_.json new file mode 100644 index 00000000..4aad536a --- /dev/null +++ b/leetcode_101/docs/4-sorting-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "4. 千奇百怪的排序算法", + "position": 4, + "link": { + "type": "generated-index", + "description": "第 4 章 千奇百怪的排序算法" + } +} diff --git a/leetcode_101/docs/5-searching-algorithms/5-1-algorithm-explanation.md b/leetcode_101/docs/5-searching-algorithms/5-1-algorithm-explanation.md new file mode 100644 index 00000000..1841acf6 --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/5-1-algorithm-explanation.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 21 +--- + +# 5.1 算法解释 + +`深度优先搜索`和`广度优先搜索`是两种最常见的优先搜索方法,它们被广泛地运用在图和树等结构中进行搜索。 \ No newline at end of file diff --git a/leetcode_101/docs/5-searching-algorithms/5-2-depth-first-search.mdx b/leetcode_101/docs/5-searching-algorithms/5-2-depth-first-search.mdx new file mode 100644 index 00000000..2027b337 --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/5-2-depth-first-search.mdx @@ -0,0 +1,372 @@ +--- +sidebar_position: 22 +--- + +# 5.2 深度优先搜索 + +`深度优先搜索`(depth-first search,DFS)在搜索到一个新的节点时,立即对该新节点进行遍历;因此遍历需要用`先入后出的栈(stack)`来实现,也可以通过与栈等价的`递归`来实现。对于树结构而言,由于总是对新节点调用遍历,因此看起来是向着“深”的方向前进。在 Python 中,我们可以用 collections.deque 来实现 C++ 中的 stack。但是通常情况下,我们还是会选用 C++ 中的 vector 或 Python 中的 list 来实现栈,因为它们既是先入后出的数据结构,又能支持随机查找。 + +考虑如下一颗简单的树,我们从 1 号节点开始遍历。假如遍历顺序是从左子节点到右子节点,那么按照优先向着“深”的方向前进的策略,则遍历过程为 1(起始节点)->2(遍历更深一层的左子节点)->4(遍历更深一层的左子节点)->2(无子节点,返回父结点)->1(子节点均已完成遍历,返回父结点)->3(遍历更深一层的右子节点)->1(无子节点,返回父结点)-> 结束程序(子节点均已完成遍历)。如果我们使用栈实现,我们的栈顶元素的变化过程为 1->2->4->3。 + +``` + 1 + / \ + 2 3 + / +4 +``` + +深度优先搜索也可以用来`检测环路`:记录每个遍历过的节点的父节点,若一个节点被再次遍历且父节点不同,则说明有环。我们也可以用之后会讲到的拓扑排序判断是否有环路,若最后存在入度不为零的点,则说明有环。 + +有时我们可能会需要对已经搜索过的节点进行标记,以防止在遍历时重复搜索某个节点,这种做法叫做`状态记录`或`记忆化`(memoization)。 + +## [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/) + +### 题目描述 + +给定一个二维的 0-1 矩阵,其中 0 表示海洋,1 表示陆地。单独的或相邻的陆地可以形成岛屿,每个格子只与其上下左右四个格子相邻。求最大的岛屿面积。 + +### 输入输出样例 + +输入是一个二维数组,输出是一个整数,表示最大的岛屿面积。 + +``` +Input: +[[1,0,1,1,0,1,0,1], + [1,0,1,1,0,1,1,1], + [0,0,0,0,0,0,0,1]] +Output: 6 +``` + +最大的岛屿面积为 6,位于最右侧。 + +### 题解 + +此题是十分标准的搜索题,我们可以拿来练手深度优先搜索。一般来说,深度优先搜索类型的题可以分为主函数和辅函数,主函数用于遍历所有的搜索位置,判断是否可以开始搜索,如果可以即在辅函数进行搜索。辅函数则负责深度优先搜索的递归调用。当然,我们也可以使用栈(stack)实现深度优先搜索,但因为栈与递归的调用原理相同,而递归相对便于实现,因此刷题时笔者推荐使用递归式写法,同时也方便进行回溯(见下节)。不过在实际工程上,直接使用栈可能才是最好的选择,一是因为便于理解,二是更不易出现递归栈满的情况。 + +我们先展示使用栈的写法。这里我们使用了一个小技巧,对于四个方向的遍历,可以创造一个数组 [-1, 0, 1, 0, -1],每相邻两位即为上下左右四个方向之一。当然您也可以显式写成 [-1, 0]、[1, 0]、[0, 1] 和 [0, -1],以便理解。 + + + + +```cpp +int maxAreaOfIsland(vector>& grid) { + vector direction{-1, 0, 1, 0, -1}; + int m = grid.size(), n = grid[0].size(), max_area = 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + stack> island; + // 初始化第第一个节点。 + int local_area = 1; + grid[i][j] = 0; + island.push({i, j}); + // DFS. + while (!island.empty()) { + auto [r, c] = island.top(); + island.pop(); + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + // 放入满足条件的相邻节点。 + if (x >= 0 && x < m && y >= 0 && y < n && + grid[x][y] == 1) { + ++local_area; + grid[x][y] = 0; + island.push({x, y}); + } + } + } + max_area = max(max_area, local_area); + } + } + } + return max_area; +} +``` + + + + +```py +def maxAreaOfIsland(grid: List[List[int]]) -> int: + direction = [-1, 0, 1, 0, -1] + m, n, max_area = len(grid), len(grid[0]), 0 + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + island = [] + # 初始化第第一个节点。 + local_area = 1 + grid[i][j] = 0 + island.append((i, j)) + # DFS. + while len(island) > 0: + r, c = island.pop() + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + # 放入满足条件的相邻节点。 + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: + local_area += 1 + grid[x][y] = 0 + island.append((x, y)) + max_area = max(max_area, local_area) + return max_area +``` + + + + + +下面我们展示递归写法,注意进行递归搜索时,一定要检查边界条件。可以在每次调用辅函数之前检查,也可以在辅函数的一开始进行检查。这里我们没有利用 [-1, 0, 1, 0, -1] 数组进行上下左右四个方向的搜索,而是直接显式地写出来四种不同的递归函数。两种写法都可以,读者可以掌握任意一种。 + + + + +```cpp +// 辅函数。 +int dfs(vector>& grid, int r, int c) { + if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size() || + grid[r][c] == 0) { + return 0; + } + grid[r][c] = 0; + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)); +} + +// 主函数。 +int maxAreaOfIsland(vector>& grid) { + int max_area = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + max_area = max(max_area, dfs(grid, i, j)); + } + } + return max_area; +} +``` + + + + +```py +# 辅函数。 +def dfs(grid: List[List[int]], r: int, c: int) -> int: + if r < 0 or r >= len(grid) or c < 0 or c >= len(grid[0]) or grid[r][c] == 0: + return 0 + grid[r][c] = 0 + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)) + +# 主函数。 +def maxAreaOfIsland(grid: List[List[int]]) -> int: + max_area = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + max_area = max(max_area, dfs(grid, i, j)) + return max_area +``` + + + + + +## [547. Number of Provinces](https://leetcode.com/problems/number-of-provinces/) + +### 题目描述 + +给定一个二维的 0-1 矩阵,如果第 (i, j) 位置是 1,则表示第 i 个城市和第 j 个城市处于同一城市圈。已知城市的相邻关系是可以传递的,即如果 a 和 b 相邻,b 和 c 相邻,那么 a 和 c 也相邻,换言之这三个城市处于同一个城市圈之内。求一共有多少个城市圈。 + +### 输入输出样例 + +输入是一个二维数组,输出是一个整数,表示城市圈数量。因为城市相邻关系具有对称性,该二维数组为对称矩阵。同时,因为自己也处于自己的城市圈,对角线上的值全部为 1。 + +``` +Input: +[[1,1,0], + [1,1,0], + [0,0,1]] +Output: 2 +``` + +在这个样例中,[1,2] 处于一个城市圈,[3] 处于一个城市圈。 + +### 题解 + +在上一道题目中,图的表示方法是,每个位置代表一个节点,每个节点与上下左右四个节点相邻。而在这一道题里面,每一行(列)表示一个节点,它的每列(行)表示是否存在一个相邻节点。上一道题目拥有 m × n 个节点,每个节点有 4 条边;而本题拥有 n 个节点,每个节点最多有 n 条边,表示和所有城市都相邻,最少可以有 1 条边,表示当前城市圈只有自己。当清楚了图的表示方法后,这道题目与上一道题目本质上是同一道题:搜索城市圈(岛屿圈)的个数。我们这里采用递归的写法。 + +:::warning + +对于节点连接类问题,我们也可以利用并查集来进行快速的连接和搜索。我们将会在之后的章节讲解。 + +::: + + + + +```cpp +// 辅函数。 +void dfs(vector>& isConnected, int i, vector& visited) { + visited[i] = true; + for (int j = 0; j < isConnected.size(); ++j) { + if (isConnected[i][j] == 1 && !visited[j]) { + dfs(isConnected, j, visited); + } + } +} + +// 主函数。 +int findCircleNum(vector>& isConnected) { + int n = isConnected.size(), count = 0; + // 防止重复搜索已被搜索过的节点。 + vector visited(n, false); + for (int i = 0; i < n; ++i) { + if (!visited[i]) { + dfs(isConnected, i, visited); + ++count; + } + } + return count; +} +``` + + + + +```py +# 辅函数。 +def dfs(isConnected: List[List[int]], city: int, visited: Set[int]): + visited.add(city) + for i in range(len(isConnected)): + if isConnected[city][i] == 1 and i not in visited: + dfs(isConnected, i, visited) + +# 主函数。 +def findCircleNum(isConnected: List[List[int]]) -> int: + count = 0 + # 防止重复搜索已被搜索过的节点。 + visited = set() + for i in range(len(isConnected)): + if i not in visited: + dfs(isConnected, i, visited) + count += 1 + return count +``` + + + + + + +## [417. Pacific Atlantic Water Flow](https://leetcode.com/problems/pacific-atlantic-water-flow/) + +### 题目描述 + +给定一个二维的非负整数矩阵,每个位置的值表示海拔高度。假设左边和上边是太平洋,右边和下边是大西洋,求从哪些位置向下流水,可以流到太平洋和大西洋。水只能从海拔高的位置流到海拔低或相同的位置。 + +### 输入输出样例 + +输入是一个二维的非负整数数组,表示海拔高度。输出是一个二维的数组,其中第二个维度大小固定为 2,表示满足条件的位置坐标。 + + +``` +Input: + 太平洋 ~ ~ ~ ~ ~ + ~ 1 2 2 3 (5) * + ~ 3 2 3 (4) (4) * + ~ 2 4 (5) 3 1 * + ~ (6) (7) 1 4 5 * + ~ (5) 1 1 2 4 * + * * * * * 大西洋 +Output: [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] +``` + +在这个样例中,有括号的区域为满足条件的位置。 + +### 题解 + +虽然题目要求的是满足向下流能到达两个大洋的位置,如果我们对所有的位置进行搜索,那么在不剪枝的情况下复杂度会很高。因此我们可以反过来想,从两个大洋开始向上流,这样我们只需要对矩形四条边进行搜索。搜索完成后,只需遍历一遍矩阵,两个大洋向上流都能到达的位置即为满足条件的位置。 + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// 辅函数。 +void dfs(const vector>& heights, vector>& can_reach, + int r, int c) { + if (can_reach[r][c]) { + return; + } + can_reach[r][c] = true; + for (int i = 0; i < 4; ++i) { + int x = r + direction[i], y = c + direction[i + 1]; + if (x >= 0 && x < heights.size() && y >= 0 && y < heights[0].size() && + heights[r][c] <= heights[x][y]) { + dfs(heights, can_reach, x, y); + } + } +} + +// 主函数。 +vector> pacificAtlantic(vector>& heights) { + int m = heights.size(), n = heights[0].size(); + vector> can_reach_p(m, vector(n, false)); + vector> can_reach_a(m, vector(n, false)); + vector> can_reach_p_and_a; + for (int i = 0; i < m; ++i) { + dfs(heights, can_reach_p, i, 0); + dfs(heights, can_reach_a, i, n - 1); + } + for (int i = 0; i < n; ++i) { + dfs(heights, can_reach_p, 0, i); + dfs(heights, can_reach_a, m - 1, i); + } + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (can_reach_p[i][j] && can_reach_a[i][j]) { + can_reach_p_and_a.push_back({i, j}); + } + } + } + return can_reach_p_and_a; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# 辅函数。 +def dfs(heights: List[List[int]], can_reach: List[List[int]], r: int, c: int): + if can_reach[r][c]: + return + can_reach[r][c] = True + for i in range(4): + x, y = r + direction[i], c + direction[i + 1] + if (x >= 0 and x < len(heights) and y >= 0 and y < len(heights[0]) and + heights[x][y] >= heights[r][c]): + dfs(heights, can_reach, x, y) + +# 主函数。 +def pacificAtlantic(heights: List[List[int]]) -> List[List[int]]: + m, n = len(heights), len(heights[0]) + can_reach_p = [[False for _ in range(n)] for _ in range(m)] + can_reach_a = [[False for _ in range(n)] for _ in range(m)] + for i in range(m): + dfs(heights, can_reach_p, i, 0) + dfs(heights, can_reach_a, i, n - 1) + for j in range(n): + dfs(heights, can_reach_p, 0, j) + dfs(heights, can_reach_a, m - 1, j) + return [ + [i, j] for i in range(m) for j in range(n) + if can_reach_p[i][j] and can_reach_a[i][j] + ] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/5-searching-algorithms/5-3-backtracking.mdx b/leetcode_101/docs/5-searching-algorithms/5-3-backtracking.mdx new file mode 100644 index 00000000..8711e78a --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/5-3-backtracking.mdx @@ -0,0 +1,375 @@ +--- +sidebar_position: 23 +--- + +# 5.3 回溯法 + +`回溯法`(backtracking)是优先搜索的一种特殊情况,又称为试探法,常用于需要记录节点状态的深度优先搜索。通常来说,排列、组合、选择类问题使用回溯法比较方便。 + +顾名思义,回溯法的核心是回溯。在搜索到某一节点的时候,如果我们发现目前的节点(及其子节点)并不是需求目标时,我们回退到原来的节点继续搜索,并且`把在目前节点修改的状态还原`。这样的好处是我们可以始终只对图的总状态进行修改,而非每次遍历时新建一个图来储存状态。在具体的写法上,它与普通的深度优先搜索一样,都有 [修改当前节点状态]→[递归子节点] 的步骤,只是多了回溯的步骤,变成了 [修改当前节点状态]→[递归子节点]→[回改当前节点状态]。 + +没有接触过回溯法的读者可能会不明白我在讲什么,这也完全正常,希望以下几道题可以让您理解回溯法。如果还是不明白,可以记住两个小诀窍,`一是按引用传状态,二是所有的状态修改在递归完成后回改`。 + +回溯法修改一般有两种情况,一种是修改最后一位输出,比如排列组合;一种是修改访问标记,比如矩阵里搜字符串。 + +## [46. Permutations](https://leetcode.com/problems/permutations/) + +### 题目描述 + +给定一个无重复数字的整数数组,求其所有的排列方式。 + +### 输入输出样例 + +输入是一个一维整数数组,输出是一个二维数组,表示输入数组的所有排列方式。 + +``` +Input: [1,2,3] +Output: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]] +``` + +可以以任意顺序输出,只要包含了所有排列方式即可。 + +### 题解 + +怎样输出所有的排列方式呢?对于每一个当前位置 i,我们可以将其于之后的任意位置交换,然后继续处理位置 i+1,直到处理到最后一位。为了防止我们每此遍历时都要新建一个子数组储存位置 i 之前已经交换好的数字,我们可以利用回溯法,只对原数组进行修改,在递归完成后再修改回来。 + +我们以样例 [1,2,3] 为例,按照这种方法,我们输出的数组顺序为 [[1,2,3], [1,3,2], [2,1,3], [2,3,1],[3,2,1], [3,1,2]],可以看到所有的排列在这个算法中都被考虑到了。 + + + + +```cpp +// 辅函数。 +void backtracking(vector &nums, int level, + vector> &permutations) { + if (level == nums.size() - 1) { + permutations.push_back(nums); + return; + } + for (int i = level; i < nums.size(); ++i) { + swap(nums[i], nums[level]); // 修改当前节点状态 + backtracking(nums, level + 1, permutations); // 递归子节点 + swap(nums[i], nums[level]); // 回改当前节点状态 + } +} +// 主函数。 +vector> permute(vector &nums) { + vector> permutations; + backtracking(nums, 0, permutations); + return permutations; +} +``` + + + + +```py +# 辅函数。 +def backtracking(nums: List[int], level: int, permutations: List[List[int]]): + if level == len(nums) - 1: + permutations.append(nums[:]) # int为基本类型,可以浅拷贝 + return + for i in range(level, len(nums)): + nums[i], nums[level] = nums[level], nums[i] # 修改当前节点状态 + backtracking(nums, level + 1, permutations) # 递归子节点 + nums[i], nums[level] = nums[level], nums[i] # 回改当前节点状态 + +# 主函数。 +def permute(nums: List[int]) -> List[List[int]]: + permutations = [] + backtracking(nums, 0, permutations) + return permutations +``` + + + + + +## [77. Combinations](https://leetcode.com/problems/combinations/) + +### 题目描述 + +给定一个整数 n 和一个整数 k,求在 1 到 n 中选取 k 个数字的所有组合方法。 + +### 输入输出样例 + +输入是两个正整数 n 和 k,输出是一个二维数组,表示所有组合方式。 + +``` +Input: n = 4, k = 2 +Output: [[2,4], [3,4], [2,3], [1,2], [1,3], [1,4]] +``` + +这里二维数组的每个维度都可以以任意顺序输出。 + +### 题解 + +类似于排列问题,我们也可以进行回溯。排列回溯的是交换的位置,而组合回溯的是是否把当前的数字加入结果中。 + + + + +```cpp +// 辅函数。 +void backtracking(vector>& combinations, vector& pick, int pos, + int n, int k) { + if (pick.size() == k) { + combinations.push_back(pick); + return; + } + for (int i = pos; i <= n; ++i) { + pick.push_back(i); // 修改当前节点状态 + backtracking(combinations, pick, i + 1, n, k); // 递归子节点 + pick.pop_back(); // 回改当前节点状态 + } +} + +// 主函数。 +vector> combine(int n, int k) { + vector> combinations; + vector pick; + backtracking(combinations, pick, 1, n, k); + return combinations; +} +``` + + + + +```py +# 辅函数。 +def backtracking( + combinations: List[List[int]], pick: List[int], pos: int, n: int, k: int +): + if len(pick) == k: + combinations.append(pick[:]) # int为基本类型,可以浅拷贝 + return + for i in range(pos, n + 1): + pick.append(i) # 修改当前节点状态 + backtracking(combinations, pick, i + 1, n, k) # 递归子节点 + pick.pop() # 回改当前节点状态 + +# 主函数。 +def combine(n: int, k: int) -> List[List[int]]: + combinations = [] + pick = [] + backtracking(combinations, pick, 1, n, k) + return combinations +``` + + + + + +## [79. Word Search](https://leetcode.com/problems/word-search/) + +### 题目描述 + +给定一个字母矩阵,所有的字母都与上下左右四个方向上的字母相连。给定一个字符串,求字符串能不能在字母矩阵中寻找到。 + +### 输入输出样例 + +输入是一个二维字符数组和一个字符串,输出是一个布尔值,表示字符串是否可以被寻找到。 + +``` +Input: word = "ABCCED", board = +[[’A’,’B’,’C’,’E’], + [’S’,’F’,’C’,’S’], + [’A’,’D’,’E’,’E’]] +Output: true +``` + +从左上角的’A’ 开始,我们可以先向右、再向下、最后向左,找到连续的"ABCCED"。 + +### 题解 + +不同于排列组合问题,本题采用的并不是修改输出方式,而是修改访问标记。在我们对任意位置进行深度优先搜索时,我们先标记当前位置为已访问,以避免重复遍历(如防止向右搜索后又向左返回);在所有的可能都搜索完成后,再回改当前位置为未访问,防止干扰其它位置搜索到当前位置。使用回溯法时,我们可以只对一个二维的访问矩阵进行修改,而不用把每次的搜索状态作为一个新对象传入递归函数中。 + + + + + +```cpp +// 辅函数。 +bool backtracking(vector>& board, string& word, + vector>& visited, int i, int j, int word_pos) { + if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || + visited[i][j] || board[i][j] != word[word_pos]) { + return false; + } + if (word_pos == word.size() - 1) { + return true; + } + visited[i][j] = true; // 修改当前节点状态 + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) || + backtracking(board, word, visited, i - 1, j, word_pos + 1) || + backtracking(board, word, visited, i, j + 1, word_pos + 1) || + backtracking(board, word, visited, i, j - 1, word_pos + 1)) { + return true; // 递归子节点 + } + visited[i][j] = false; // 回改当前节点状态 + return false; +} + +// 主函数。 +bool exist(vector>& board, string word) { + int m = board.size(), n = board[0].size(); + vector> visited(m, vector(n, false)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (backtracking(board, word, visited, i, j, 0)) { + return true; + } + } + } + return false; +} +``` + + + + +```py +# 辅函数。 +def backtracking(board: List[List[str]], word: str, + visited: List[List[bool]], i: int, j: int, word_pos: int): + if (i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) + or visited[i][j] or board[i][j] != word[word_pos]): + return False + if word_pos == len(word) - 1: + return True + visited[i][j] = True # 修改当前节点状态 + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) or + backtracking(board, word, visited, i - 1, j, word_pos + 1) or + backtracking(board, word, visited, i, j + 1, word_pos + 1) or + backtracking(board, word, visited, i, j - 1, word_pos + 1)): + return True # 递归子节点 + visited[i][j] = False # 回改当前节点状态 + return False + +# 主函数。 +def exist(board: List[List[str]], word: str) -> bool: + m, n = len(board), len(board[0]) + visited = [[False for _ in range(n)] for _ in range(m)] + return any([ + backtracking(board, word, visited, i, j, 0) + for i in range(m) for j in range(n) + ]) +``` + + + + + +## [51. N-Queens](https://leetcode.com/problems/n-queens/) + +### 题目描述 + +给定一个大小为 n 的正方形国际象棋棋盘,求有多少种方式可以放置 n 个皇后并使得她们互不攻击,即每一行、列、左斜、右斜最多只有一个皇后。 + +
+![](n-queens.png) +
题目 51 - 八皇后的一种解法
+
+ +### 输入输出样例 + +输入是一个整数 n,输出是一个二维字符串数组,表示所有的棋盘表示方法。 + +``` +Input: 4 +Output: [ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] +``` + +在这个样例中,点代表空白位置,Q 代表皇后。 + +### 题解 + +类似于在矩阵中寻找字符串,本题也是通过修改状态矩阵来进行回溯。不同的是,我们需要对每一行、列、左斜、右斜建立访问数组,来记录它们是否存在皇后。这里如果我们通过对每一行/列遍历来插入皇后,我们就不需要对行/列建立访问数组了。 + + + + +```cpp +// 辅函数。 +void backtracking(vector> &solutions, vector &board, + vector &column, vector &ldiag, + vector &rdiag, int row) { + int n = board.size(); + if (row == n) { + solutions.push_back(board); + return; + } + for (int i = 0; i < n; ++i) { + if (column[i] || ldiag[n - row + i - 1] || rdiag[row + i]) { + continue; + } + // 修改当前节点状态。 + board[row][i] = ’Q’; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = true; + // 递归子节点。 + backtracking(solutions, board, column, ldiag, rdiag, row + 1); + // 回改当前节点状态。 + board[row][i] = ’.’; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = false; + } +} + +// 主函数。 +vector> solveNQueens(int n) { + vector> solutions; + vector board(n, string(n, ’.’)); + vector column(n, false); + vector ldiag(2 * n - 1, false); + vector rdiag(2 * n - 1, false); + backtracking(solutions, board, column, ldiag, rdiag, 0); + return solutions; +} +``` + + + + +```py +# 辅函数。 +def backtracking(solutions: List[List[str]], board: List[List[str]], + column: List[bool], ldiag: List[bool], rdiag: List[bool], row: int): + n = len(board) + if row == n: + solutions.append(["".join(row) for row in board]) + return + for i in range(n): + if column[i] or ldiag[n - row + i - 1] or rdiag[row + i]: + continue + # 修改当前节点状态。 + board[row][i] = "Q" + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = True + # 递归子节点。 + backtracking(solutions, board, column, ldiag, rdiag, row + 1) + # 回改当前节点状态。 + board[row][i] = "." + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = False + +# 主函数。 +def solveNQueens(n: int) -> List[List[str]]: + solutions = [] + board = [["." for _ in range(n)] for _ in range(n)] + column = [False] * n + ldiag = [False] * (2 * n - 1) + rdiag = [False] * (2 * n - 1) + backtracking(solutions, board, column, ldiag, rdiag, 0) + return solutions +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/5-searching-algorithms/5-4-breadth-first-search.mdx b/leetcode_101/docs/5-searching-algorithms/5-4-breadth-first-search.mdx new file mode 100644 index 00000000..f4afb9ec --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/5-4-breadth-first-search.mdx @@ -0,0 +1,454 @@ +--- +sidebar_position: 24 +--- + +# 5.4 广度优先搜索 + +`广度优先搜索`(breadth-first search,BFS)不同与深度优先搜索,它是一层层进行遍历的,因此`需要用先入先出的队列 (queue)` 而非先入后出的栈 (stack) 进行遍历。由于是按层次进行遍历,广度优先搜索时按照“广”的方向进行遍历的,也常常用来处理最短路径等问题。在 Python 中,我们可以用 collections.deque 来实现 C++ 中的 queue。 + +``` + 1 + / \ + 2 3 + / +4 +``` + +这里要注意,深度优先搜索和广度优先搜索都可以处理`可达性`问题,即从一个节点开始是否能达到另一个节点。因为深度优先搜索可以利用递归快速实现,很多人会习惯使用深度优先搜索刷此类题目。实际软件工程中,笔者很少见到递归的写法,因为一方面难以理解,另一方面可能产生栈溢出的情况;而用栈实现的深度优先搜索和用队列实现的广度优先搜索在写法上并没有太大差异,因此使用哪一种搜索方式需要根据实际的功能需求来判断。另外,如果需要自定义搜索优先级,我们可以利用优先队列,这个我们会在数据结构的章节讲到。 + +## [1091. Shortest Path in Binary Matrix](https://leetcode.com/problems/shortest-path-in-binary-matrix/) + +### 题目描述 + +给定一个二维 0-1 矩阵,其中 1 表示障碍,0 表示道路,每个位置与周围八个格子相连。求从左上角到右下角的最短到达距离。如果没有可以到达的方法,返回-1。 + +### 输入输出样例 + +输入是一个二维整数数组,输出是一个整数,表示最短距离。 + +``` +Input: +[[0,0,1], + [1,1,0], + [1,1,0]] +Output: 4 +``` + +最短到达方法为先向右,拐弯之后再向下。 + +### 题解 + +利用队列,我们可以很直观地利用广度优先搜索,搜索最少扩展层数,即最短到达目的地的距离。注意不要重复搜索相同位置。 + + + + +```cpp +int shortestPathBinaryMatrix(vector>& grid) { + if (grid[0][0] == 1) { + return -1; + } + int m = grid.size(), n = grid[0].size(); + int dist = 0, count; + queue> q; + q.push({0, 0}); + grid[0][0] = -1; // -1表示visited + count = q.size(); + while (count > 0) { + ++dist; + while (count--) { + auto [r, c] = q.front(); + q.pop(); + if (r == m - 1 && c == n - 1) { + return dist; + } + for (int dx = -1; dx <= 1; ++dx) { + for (int dy = -1; dy <= 1; ++dy) { + if (dx == 0 && dy == 0) { + continue; + } + int x = r + dx, y = c + dy; + if (x < 0 || y < 0 || x >= m || y >= n || grid[x][y] != 0) { + continue; + } + grid[x][y] = -1; + q.push({x, y}); + } + } + } + count = q.size(); + } + return -1; +} +``` + + + + +```py +def shortestPathBinaryMatrix(grid: List[List[int]]) -> int: + if grid[0][0] == 1: + return -1 + m, n = len(grid), len(grid[0]) + dist = 0 + q = collections.deque() + q.append((0, 0)) + grid[0][0] = -1 # -1表示visited + count = len(q) + while count > 0: + dist += 1 + while count > 0: + count -= 1 + r, c = q.popleft() + if r == m - 1 and c == n - 1: + return dist + for dx in range(-1, 2): + for dy in range(-1, 2): + if dx == 0 and dy == 0: + continue + x, y = r + dx, c + dy + if x < 0 or y < 0 or x >= m or y >= n or grid[x][y] != 0: + continue + grid[x][y] = -1 + q.append((x, y)) + count = len(q) + return -1 +``` + + + + + +## [934. Shortest Bridge](https://leetcode.com/problems/shortest-bridge/) + +### 题目描述 + +给定一个二维 0-1 矩阵,其中 1 表示陆地,0 表示海洋,每个位置与上下左右相连。已知矩阵中有且只有两个岛屿,求最少要填海造陆多少个位置才可以将两个岛屿相连。 + +### 输入输出样例 + +输入是一个二维整数数组,输出是一个非负整数,表示需要填海造陆的位置数。 + +``` +Input: +[[1,1,1,1,1], + [1,0,0,0,1], + [1,0,1,0,1], + [1,0,0,0,1], + [1,1,1,1,1]] +Output: 1 +``` + +### 题解 + +本题实际上是求两个岛屿间的最短距离,因此我们可以先通过任意搜索方法找到其中一个岛屿,然后利用广度优先搜索,查找其与另一个岛屿的最短距离。这里我们展示利用深度优先搜索查找第一个岛屿。 + + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// 辅函数。 + +void dfs(queue>& points, vector>& grid, int i, + int j) { + int m = grid.size(), n = grid[0].size(); + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 2) { + return; + } + if (grid[i][j] == 0) { + points.push({i, j}); + return; + } + grid[i][j] = 2; + for (int k = 0; k < 4; ++k) { + dfs(points, grid, i + direction[k], j + direction[k + 1]); + } +} + +// 主函数。 +int shortestBridge(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + queue> points; + // DFS寻找第一个岛屿,并把1全部赋值为2。 + bool flipped = false; + for (int i = 0; i < m && !flipped; ++i) { + for (int j = 0; j < n && !flipped; ++j) { + if (grid[i][j] == 1) { + dfs(points, grid, i, j); + flipped = true; + } + } + } + // BFS寻找第二个岛屿,并把过程中经过的0赋值为2。 + int level = 0; + while (!points.empty()) { + ++level; + int n_points = points.size(); + while (n_points--) { + auto [r, c] = points.front(); + points.pop(); + grid[r][c] = 2; + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + if (grid[x][y] == 2) { + continue; + } + if (grid[x][y] == 1) { + return level; + } + grid[x][y] = 2; + points.push({x, y}); + } + } + } + } + return 0; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# 辅函数。 +def dfs(points: Deque[Tuple[int, int]], grid: List[List[int]], i: int, j: int): + m, n = len(grid), len(grid[0]) + if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 2: + return + if grid[i][j] == 0: + points.append((i, j)) + return + grid[i][j] = 2 + for k in range(4): + dfs(points, grid, i + direction[k], j + direction[k + 1]) + +def shortestBridge(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + points = collections.deque() + # DFS寻找第一个岛屿,并把1全部赋值为2。 + flipped = False + for i in range(m): + if flipped: + break + for j in range(n): + if grid[i][j] == 1: + dfs(points, grid, i, j) + flipped = True + break + # BFS寻找第二个岛屿,并把过程中经过的0赋值为2。 + level = 0 + while len(points) > 0: + level += 1 + points_at_current_level = len(points) + for _ in range(points_at_current_level): + r, c = points.popleft() + grid[r][c] = 2 + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + if x >= 0 and x < m and y >= 0 and y < n: + if grid[x][y] == 2: + continue + if grid[x][y] == 1: + return level + grid[x][y] = 2 + points.append((x, y)) + return level +``` + + + + + +## [126. Word Ladder II](https://leetcode.com/problems/word-ladder-ii/) + +### 题目描述 + +给定一个起始字符串和一个终止字符串,以及一个单词表,求是否可以将起始字符串每次改一个字符,直到改成终止字符串,且所有中间的修改过程表示的字符串都可以在单词表里找到。若存在,输出需要修改次数最少的所有更改方式。 + +### 输入输出样例 + +输入是两个字符串,输出是一个二维字符串数组,表示每种字符串修改方式。 + +``` +Input: beginWord = "hit", endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] +Output: +[["hit","hot","dot","dog","cog"], + ["hit","hot","lot","log","cog"]] +``` + +### 题解 + + +我们可以把起始字符串、终止字符串、以及单词表里所有的字符串想象成节点。若两个字符串只有一个字符不同,那么它们相连。因为题目需要输出修改次数最少的所有修改方式,因此我们可以使用广度优先搜索,求得起始节点到终止节点的最短距离。 + +我们同时还使用了一个小技巧:我们并不是直接从起始节点进行广度优先搜索,直到找到终止节点为止;而是从起始节点和终止节点分别进行广度优先搜索,每次只延展当前层节点数最少的那一端,这样我们可以减少搜索的总结点数。举例来说,假设最短距离为 4,如果我们只从一端搜索 4 层,总遍历节点数最多是 $1 + 2 + 4 + 8 + 16 = 31$;而如果我们从两端各搜索两层,总遍历节点数最多只有 $2 × (1 + 2 + 4) =14$。 + +在搜索结束后,我们还需要通过回溯法来重建所有可能的路径。 + +这道题略微复杂,需要读者耐心思考和实现代码。LeetCode 对于本题的时间要求非常严格,即使是官方题解也经常容易超时,可以尝试多次提交。 + + + + +```cpp +// 辅函数。 +void backtracking(const string &src, const string &dst, + unordered_map> &next_words, + vector &path, vector> &ladder) { + if (src == dst) { + ladder.push_back(path); + return; + } + if (!next_words.contains(src)) { + return; + } + for (const auto &w : next_words[src]) { + path.push_back(w); // 修改当前节点状态 + backtracking(w, dst, next_words, path, ladder); // 递归子节点 + path.pop_back(); // 回改当前节点状态 + } +} + +// 主函数。 +vector> findLadders(string beginWord, string endWord, + vector &wordList) { + vector> ladder; + // 用哈希集合存储字典,方便查找。 + unordered_set word_dict; + for (const auto &w : wordList) { + word_dict.insert(w); + } + if (!word_dict.contains(endWord)) { + return ladder; + } + word_dict.erase(beginWord); + word_dict.erase(endWord); + // 建立两个queue,从beginWord和endWord同时延展,每次延展最小的。 + // 因为之后的去重操作需要遍历queue,我们这里用哈希表实现它, + // 只要保证是分层次遍历即可。 + unordered_set q_small{beginWord}, q_large{endWord}; + unordered_map> next_words; + bool reversed_path = false, found_path = false; + while (!q_small.empty()) { + unordered_set q; + for (const auto &w : q_small) { + string s = w; + for (int i = 0; i < s.size(); ++i) { + for (int j = 0; j < 26; ++j) { + s[i] = j + ’a’; + if (q_large.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + found_path = true; + } + if (word_dict.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + q.insert(s); + } + } + s[i] = w[i]; + } + } + if (found_path) { + break; + } + // 环路一定不是最短解,所以这里需要去重和避免无限循环。 + for (const auto &w : q) { + word_dict.erase(w); + } + // 更新两个queue,并维持大小关系。 + if (q.size() <= q_large.size()) { + q_small = q; + } else { + reversed_path = !reversed_path; + q_small = q_large; + q_large = q; + } + } + if (found_path) { + vector path{beginWord}; + backtracking(beginWord, endWord, next_words, path, ladder); + } + return ladder; +} +``` + + + + +```py +# 辅函数。 +def backtracking(src: str, dst: str, next_words: Dict[str, List[str]], + path: List[str], ladder: List[List[str]]): + if src == dst: + ladder.append(path[:]) + return + if src not in next_words: + return + for w in next_words[src]: + path.append(w) # 修改当前节点状态 + backtracking(w, dst, next_words, path, ladder) # 递归子节点 + path.pop() # 回改当前节点状态 + +# 主函数。 +def findLadders(beginWord: str, endWord: str, + wordList: List[str]) -> List[List[str]]: + ladder = [] + # 用哈希集合存储字典,方便查找。 + word_dict = set(wordList) + if endWord not in word_dict: + return ladder + word_dict = word_dict.difference(set([beginWord, endWord])) + # 建立两个queue,从beginWord和endWord同时延展,每次延展最小的。 + # 因为之后的去重操作需要遍历queue,我们这里用哈希表实现它, + # 只要保证是分层次遍历即可。 + q_small, q_large = set([beginWord]), set([endWord]) + next_words = dict() + reversed_path, found_path = False, False + while len(q_small) > 0: + q = set() + for w in q_small: + for i in range(len(w)): + for j in range(26): + s = w[:i] + chr(ord("a") + j) + w[i + 1:] + if s in q_large: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + found_path = True + if s in word_dict: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + q.add(s) + if found_path: + break + # 环路一定不是最短解,所以这里需要去重和避免无限循环。 + word_dict = word_dict.difference(q) + # 更新两个queue,并维持大小关系。 + if len(q) <= len(q_large): + q_small = q + else: + reversed_path = not reversed_path + q_small = q_large + q_large = q + + if found_path: + path = [beginWord] + backtracking(beginWord, endWord, next_words, path, ladder) + return ladder + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/5-searching-algorithms/5-5-exercises.md b/leetcode_101/docs/5-searching-algorithms/5-5-exercises.md new file mode 100644 index 00000000..cfd5d3d7 --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/5-5-exercises.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 25 +--- + +# 5.5 练习 + +## 基础难度 + +### [130. Surrounded Regions](https://leetcode.com/problems/surrounded-regions/) + +先从最外侧填充,然后再考虑里侧。 + +--- + +### [257. Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) + +输出二叉树中所有从根到叶子的路径,回溯法使用与否有什么区别? + +--- + +## 进阶难度 + +### [47. Permutations II](https://leetcode.com/problems/permutations-ii/) + +排列题的 follow-up,如何处理重复元素? + +--- + +### [40. Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) + +组合题的 follow-up,如何处理重复元素? + +--- + +### [37. Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) + +十分经典的数独题,可以利用回溯法求解。事实上对于数独类型的题,有很多进阶的搜索方法和剪枝策略可以提高速度,如启发式搜索。 + +--- + +### [310. Minimum Height Trees](https://leetcode.com/problems/minimum-height-trees/) + +如何将这道题转为搜索类型题?是使用深度优先还是广度优先呢? \ No newline at end of file diff --git a/leetcode_101/docs/5-searching-algorithms/_category_.json b/leetcode_101/docs/5-searching-algorithms/_category_.json new file mode 100644 index 00000000..0943e8c5 --- /dev/null +++ b/leetcode_101/docs/5-searching-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "5. 一切皆可搜索", + "position": 5, + "link": { + "type": "generated-index", + "description": "第 5 章 一切皆可搜索" + } +} diff --git a/leetcode_101/docs/5-searching-algorithms/n-queens.png b/leetcode_101/docs/5-searching-algorithms/n-queens.png new file mode 100644 index 00000000..f6ea0755 Binary files /dev/null and b/leetcode_101/docs/5-searching-algorithms/n-queens.png differ diff --git a/leetcode_101/docs/6-dynamic-programming/6-1-algorithm-explanation.md b/leetcode_101/docs/6-dynamic-programming/6-1-algorithm-explanation.md new file mode 100644 index 00000000..48055183 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-1-algorithm-explanation.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 26 +--- + +# 6.1 算法解释 + +这里我们引用一下维基百科的描述:“`动态规划`(Dynamic Programming, DP)在查找有很多`重叠子问题`的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间 · · · · · · 动态规划只能应用于有`最优子结构`的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。” + +通俗一点来讲,动态规划和其它遍历算法(如深/广度优先搜索)都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划`保存子问题的解,避免重复计算`。解决动态规划问题的关键是找到`状态转移方程`,这样我们可以通过计算和储存子问题的解来求解最终问题。 + +同时,我们也可以对动态规划进行`空间压缩`,起到节省空间消耗的效果。这一技巧笔者将在之后的题目中介绍。 + +在一些情况下,动态规划可以看成是带有`状态记录`(memoization)的优先搜索。状态记录的意思为,如果一个子问题在优先搜索时已经计算过一次,我们可以把它的结果储存下来,之后遍历到该子问题的时候可以直接返回储存的结果。动态规划是自下而上的,即先解决子问题,再解决父问题;而用带有状态记录的优先搜索是自上而下的,即从父问题搜索到子问题,若重复搜索到同一个子问题则进行状态记录,防止重复计算。如果题目需求的是最终状态,那么使用动态搜索比较方便;如果题目需要输出所有的路径,那么使用带有状态记录的优先搜索会比较方便。 \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-2-basic-dp-1d.mdx b/leetcode_101/docs/6-dynamic-programming/6-2-basic-dp-1d.mdx new file mode 100644 index 00000000..e5d96da3 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-2-basic-dp-1d.mdx @@ -0,0 +1,236 @@ +--- +sidebar_position: 27 +--- + +# 6.2 基本动态规划:一维 + +## [70. Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) + +### 题目描述 + +给定 $n$ 节台阶,每次可以走一步或走两步,求一共有多少种方式可以走完这些台阶。 + +### 输入输出样例 + +输入是一个数字,表示台阶数量;输出是爬台阶的总方式。 + +``` +Input: 3 +Output: 3 +``` + +在这个样例中,一共有三种方法走完这三节台阶:每次走一步;先走一步,再走两步;先走两步,再走一步。 + +### 题解 + +这是十分经典的斐波那契数列题。定义一个数组 dp,dp[i] 表示走到第 i 阶的方法数。因为我们每次可以走一步或者两步,所以第 i 阶可以从第 i-1 或 i-2 阶到达。换句话说,走到第 i 阶的方法数即为走到第 i-1 阶的方法数加上走到第 i-2 阶的方法数。这样我们就得到了状态转移方程 dp[i] = dp[i-1] + dp[i-2]。注意边界条件的处理。 + +:::warning + +有的时候为了方便处理边界情况,我们可以在构造 dp 数组时多留一个位置,用来处理初始状态。本题即多留了一个第 0 阶的初始位置。 + +::: + + + + +```cpp +int climbStairs(int n) { + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + dp = [1] * (n + 1) + for i in range(2, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + return dp[n] +``` + + + + + +进一步的,我们可以对动态规划进行空间压缩。因为 dp[i] 只与 dp[i-1] 和 dp[i-2] 有关,因此可以只用两个变量来存储 dp[i-1] 和 dp[i-2],使得原来的 $O(n)$ 空间复杂度优化为 $O(1)$ 复杂度。 + + + + +```cpp +int climbStairs(int n) { + int prev_prev = 1, prev = 1, cur = 1; + for (int i = 2; i <= n; ++i) { + cur = prev_prev + prev; + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + prev_prev = prev = cur = 1 + for _ in range(2, n + 1): + cur = prev_prev + prev + prev_prev = prev + prev = cur + return cur +``` + + + + + + +## [198. House Robber](https://leetcode.com/problems/house-robber/) + +### 题目描述 + +假如你是一个劫匪,并且决定抢劫一条街上的房子,每个房子内的钱财数量各不相同。如果你抢了两栋相邻的房子,则会触发警报机关。求在不触发机关的情况下最多可以抢劫多少钱。 + +### 输入输出样例 + +输入是一个一维数组,表示每个房子的钱财数量;输出是劫匪可以最多抢劫的钱财数量。 + +``` +Input: [2,7,9,3,1] +Output: 12 +``` + +在这个样例中,最多的抢劫方式为抢劫第 1、3、5 个房子。 + +### 题解 + +定义一个数组 dp,dp[i] 表示抢劫到第 i 个房子时,可以抢劫的最大数量。我们考虑 dp[i],此时可以抢劫的最大数量有两种可能,一种是我们选择不抢劫这个房子,此时累计的金额即为 dp[i-1];另一种是我们选择抢劫这个房子,那么此前累计的最大金额只能是 dp[i-2],因为我们不能够抢劫第 i-1 个房子,否则会触发警报机关。因此本题的状态转移方程为 dp[i] = max(dp[i-1], nums[i-1] + dp[i-2])。 + + + + +```cpp +int rob(vector& nums) { + int n = nums.size(); + vector dp(n + 1, 0); + dp[1] = nums[0]; + for (int i = 2; i <= n; ++i) { + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]); + } + return dp[n]; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + n = len(nums) + dp = [0] * (n + 1) + dp[1] = nums[0] + for i in range(2, n + 1): + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]) + return dp[n] +``` + + + + + +同样的,我们可以像题目 70 那样,对空间进行压缩。 + + + + +```cpp +int rob(vector& nums) { + int prev_prev = 0, prev = 0, cur = 0; + for (int i = 0; i < nums.size(); ++i) { + cur = max(prev_prev + nums[i], prev); + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + prev_prev = prev = cur = 0 + for i in range(len(nums)): + cur = max(prev_prev + nums[i], prev) + prev_prev = prev + prev = cur + return cur +``` + + + + + +## [413. Arithmetic Slices](https://leetcode.com/problems/arithmetic-slices/) + +### 题目描述 + +给定一个数组,求这个数组中连续且等差的子数组一共有多少个。 + +### 输入输出样例 + +输入是一个一维数组,输出是满足等差条件的连续子数组个数。 + +``` +Input: nums = [1,2,3,4] +Output: 3 +``` + +在这个样例中,等差数列有 [1,2,3]、[2,3,4] 和 [1,2,3,4]。 + +### 题解 + +因为要求是等差数列,可以很自然地想到子数组必定满足 num[i] - num[i-1] = num[i-1] - num[i-2]。这里我们对于 dp 数组的定义是以 i 结尾的,满足该条件的子数组数量。因为等差子数组可以在任意一个位置终结,所以我们需要对 dp 数组求和进行子数组统计。 + + + + +```cpp +int numberOfArithmeticSlices(vector& nums) { + int n = nums.size(); + vector dp(n, 0); + for (int i = 2; i < n; ++i) { + if (nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]) { + dp[i] = dp[i - 1] + 1; + } + } + return accumulate(dp.begin(), dp.end(), 0); +} +``` + + + + +```py +def numberOfArithmeticSlices(nums: List[int]) -> int: + n = len(nums) + dp = [0] * n + for i in range(2, n): + if nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]: + dp[i] = dp[i - 1] + 1 + return sum(dp) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-3-basic-dp-2d.mdx b/leetcode_101/docs/6-dynamic-programming/6-3-basic-dp-2d.mdx new file mode 100644 index 00000000..02a85a91 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-3-basic-dp-2d.mdx @@ -0,0 +1,307 @@ +--- +sidebar_position: 28 +--- + +# 6.3 基本动态规划:二维 + +## [64. Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/) + +### 题目描述 + +给定一个 $m × n$ 大小的非负整数矩阵,求从左上角开始到右下角结束的、经过的数字的和最 +小的路径。每次只能向右或者向下移动。 + +### 输入输出样例 + +输入是一个二维数组,输出是最优路径的数字和。 + +``` +Input: +[[1,3,1], + [1,5,1], + [4,2,1]] +Output: 7 +``` + +在这个样例中,最短路径为 1->3->1->1->1。 + +### 题解 + +我们可以定义一个同样是二维的 dp 数组,其中 dp[i][j] 表示从左上角开始到 (i, j) 位置的最优路径的数字和。因为每次只能向下或者向右移动,我们可以很直观地得到状态转移方程 dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]),其中 grid 表示原数组。 + +:::warning + +Python 语言中,多维数组多初始化比较特殊,直接初始化为 [[val] * n] * m 会导致只是创造了 m 个 [[val] * n] 的引用。正确的初始化方法为 [[val for _ in range(n)] for _ in range(m)]。 + +::: + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector> dp(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[i][j] = grid[i][j]; + } else if (i == 0) { + dp[i][j] = grid[i][j] + dp[i][j - 1]; + } else if (j == 0) { + dp[i][j] = grid[i][j] + dp[i - 1][j]; + } else { + dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m - 1][n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [[0 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[i][j] = grid[i][j] + elif i == 0: + dp[i][j] = grid[i][j] + dp[i][j - 1] + elif j == 0: + dp[i][j] = grid[i][j] + dp[i - 1][j] + else: + dp[i][j] = grid[i][j] + min(dp[i][j - 1], dp[i - 1][j]) + return dp[m - 1][n - 1] +``` + + + + + +因为 dp 矩阵的每一个值只和左边和上面的值相关,我们可以使用空间压缩将 dp 数组压缩为一维。对于第 i 行,在遍历到第 j 列的时候,因为第 j-1 列已经更新过了,所以 dp[j-1] 代表 dp[i][j-1]的值;而 dp[j] 待更新,当前存储的值是在第 i-1 行的时候计算的,所以代表 dp[i-1][j] 的值。 + +:::warning + +如果不是很熟悉空间压缩技巧,笔者推荐您优先尝试写出非空间压缩的解法,如果时间充裕且力所能及再进行空间压缩。 + +::: + + + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector dp(n, 0); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[j] = grid[i][j]; + } else if (i == 0) { + dp[j] = grid[i][j] + dp[j - 1]; + } else if (j == 0) { + dp[j] = grid[i][j] + dp[j]; + } else { + dp[j] = grid[i][j] + min(dp[j], dp[j - 1]); + } + } + } + return dp[n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [0 for _ in range(n)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[j] = grid[i][j] + elif i == 0: + dp[j] = grid[i][j] + dp[j - 1] + elif j == 0: + dp[j] = grid[i][j] + dp[j] + else: + dp[j] = grid[i][j] + min(dp[j - 1], dp[j]) + return dp[n - 1] +``` + + + + + + +## [542. 01 Matrix](https://leetcode.com/problems/01-matrix/) + +### 题目描述 + +给定一个由 0 和 1 组成的二维矩阵,求每个位置到最近的 0 的距离。 + +### 输入输出样例 + +输入是一个二维 0-1 数组,输出是一个同样大小的非负整数数组,表示每个位置到最近的 0 的距离。 + +``` +Input: +[[0,0,0], + [0,1,0], + [1,1,1]] + +Output: +[[0,0,0], + [0,1,0], + [1,2,1]] +``` + +### 题解 + +一般来说,因为这道题涉及到四个方向上的最近搜索,所以很多人的第一反应可能会是广度优先搜索。但是对于一个大小 $O(mn)$ 的二维数组,对每个位置进行四向搜索,最坏情况的时间复杂度(即全是 1)会达到恐怖的 $O(m^2n^2)$。一种办法是使用一个二维布尔值数组做 memoization,使得广度优先搜索不会重复遍历相同位置;另一种更简单的方法是,我们从左上到右下进行一次动态搜索,再从右下到左上进行一次动态搜索。两次动态搜索即可完成四个方向上的查找。 + + + + + +```cpp +vector> updateMatrix(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + vector> dp(m, vector(n, numeric_limits::max() - 1)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (matrix[i][j] != 0) { + if (i > 0) { + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + } + if (j > 0) { + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } else { + dp[i][j] = 0; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (matrix[i][j] != 0) { + if (i < m - 1) { + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1); + } + if (j < n - 1) { + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1); + } + } + } + } + return dp; +} +``` + + + + +```py +def updateMatrix(matrix: List[List[int]]) -> List[List[int]]: + m, n = len(matrix), len(matrix[0]) + dp = [[sys.maxsize - 1 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if matrix[i][j] != 0: + if i > 0: + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1) + if j > 0: + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1) + else: + dp[i][j] = 0 + for i in range(m - 1, -1, -1): # m-1 to 0, reversed + for j in range(n - 1, -1, -1): # n-1 to 0, reversed + if matrix[i][j] != 0: + if i < m - 1: + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1) + if j < n - 1: + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1) + return dp +``` + + + + + +## [221. Maximal Square](https://leetcode.com/problems/maximal-square/) + +### 题目描述 + +给定一个二维的 0-1 矩阵,求全由 1 构成的最大正方形面积。 + +### 输入输出样例 + +输入是一个二维 0-1 数组,输出是最大正方形面积。 + +``` +Input: +[["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"]] +Output: 4 +``` + +### 题解 + +对于在矩阵内搜索正方形或长方形的题型,一种常见的做法是定义一个二维 dp 数组,其中 dp[i][j] 表示满足题目条件的、以 (i, j) 为右下角的正方形或者长方形的属性。对于本题,则表示以 (i, j) 为右下角的全由 1 构成的最大正方形边长。如果当前位置是 0,那么 dp[i][j] 即为 0;如果当前位置是 1,我们假设 dp[i][j] = k,其充分条件为 dp[i-1][j-1]、dp[i][j-1] 和 dp[i-1][j] 的值必须都不小于 k − 1,否则 (i, j) 位置不可以构成一个面积为 $k^2$ 的正方形。同理,如果这三个值中的的最小值为 k − 1,则 (i, j) 位置一定且最大可以构成一个面积为 $k^2$ 的正方形。 + + +
+ + ![](6.1.png) + +
图 6.1: 题目 542 - 左边为一个 0-1 矩阵,右边为其对应的 dp 矩阵,我们可以发现最大的正方形边长为 3
+
+ + + + +```cpp +int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + int max_side = 0; + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (matrix[i - 1][j - 1] == ’1’) { + dp[i][j] = + min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1; + } + max_side = max(max_side, dp[i][j]); + } + } + return max_side * max_side; +} +``` + + + + +```py +def maximalSquare(matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1 + return max(max(row) for row in dp) ** 2 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-4-partition-problems.mdx b/leetcode_101/docs/6-dynamic-programming/6-4-partition-problems.mdx new file mode 100644 index 00000000..59d3b6b9 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-4-partition-problems.mdx @@ -0,0 +1,347 @@ +--- +sidebar_position: 29 +--- + +# 6.4 分割类型题 + +## [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) + +### 题目描述 + +给定一个正整数,求其最少可以由几个完全平方数相加构成。 + +### 输入输出样例 + +输入是给定的正整数,输出也是一个正整数,表示输入的数字最少可以由几个完全平方数相加构成。 + +``` +Input: n = 13 +Output: 2 +``` + +在这个样例中,13 的最少构成方法为 4+9。 + +### 题解 + +对于分割类型题,动态规划的状态转移方程通常并不依赖相邻的位置,而是依赖于满足分割条件的位置。我们定义一个一维矩阵 dp,其中 dp[i] 表示数字 i 最少可以由几个完全平方数相加构成。在本题中,位置 i 只依赖 $i - j^2$ 的位置,如 i - 1、i - 4、i - 9 等等,才能满足完全平方分割的条件。因此 dp[i] 可以取的最小值即为 1+ min(dp[i-1], dp[i-4], dp[i-9] · · · )。注意边界条件的处理。 + + + + +```cpp +int numSquares(int n) { + vector dp(n + 1, numeric_limits::max()); + dp[0] = 0; + for (int i = 1; i <= n; ++i) { + for (int j = 1; j * j <= i; ++j) { + dp[i] = min(dp[i], dp[i - j * j] + 1); + } + } + return dp[n]; +} +``` + + + + +```py +def numSquares(n: int) -> int: + dp = [0] + [sys.maxsize] * n + for i in range(1, n + 1): + for j in range(1, int(floor(sqrt(i))) + 1): + dp[i] = min(dp[i], dp[i - j * j] + 1) + return dp[n] +``` + + + + + +## [91. Decode Ways](https://leetcode.com/problems/decode-ways/) + +### 题目描述 + +已知字母 A-Z 可以表示成数字 1-26。给定一个数字串,求有多少种不同的字符串等价于这个数字串。 + +### 输入输出样例 + +输入是一个由数字组成的字符串,输出是满足条件的解码方式总数。 + +``` +Input: "226" +Output: 3 +``` + +在这个样例中,有三种解码方式:BZ(2 26)、VF(22 6) 或 BBF(2 2 6)。 + +### 题解 + +这是一道很经典的动态规划题,难度不大但是十分考验耐心。这是因为只有 1-26 可以表示字母,因此对于一些特殊情况,比如数字 0 或者当相邻两数字大于 26 时,需要有不同的状态转移方程,详见如下代码。 + + + + +```cpp +int numDecodings(string s) { + int n = s.length(); + int prev = s[0] - ’0’; + if (prev == 0) { + return 0; + } + if (n == 1) { + return 1; + } + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + int cur = s[i - 1] - ’0’; + if ((prev == 0 || prev > 2) && cur == 0) { + // 00, 30, 40, ..., 90, 非法。 + return 0; + } + if ((prev < 2 && prev > 0) || (prev == 2 && cur <= 6)) { + // 10, 11, ..., 25, 26. + if (cur == 0) { + // 10, 20,只能连续解码两位。 + dp[i] = dp[i - 2]; + } else { + // 可以解码当前位,也可以连续解码两位。 + dp[i] = dp[i - 2] + dp[i - 1]; + } + } else { + // 合法,但只能解码当前位。 + dp[i] = dp[i - 1]; + } + prev = cur; + } + return dp[n]; +} +``` + + + + +```py +def numDecodings(s: str) -> int: + n = len(s) + prev = ord(s[0]) - ord("0") + if prev == 0: + return 0 + if n == 1: + return 1 + dp = [1] * (n + 1) + for i in range(2, n + 1): + cur = ord(s[i - 1]) - ord("0") + if (prev == 0 or prev > 2) and cur == 0: + # 00, 30, 40, ..., 90, 非法。 + return 0 + if 0 < prev < 2 or (prev == 2 and cur <= 6): + # 10, 11, ..., 25, 26. + if cur == 0: + # 10, 20,只能连续解码两位。 + dp[i] = dp[i - 2] + else: + # 可以解码当前位,也可以连续解码两位。 + dp[i] = dp[i - 2] + dp[i - 1] + else: + # 合法,但只能解码当前位。 + dp[i] = dp[i - 1] + prev = cur + return dp[n] +``` + + + + + +## [139. Word Break](https://leetcode.com/problems/word-break/) + +### 题目描述 + +给定一个字符串和一个字符串集合,求是否存在一种分割方式,使得原字符串分割后的子字符串都可以在集合内找到。 + +### 输入输出样例 + +``` +Input: s = "applepenapple", wordDict = ["apple", "pen"] +Output: true +``` + +在这个样例中,字符串可以被分割为 [“apple”,“pen”,“apple”]。 + +### 题解 + +类似于完全平方数分割问题,这道题的分割条件由集合内的字符串决定,因此在考虑每个分割位置时,需要遍历字符串集合,以确定当前位置是否可以成功分割。注意对于位置 0,需要初始化值为真。 + + + + +```cpp +bool wordBreak(string s, vector& wordDict) { + int n = s.length(); + vector dp(n + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (const string& word : wordDict) { + int m = word.length(); + if (i >= m && s.substr(i - m, m) == word) { + dp[i] = dp[i - m]; + } + // 提前剪枝,略微加速运算。 + // 如果不剪枝,上一行代码需要变更为 dp[i] = dp[i] || dp[i - m]; + if (dp[i]) { + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def wordBreak(s: str, wordDict: List[str]) -> bool: + n = len(s) + dp = [True] + [False] * n + for i in range(1, n + 1): + for word in wordDict: + m = len(word) + if i >= m and s[i - m : i] == word: + dp[i] = dp[i - m] + # 提前剪枝,略微加速运算。 + # 如果不剪枝,上一行代码需要变更为 dp[i] = dp[i] or dp[i-m] + if dp[i]: + break + return dp[n] +``` + + + + + +## [1105. Filling Bookcase Shelves](https://leetcode.com/problems/filling-bookcase-shelves/) + +### 题目描述 + +给定一个数组,每个元素代表一本书的厚度和高度。问对于一个固定宽度的书架,如果按照数组中书的顺序从左到右、从上到下摆放,最小总高度是多少。 + +### 输入输出样例 + + +``` +Input: books = [[1,1],[2,3],[2,3],[1,1],[1,1],[1,1],[1,2]], shelfWidth = 4 +Output: 6 +``` + + +
+ + ![](https://assets.leetcode.com/uploads/2019/06/24/shelves.png) + +
图 6.2: 书架摆放问题 - 样例图解
+
+ +### 题解 + +令 dp[i] 表示放置第 i 本书时的最小总高度,则 dp[i] 可以是在第 i-1 本书下面重新放一排,也可以是在满足不超过前一排宽度的情况下放在前一排。 + + + + +```cpp +int minHeightShelves(vector>& books, int shelfWidth) { + int n = books.size(); + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) { + int w = books[i - 1][0], h = books[i - 1][1]; + dp[i] = dp[i - 1] + h; + for (int j = i - 1; j > 0; --j) { + int prev_w = books[j - 1][0], prev_h = books[j - 1][1]; + w += prev_w; + if (w > shelfWidth) { + break; + } + h = max(h, prev_h); + dp[i] = min(dp[i], dp[j - 1] + h); + } + } + return dp[n]; +} +``` + + + + +```py +def minHeightShelves(books: List[List[int]], shelfWidth: int) -> int: + n = len(books) + dp = [0] * (n + 1) + for i, (w, h) in enumerate(books, 1): + dp[i] = dp[i - 1] + h + for j in range(i - 1, 0, -1): + prev_w, prev_h = books[j - 1] + w += prev_w + if w > shelfWidth: + break + h = max(h, prev_h) + dp[i] = min(dp[i], dp[j - 1] + h) + return dp[n] +``` + + + + + +## [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) + +### 题目描述 + +给定一个不重复数字的数组和一个目标数,求加起来是目标数的所有排列的总数量。(虽然这道题叫做 Combination Sum,但是不同顺序的组合会被当作不同答案,因此本质上是排列。) + +### 输入输出样例 + +``` +Input: nums = [1,2,3], target = 4 +Output: 7 +``` + +七种不同的排列为 (1, 1, 1, 1)、(1, 1, 2)、(1, 2, 1)、(1, 3)、(2, 1, 1)、(2, 2) 和 (3, 1)。 + + +### 题解 + +令 dp[i] 表示加起来和为 i 时,满足条件的排列数量。在内循环中我们可以直接对所有合法数字进行拿取。这里注意,在 C++ 题解中,因为求和时很容易超过 int 上界,我们这里用 double 存储 dp 数组。 + + + + +```cpp +int combinationSum4(vector& nums, int target) { + vector dp(target + 1, 0); + dp[0] = 1; + for (int i = 1; i <= target; ++i) { + for (int num : nums) { + if (num <= i) { + dp[i] += dp[i - num]; + } + } + } + return dp[target]; +} +``` + + + + +```py +def combinationSum4(nums: List[int], target: int) -> int: + dp = [1] + [0] * target + for i in range(1, target + 1): + dp[i] = sum(dp[i - num] for num in nums if i >= num) + return dp[target] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-5-subsequence-problems.mdx b/leetcode_101/docs/6-dynamic-programming/6-5-subsequence-problems.mdx new file mode 100644 index 00000000..f61fbdbb --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-5-subsequence-problems.mdx @@ -0,0 +1,189 @@ +--- +sidebar_position: 30 +--- + +# 6.5 子序列问题 + +## [300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) + +### 题目描述 + +给定一个未排序的整数数组,求最长的递增子序列。 + +:::warning + +按照 LeetCode 的习惯,子序列(subsequence)不必连续,子数组(subarray)或子字符串(substring)必须连续。 + +::: + +### 输入输出样例 + +输入是一个一维数组,输出是一个正整数,表示最长递增子序列的长度。 + +``` +Input: [10,9,2,5,3,7,101,4] +Output: 4 +``` + +在这个样例中,最长递增子序列之一是 [2,3,7,101]。 + +### 题解 + +对于子序列问题,第一种动态规划方法是,定义一个 dp 数组,其中 dp[i] 表示以 i 结尾的子序列的性质。在处理好每个位置后,统计一遍各个位置的结果即可得到题目要求的结果。 + +在本题中,dp[i] 可以表示以 i 结尾的、最长子序列长度。对于每一个位置 i,如果其之前的某个位置 j 所对应的数字小于位置 i 所对应的数字,则我们可以获得一个以 i 结尾的、长度为 dp[j] + 1 的子序列。为了遍历所有情况,我们需要 i 和 j 进行两层循环,其时间复杂度为 $O(n^2)$。 + + + + +```cpp +int lengthOfLIS(vector& nums) { + int max_len = 0, n = nums.size(); + vector dp(n, 1); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + if (nums[i] > nums[j]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + max_len = max(max_len, dp[i]); + } + return max_len; +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + n = len(nums) + dp = [1] * n + for i in range(n): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) +``` + + + + + +本题还可以使用二分查找将时间复杂度降低为 $O(n \log n)$。我们定义一个 dp 数组,其中 dp[k] 存储长度为 k+1 的最长递增子序列的最后一个数字。我们遍历每一个位置 i,如果其对应的数字大于 dp 数组中所有数字的值,那么我们把它放在 dp 数组尾部,表示最长递增子序列长度加 1;如果我们发现这个数字在 dp 数组中比数字 a 大、比数字 b 小,则我们将 b 更新为此数字,使得之后构成递增序列的可能性增大。以这种方式维护的 dp 数组永远是递增的,因此可以用二分查找加速搜索。 + +以样例为例,对于数组 [10,9,2,5,3,7,101,4],我们每轮的更新查找情况为: + +``` +num dp +10 [10] +9 [9] +2 [2] +5 [2,5] +3 [2,3] +7 [2,3,7] +101 [2,3,7,101] +4 [2,3,4,101] +``` + +最终我们知道最长递增子序列的长度是 4。注意 dp 数组最终的形式并不一定是合法的排列形式,如 [2,3,4,101] 并不是子序列;但之前覆盖掉的 [2,3,7,101] 是最优解之一。 + +类似的,对于其他题目,如果状态转移方程的结果递增或递减,且需要进行插入或查找操作,我们也可以使用二分法进行加速。 + + + + +```cpp +int lengthOfLIS(vector& nums) { + vector dp{nums[0]}; + for (int num : nums) { + if (dp.back() < num) { + dp.push_back(num); + } else { + *lower_bound(dp.begin(), dp.end(), num) = num; + } + } + return dp.size(); +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + dp = [nums[0]] + for num in nums: + if dp[-1] < num: + dp.append(num) + else: + dp[bisect.bisect_left(dp, num, 0, len(dp))] = num + return len(dp) +``` + + + + + +## [1143. Longest Commom Subsequence](https://leetcode.com/problems/longest-common-subsequence/) + +### 题目描述 + +给定两个字符串,求它们最长的公共子序列长度。 + +### 输入输出样例 + +输入是两个字符串,输出是一个整数,表示它们满足题目条件的长度。 + +``` +Input: text1 = "abcde", text2 = "ace" +Output: 3 +``` + +在这个样例中,最长公共子序列是“ace”。 + +### 题解 + +对于子序列问题,第二种动态规划方法是,定义一个 dp 数组,其中 dp[i] 表示到位置 i 为止的子序列的性质,并不必须以 i 结尾。这样 dp 数组的最后一位结果即为题目所求,不需要再对每个位置进行统计。 + +在本题中,我们可以建立一个二维数组 dp,其中 dp[i][j] 表示到第一个字符串位置 i 为止、到第二个字符串位置 j 为止、最长的公共子序列长度。这样一来我们就可以很方便地分情况讨论这两个位置对应的字母相同与不同的情况了。 + + + + +```cpp +int longestCommonSubsequence(string text1, string text2) { + int m = text1.length(), n = text2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (text1[i - 1] == text2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def longestCommonSubsequence(text1: str, text2: str) -> int: + m, n = len(text1), len(text2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if text1[i - 1] == text2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + return dp[m][n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-6-knapsack-problem.mdx b/leetcode_101/docs/6-dynamic-programming/6-6-knapsack-problem.mdx new file mode 100644 index 00000000..49107bec --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-6-knapsack-problem.mdx @@ -0,0 +1,421 @@ +--- +sidebar_position: 31 +--- + +# 6.6 背包问题 + +`背包问题(knapsack problem)`是一种组合优化的 NP 完全问题:有 n 个物品和载重为 w 的背包,每个物品都有自己的重量 weight 和价值 value,求拿哪些物品可以使得背包所装下物品的总价值最大。如果限定每种物品只能选择 0 个或 1 个,则问题称为 `0-1 背包问题(0-1 knapsack)`;如果不限定每种物品的数量,则问题称为`无界背包问题或完全背包问题(unbounded knapsack)`。 + +我们可以用动态规划来解决背包问题。以 0-1 背包问题为例。我们可以定义一个二维数组 dp存储最大价值,其中 dp[i][j] 表示前 i 件物品重量不超过 j 的情况下能达到的最大价值。在我们遍历到第 i 件物品时,在当前背包总载重为 j 的情况下,如果我们不将物品 i 放入背包,那么 dp[i][j] = dp[i-1][j],即前 i 个物品的最大价值等于只取前 i-1 个物品时的最大价值;如果我们将物品 i 放入背包,假设第 i 件物品重量为 weight,价值为 value,那么我们得到 dp[i][j] = dp[i-1][j-weight] + value。我们只需在遍历过程中对这两种情况取最大值即可,总时间复杂度和空间复杂度都为 $O(nw)$。 + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +
+ + ![](6.3.png) + +
图 6.3: 0-1 背包问题 - 状态转移矩阵样例
+
+ +我们可以进一步对 0-1 背包进行空间优化,将空间复杂度降低为 O(w)。如图所示,假设我们目前考虑物品 i = 2,且其重量为 weight = 2,价值为 value = 3;对于背包载重 j,我们可以得到 dp[2][j] = max(dp[1][j], dp[1][j-2] + 3)。这里可以发现我们永远只依赖于上一排 i = 1 的信息,之前算过的其他物品都不需要再使用。因此我们可以去掉 dp 矩阵的第一个维度,在考虑物品 i 时变成 dp[j] = max(dp[j], dp[j-weight] + value)。这里要注意我们在遍历每一行的时候必须`逆向遍历`,这样才能够调用上一行物品 i-1 时 dp[j-weight] 的值;若按照从左往右的顺序进行正向遍历,则dp[j-weight] 的值在遍历到 j 之前就已经被更新成物品 i 的值了。 + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = w; j >= weight; --j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(w, weight - 1, -1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +在完全背包问题中,一个物品可以拿多次。如图上半部分所示,假设我们遍历到物品 i = 2,且其重量为 weight = 2,价值为 value = 3;对于背包载重 j = 5,最多只能装下 2 个该物品。那么我们的状态转移方程就变成了 dp[2][5] = max(dp[1][5], dp[1][3] + 3, dp[1][1] + 6)。如果采用这种方法,假设背包载重无穷大而物体的重量无穷小,我们这里的比较次数也会趋近于无穷大,远超$O(nw)$ 的时间复杂度。 + +
+ + ![](6.4.png) + +
图 6.4: 完全背包问题 - 状态转移矩阵样例
+
+ +怎么解决这个问题呢?我们发现在 dp[2][3] 的时候我们其实已经考虑了 dp[1][3] 和 dp[2][1] 的情况,而在时 dp[2][1] 也已经考虑了 dp[1][1] 的情况。因此,如图下半部分所示,对于拿多个物品的情况,我们只需考虑 dp[2][3] 即可,即 dp[2][5] = max(dp[1][5], dp[2][3] + 3)。这样,我们就得到了完全背包问题的状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i][j-w] + v),其与 0-1 背包问题的差别仅仅是把状态转移方程中的第二个 i-1 变成了 i。 + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +同样的,我们也可以利用空间压缩将时间复杂度降低为 $O(w)$。这里要注意我们在遍历每一行的时候必须`正向遍历`,因为我们需要利用当前物品在第 j-weight 列的信息。 + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = weight; j <= w; ++j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(weight, w + 1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +:::warning + +压缩空间时到底需要正向还是逆向遍历呢?物品和重量哪个放在外层,哪个放在内层呢?这取决于状态转移方程的依赖关系。在思考空间压缩前,不妨将状态转移矩阵画出来,方便思考如何进行空间压缩,以及压缩哪个维度更省空间。 + +::: + +## [416. Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/) + +### 题目描述 + +给定一个正整数数组,求是否可以把这个数组分成和相等的两部分。 + +### 输入输出样例 + +输入是一个一维正整数数组,输出时一个布尔值,表示是否可以满足题目要求。 + +``` +Input: [1,5,11,5] +Output: true +``` + +在这个样例中,满足条件的分割方法是 [1,5,5] 和 [11]。 + +### 题解 + +本题等价于 0-1 背包问题,设所有数字和为 sum,我们的目标是选取一部分物品,使得它们的总和为 sum/2。这道题不需要考虑价值,因此我们只需要通过一个布尔值矩阵来表示状态转移矩阵。注意边界条件的处理。 + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector> dp(n + 1, vector(target + 1, false)); + dp[0][0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j <= target; ++j) { + if (j < nums[i - 1]) { + dp[i][j] = dp[i - 1][j]; + } else { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; + } + } + } + return dp[n][target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [[False for _ in range(target + 1)] for _ in range(n + 1)] + dp[0][0] = True + for i in range(1, n + 1): + for j in range(target + 1): + if j < nums[i - 1]: + dp[i][j] = dp[i - 1][j] + else: + dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]] + return dp[n][target] +``` + + + + + +同样的,我们也可以对本题进行空间压缩。注意对数字和的遍历需要逆向。 + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector dp(target + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = target; j >= nums[i - 1]; --j) { + dp[j] = dp[j] || dp[j - nums[i - 1]]; + } + } + return dp[target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [True] + [False] * target + for i in range(1, n + 1): + for j in range(target, nums[i - 1] - 1, -1): + dp[j] = dp[j] or dp[j - nums[i - 1]] + return dp[target] +``` + + + + + +## [474. Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes/) + +### 题目描述 + +给定 $m$ 个数字 0 和 $n$ 个数字 1,以及一些由 0-1 构成的字符串,求利用这些数字最多可以构成多少个给定的字符串,字符串只可以构成一次。 + +### 输入输出样例 + +输入两个整数 $m$ 和 $n$,表示 0 和 1 的数量,以及一个一维字符串数组,表示待构成的字符串; +输出是一个整数,表示最多可以生成的字符串个数。 + +``` +Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 +Output: 4 +``` + +在这个样例中,我们可以用 5 个 0 和 3 个 1 构成 [“10”, “0001”, “1”, “0”]。 + +### 题解 + +这是一个多维费用的 0-1 背包问题,有两个背包大小,0 的数量和 1 的数量。我们在这里直接展示三维空间压缩到二维后的写法。 + + + + +```cpp +int findMaxForm(vector& strs, int m, int n) { + vector> dp(m + 1, vector(n + 1, 0)); + for (const string& s : strs) { + int zeros = 0, ones = 0; + for (char c : s) { + if (c == ’0’) { + ++zeros; + } else { + ++ones; + } + } + for (int i = m; i >= zeros; --i) { + for (int j = n; j >= ones; --j) { + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def findMaxForm(strs: List[str], m: int, n: int) -> int: + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for s in strs: + zeros = len(list(filter(lambda c: c == "0", s))) + ones = len(s) - zeros + for i in range(m, zeros - 1, -1): + for j in range(n, ones - 1, -1): + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) + return dp[m][n] +``` + + + + + +## [322. Coin Change](https://leetcode.com/problems/coin-change/) + +### 题目描述 + +给定一些硬币的面额,求最少可以用多少颗硬币组成给定的金额。 + +### 输入输出样例 + +输入一个一维整数数组,表示硬币的面额;以及一个整数,表示给定的金额。输出一个整数,表示满足条件的最少的硬币数量。若不存在解,则返回-1。 + +``` +Input: coins = [1, 2, 5], amount = 11 +Output: 3 +``` + +在这个样例中,最少的组合方法是 11 = 5 + 5 + 1。 + +### 题解 + +因为每个硬币可以用无限多次,这道题本质上是完全背包。我们直接展示二维空间压缩为一维的写法。 + +这里注意,我们把 dp 数组初始化为 amount + 1 而不是-1 的原因是,在动态规划过程中有求最小值的操作,如果初始化成-1 则会导致结果始终为-1。至于为什么取这个值,是因为 i 最大可以取 amount,而最多的组成方式是只用 1 元硬币,因此 amount + 1 一定大于所有可能的组合方式,取最小值时一定不会是它。在动态规划完成后,若结果仍然是此值,则说明不存在满足条件的组合方法,返回-1。 + + + + +```cpp +int coinChange(vector& coins, int amount) { + vector dp(amount + 1, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; ++i) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] != amount + 1 ? dp[amount] : -1; +} +``` + + + + +```py +def coinChange(coins: List[int], amount: int) -> int: + dp = [0] + [amount + 1] * amount + for i in range(1, amount + 1): + for coin in coins: + if i >= coin: + dp[i] = min(dp[i], dp[i - coin] + 1) + return dp[amount] if dp[amount] != amount + 1 else -1 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-7-string-editing.mdx b/leetcode_101/docs/6-dynamic-programming/6-7-string-editing.mdx new file mode 100644 index 00000000..8db6b323 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-7-string-editing.mdx @@ -0,0 +1,132 @@ +--- +sidebar_position: 32 +--- + +# 6.7 字符串编辑 + +## [72. Edit Distance](https://leetcode.com/problems/edit-distance/) + +### 题目描述 + +给定两个字符串,已知你可以删除、替换和插入任意字符串的任意字符,求最少编辑几步可以将两个字符串变成相同。 + +### 输入输出样例 + +输入是两个字符串,输出是一个整数,表示最少的步骤。 + +``` +Input: word1 = "horse", word2 = "ros" +Output: 3 +``` + +在这个样例中,一种最优编辑方法是 horse -> rorse -> rose -> ros。 + +### 题解 + +类似于题目 1143,我们使用一个二维数组 dp[i][j],表示将第一个字符串到位置 i 为止,和第二个字符串到位置 j 为止,最多需要几步编辑。当第 i 位和第 j 位对应的字符相同时,dp[i][j] 等于 dp[i-1][j-1];当二者对应的字符不同时,修改的消耗是 dp[i-1][j-1]+1,插入 i 位置/删除 j 位置的消耗是 dp[i][j-1] + 1,插入 j 位置/删除 i 位置的消耗是 dp[i-1][j] + 1。 + + + + +```cpp +int minDistance(string word1, string word2) { + int m = word1.length(), n = word2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 0; i <= m; ++i) { + for (int j = 0; j <= n; ++j) { + if (i == 0 || j == 0) { + dp[i][j] = i + j; + } else { + dp[i][j] = dp[i - 1][j - 1] + (word1[i - 1] != word2[j - 1]); + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def minDistance(word1: str, word2: str) -> int: + m, n = len(word1), len(word2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(m + 1): + for j in range(n + 1): + if i == 0 or j == 0: + dp[i][j] = i + j + else: + dp[i][j] = min( + dp[i - 1][j - 1] + int(word1[i - 1] != word2[j - 1]), + dp[i][j - 1] + 1, + dp[i - 1][j] + 1, + ) + return dp[m][n] +``` + + + + + +## [650. 2 Keys Keyboard](https://leetcode.com/problems/2-keys-keyboard/) + +### 题目描述 + +给定一个字母 A,已知你可以每次选择复制全部字符,或者粘贴之前复制的字符,求最少需要几次操作可以把字符串延展到指定长度。 + +### 输入输出样例 + +输入是一个正整数,代表指定长度;输出是一个整数,表示最少操作次数。 + +``` +Input: 3 +Output: 3 +``` + +在这个样例中,一种最优的操作方法是先复制一次,再粘贴两次。 + +### 题解 + +不同于以往通过加减实现的动态规划,这里需要乘除法来计算位置,因为粘贴操作是倍数增加的。我们使用一个一维数组 dp,其中位置 i 表示延展到长度 i 的最少操作次数。对于每个位置 j,如果 j 可以被 i 整除,那么长度 i 就可以由长度 j 操作得到,其操作次数等价于把一个长度为 j 的 A 延展到长度为 i/j。因此我们可以得到递推公式 dp[i] = dp[j] + dp[i/j]。 + + + + +```cpp +int minSteps(int n) { + vector dp(n + 1, 0); + for (int i = 2; i <= n; ++i) { + dp[i] = i; + for (int j = 2; j * j <= i; ++j) { + if (i % j == 0) { + dp[i] = dp[j] + dp[i / j]; + // 提前剪枝,因为j从小到大,因此操作数量一定最小。 + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def minSteps(n: int) -> int: + dp = [0] * 2 + list(range(2, n + 1)) + for i in range(2, n + 1): + for j in range(2, floor(sqrt(i)) + 1): + if i % j == 0: + dp[i] = dp[j] + dp[i // j] + # 提前剪枝,因为j从小到大,因此操作数量一定最小。 + break + return dp[n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-8-stock-trading.mdx b/leetcode_101/docs/6-dynamic-programming/6-8-stock-trading.mdx new file mode 100644 index 00000000..e4c7b4f8 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-8-stock-trading.mdx @@ -0,0 +1,183 @@ +--- +sidebar_position: 33 +--- + +# 6.8 股票交易 + +`股票交易`类问题通常可以用动态规划来解决。对于稍微复杂一些的股票交易类问题,比如需要冷却时间或者交易费用,则可以用通过动态规划实现的`状态机`来解决。 + +## [121. Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) + +### 题目描述 + +给定一段时间内每天某只股票的固定价格,已知你只可以买卖各一次,求最大的收益。 + +### 输入输出样例 + +输入一个一维整数数组,表示每天的股票价格;输出一个整数,表示最大的收益。 + +``` +Input: [7,1,5,3,6,4] +Output: 5 +``` + +在这个样例中,最大的利润为在第二天价格为 1 时买入,在第五天价格为 6 时卖出。 + +### 题解 + +我们可以遍历一遍数组,在每一个位置 i 时,记录 i 位置之前所有价格中的最低价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益即可。注意本题中以及之后题目中的buy 和 sell 表示买卖操作时,用户账户的收益。因此买时为负,卖时为正。 + + + + +```cpp +int maxProfit(vector& prices) { + int buy = numeric_limits::lowest(), sell = 0; + for (int price : prices) { + buy = max(buy, -price); + sell = max(sell, buy + price); + } + return sell; +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + buy, sell = -sys.maxsize, 0 + for price in prices: + buy = max(buy, -price) + sell = max(sell, buy + price) + return sell +``` + + + + + +## [188. Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) + +### 题目描述 + +给定一段时间内每天某只股票的固定价格,已知你只可以买卖各 $k$ 次,且每次只能拥有一支股票,求最大的收益。 + +### 输入输出样例 + +输入一个一维整数数组,表示每天的股票价格;以及一个整数,表示可以买卖的次数 $k$。输出一个整数,表示最大的收益。 + +``` +Input: [3,2,6,5,0,3], k = 2 +Output: 7 +``` + +在这个样例中,最大的利润为在第二天价格为 2 时买入,在第三天价格为 6 时卖出;再在第五天价格为 0 时买入,在第六天价格为 3 时卖出。 + +### 题解 + +类似地,我们可以建立两个动态规划数组 buy 和 sell,对于每天的股票价格,buy[j] 表示在第 j 次买入时的最大收益,sell[j] 表示在第 j 次卖出时的最大收益。 + + + + + +```cpp +int maxProfit(int k, vector& prices) { + int days = prices.size(); + vector buy(k + 1, numeric_limits::lowest()), sell(k + 1, 0); + for (int i = 0; i < days; ++i) { + for (int j = 1; j <= k; ++j) { + buy[j] = max(buy[j], sell[j - 1] - prices[i]); + sell[j] = max(sell[j], buy[j] + prices[i]); + } + } + return sell[k]; +} +``` + + + + +```py +def maxProfit(k: int, prices: List[int]) -> int: + days = len(prices) + buy, sell = [-sys.maxsize] * (k + 1), [0] * (k + 1) + for i in range(days): + for j in range(1, k + 1): + buy[j] = max(buy[j], sell[j - 1] - prices[i]) + sell[j] = max(sell[j], buy[j] + prices[i]) + return sell[k] +``` + + + + + +## [309. Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) + +### 题目描述 + +给定一段时间内每天某只股票的固定价格,已知每次卖出之后必须冷却一天,且每次只能拥有一支股票,求最大的收益。 + +### 输入输出样例 + +输入一个一维整数数组,表示每天的股票价格;输出一个整数,表示最大的收益。 + +``` +Input: [1,2,3,0,2] +Output: 3 +``` + +在这个样例中,最大的利润获取操作是买入、卖出、冷却、买入、卖出。 + +### 题解 + +我们可以使用状态机来解决这类复杂的状态转移问题,通过建立多个状态以及它们的转移方式,我们可以很容易地推导出各个状态的转移方程。如图所示,我们可以建立四个状态来表示带有冷却的股票交易,以及它们的之间的转移方式。 + +
+ + ![](6.5.png) + +
图 6.5: 题目 309 - 状态机状态转移
+
+ + + + +```cpp +int maxProfit(vector& prices) { + int n = prices.size(); + vector buy(n), sell(n), s1(n), s2(n); + s1[0] = buy[0] = -prices[0]; + sell[0] = s2[0] = 0; + for (int i = 1; i < n; ++i) { + buy[i] = s2[i - 1] - prices[i]; + s1[i] = max(buy[i - 1], s1[i - 1]); + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i]; + s2[i] = max(s2[i - 1], sell[i - 1]); + } + return max(sell[n - 1], s2[n - 1]); +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + n = len(prices) + buy, sell, s1, s2 = [0] * n, [0] * n, [0] * n, [0] * n + s1[0] = buy[0] = -prices[0] + sell[0] = s2[0] = 0 + for i in range(1, n): + buy[i] = s2[i - 1] - prices[i] + s1[i] = max(buy[i - 1], s1[i - 1]) + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i] + s2[i] = max(s2[i - 1], sell[i - 1]) + return max(sell[n - 1], s2[n - 1]) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6-9-exercises.md b/leetcode_101/docs/6-dynamic-programming/6-9-exercises.md new file mode 100644 index 00000000..f02150aa --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/6-9-exercises.md @@ -0,0 +1,62 @@ +--- +sidebar_position: 34 +--- + +# 6.9 练习 + +## 基础难度 + +### [213. House Robber II](https://leetcode.com/problems/house-robber-ii/) + +强盗抢劫题目的 follow-up,如何处理环形数组呢? + +--- + +### [53. Maximum Subarray](https://leetcode.com/problems/maximum-subarray/) + +经典的一维动态规划题目,试着把一维空间优化为常量吧。 + +--- + +### [343. Integer Break](https://leetcode.com/problems/integer-break/) + +分割类型题,先尝试用动态规划求解,再思考是否有更简单的解法。 + +--- + +### [583. Delete Operation for Two Strings](https://leetcode.com/problems/delete-operation-for-two-strings/) + +最长公共子序列的变种题。 + +--- + +## 进阶难度 + + +### [646. Maximum Length of Pair Chain](https://leetcode.com/problems/maximum-length-of-pair-chain/) + +最长递增子序列的变种题,同样的,尝试用二分进行加速。 + +--- + +### [10. Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching/) + +正则表达式匹配,非常考验耐心。需要根据正则表达式的不同情况,即字符、星号,点号等,分情况讨论。 + +--- + +### [376. Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/) + +最长摆动子序列,通项公式比较特殊,需要仔细思考。 + +--- + +### [494. Target Sum](https://leetcode.com/problems/target-sum/) + +如果告诉你这道题是 0-1 背包,你是否会有一些思路? + +--- + +### [714. Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) + +建立状态机,股票交易类问题就会迎刃而解。 \ No newline at end of file diff --git a/leetcode_101/docs/6-dynamic-programming/6.1.png b/leetcode_101/docs/6-dynamic-programming/6.1.png new file mode 100644 index 00000000..6b075633 Binary files /dev/null and b/leetcode_101/docs/6-dynamic-programming/6.1.png differ diff --git a/leetcode_101/docs/6-dynamic-programming/6.3.png b/leetcode_101/docs/6-dynamic-programming/6.3.png new file mode 100644 index 00000000..4ff0572c Binary files /dev/null and b/leetcode_101/docs/6-dynamic-programming/6.3.png differ diff --git a/leetcode_101/docs/6-dynamic-programming/6.4.png b/leetcode_101/docs/6-dynamic-programming/6.4.png new file mode 100644 index 00000000..4acc447e Binary files /dev/null and b/leetcode_101/docs/6-dynamic-programming/6.4.png differ diff --git a/leetcode_101/docs/6-dynamic-programming/6.5.png b/leetcode_101/docs/6-dynamic-programming/6.5.png new file mode 100644 index 00000000..97774d35 Binary files /dev/null and b/leetcode_101/docs/6-dynamic-programming/6.5.png differ diff --git a/leetcode_101/docs/6-dynamic-programming/_category_.json b/leetcode_101/docs/6-dynamic-programming/_category_.json new file mode 100644 index 00000000..1a2cb467 --- /dev/null +++ b/leetcode_101/docs/6-dynamic-programming/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "6. 深入浅出动态规划", + "position": 6, + "link": { + "type": "generated-index", + "description": "第 6 章 深入浅出动态规划" + } +} diff --git a/leetcode_101/docs/7-divide-and-conquer/7-1-algorithm-explanation.md b/leetcode_101/docs/7-divide-and-conquer/7-1-algorithm-explanation.md new file mode 100644 index 00000000..8c1f25c4 --- /dev/null +++ b/leetcode_101/docs/7-divide-and-conquer/7-1-algorithm-explanation.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 35 +--- + +# 7.1 算法解释 + +顾名思义,`分治问题`由“分”(divide)和“治”(conquer)两部分组成,通过把原问题分为子问题,再将子问题进行处理合并,从而实现对原问题的求解。我们在排序章节展示的归并排序就是典型的分治问题,其中“分”即为把大数组平均分成两个小数组,通过递归实现,最终我们会得到多个长度为 1 的子数组;“治”即为把已经排好序的两个小数组合成为一个排好序的大数组从长度为 1 的子数组开始,最终合成一个大数组。 + +我们也使用数学表达式来表示这个过程。定义 $T(n)$ 表示处理一个长度为 $n$ 的数组的时间复杂度,则归并排序的时间复杂度递推公式为 $T(n) =2T(n/2) +O(n)$。其中 $2T(n/2)$ 表示我们分成了两个长度减半的子问题,$O(n)$ 则为合并两个长度为 $n/2$ 数组的时间复杂度。 + +:::info 定理 7.1. 主定理 + +考虑 $T(n) =aT(n/b) + f (n)$,定义 $k =\log_{b} a$ +1. 如果 $f (n) =O(n^p)$ 且 $p < k$,那么 $T(n) =O(n^K)$ +2. 如果存在 $c ≥ 0$ 满足 $f (n) =O(n^k \log^c n)$,那么 $T(n) = O(n^k \log^{c+1} n)$ +3. 如果 $f (n) =O(n^p)$ 且 $p > k$,那么 $T(n) =O( f (n))$ + +::: + +通过主定理我们可以知道,归并排序属于第二种情况,且时间复杂度为 $O(n \log n)$。其他的分治问题也可以通过主定理求得时间复杂度。 + +另外,自上而下的分治可以和 memoization 结合,避免重复遍历相同的子问题。如果方便推导,也可以换用自下而上的动态规划方法求解。 \ No newline at end of file diff --git a/leetcode_101/docs/7-divide-and-conquer/7-2-expression-problems.mdx b/leetcode_101/docs/7-divide-and-conquer/7-2-expression-problems.mdx new file mode 100644 index 00000000..7d89be26 --- /dev/null +++ b/leetcode_101/docs/7-divide-and-conquer/7-2-expression-problems.mdx @@ -0,0 +1,154 @@ +--- +sidebar_position: 36 +--- + +# 7.2 表达式问题 + +## [241. Different Ways to Add Parentheses](https://leetcode.com/problems/different-ways-to-add-parentheses/) + +### 题目描述 + +给定一个只包含加、减和乘法的数学表达式,求通过加括号可以得到多少种不同的结果。 + +### 输入输出样例 + +输入是一个字符串,表示数学表达式;输出是一个数组,存储所有不同的加括号结果。 + +``` +Input: "2-1-1" +Output: [0, 2] +``` + +在这个样例中,有两种加括号结果:((2-1)-1) = 0 和 (2-(1-1)) = 2。 + +### 题解 + +利用分治思想,我们可以把加括号转化为,对于每个运算符号,先执行处理两侧的数学表达式,再处理此运算符号。注意边界情况,即字符串内无运算符号,只有数字。 + + + + +```cpp +vector diffWaysToCompute(string expression) { + vector ways; + unordered_map> op_funcs; + op_funcs[’+’] = [](int x, int y) { return x + y; }; + op_funcs[’-’] = [](int x, int y) { return x - y; }; + op_funcs[’*’] = [](int x, int y) { return x * y; }; + for (int i = 0; i < expression.length(); ++i) { + char c = expression[i]; + if (!op_funcs.contains(c)) { + continue; + } + auto left = diffWaysToCompute(expression.substr(0, i)); + auto right = diffWaysToCompute(expression.substr(i + 1)); + for (int l : left) { + for (int r : right) { + ways.push_back(op_funcs[c](l, r)); + } + } + } + return ways.empty() ? vector{stoi(expression)} : ways; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + ways = [] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i, c in enumerate(expression): + if c not in op_funcs: + continue + left = diffWaysToCompute(expression[:i]) + right = diffWaysToCompute(expression[i + 1 :]) + ways += [op_funcs[c](l, r) for l in left for r in right] + return [int(expression)] if len(ways) == 0 else ways +``` + + + + + +我们发现,某些被 divide 的子字符串可能重复出现多次,因此我们可以用 memoization 来去重。比如建立一个哈希表,key 是 (l, r),value 是 ways。每次遇到相同的 (l, r),我们可以直接返回已经计算过的 ways。或者与其我们从上到下用分治处理 +memoization,不如直接从下到上用动态规划处理。 + + + + +```cpp +vector diffWaysToCompute(string expression) { + // 利用istringstream, 将数字和操作符进行分词。 + vector nums; + vector ops; + int num = 0; + char op = ’ ’; + istringstream ss(expression); + while (ss >> num) { + nums.push_back(num); + if (ss >> op) { + ops.push_back(op); + } + } + int n = nums.size(); + vector>> dp(n, vector>(n, vector())); + unordered_map> op_funcs; + op_funcs[’+’] = [](int a, int b) { return a + b; }; + op_funcs[’-’] = [](int a, int b) { return a - b; }; + op_funcs[’*’] = [](int a, int b) { return a * b; }; + for (int i = 0; i < n; ++i) { + for (int j = i; j >= 0; --j) { + if (i == j) { + dp[j][i].push_back(nums[i]); + continue; + } + for (int k = j; k < i; ++k) { + for (auto l : dp[j][k]) { + for (auto r : dp[k + 1][i]) { + dp[j][i].push_back(op_funcs[ops[k]](l, r)); + } + } + } + } + } + return dp[0][n - 1]; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + # re.split可以将操作符(\D)和数字直接分开。 + sections = re.split(r"(\D)", expression) + nums = [int(num) for num in sections if num.isdigit()] + ops = [op for op in sections if not op.isdigit()] + n = len(nums) + dp = [[[] for _ in range(n)] for _ in range(n)] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i in range(n): + for j in range(i, -1, -1): + if i == j: + dp[j][i].append(nums[i]) + continue + for k in range(j, i): + dp[j][i] += [op_funcs[ops[k]](l, r) + for l in dp[j][k] for r in dp[k + 1][i]] + + return dp[0][n - 1] + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/7-divide-and-conquer/7-3-exercises.md b/leetcode_101/docs/7-divide-and-conquer/7-3-exercises.md new file mode 100644 index 00000000..bc1968dd --- /dev/null +++ b/leetcode_101/docs/7-divide-and-conquer/7-3-exercises.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 37 +--- + +# 7.3 练习 + +## 基础难度 + +### [932. Beautiful Array](https://leetcode.com/problems/beautiful-array/) + +试着用从上到下的分治(递归)写法求解,最好加上 memoization;再用从下到上的动态规划写法求解。 + +--- + +## 进阶难度 + +### [312. Burst Balloons](https://leetcode.com/problems/burst-balloons/) + +试着用从上到下的分治(递归)写法求解,最好加上 memoization;再用从下到上的动态规划写法求解。 \ No newline at end of file diff --git a/leetcode_101/docs/7-divide-and-conquer/_category_.json b/leetcode_101/docs/7-divide-and-conquer/_category_.json new file mode 100644 index 00000000..2535d2d4 --- /dev/null +++ b/leetcode_101/docs/7-divide-and-conquer/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "7. 化繁为简的分治法", + "position": 7, + "link": { + "type": "generated-index", + "description": "第 7 章 化繁为简的分治法" + } +} diff --git a/leetcode_101/docs/8-mathematical-solutions/8-1-introduction.md b/leetcode_101/docs/8-mathematical-solutions/8-1-introduction.md new file mode 100644 index 00000000..d753971e --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 38 +--- + +# 8.1 引言 + +对于 LeetCode 上数量不少的数学题,我们尽量将其按照类型划分讲解。然而很多数学题的解法并不通用,我们也很难一口气把所有的套路讲清楚,因此我们只选择了几道经典或是典型的题目,供大家参考。 \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/8-2-lcm-gcd.mdx b/leetcode_101/docs/8-mathematical-solutions/8-2-lcm-gcd.mdx new file mode 100644 index 00000000..58dda1b8 --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-2-lcm-gcd.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 39 +--- + +# 8.2 公倍数与公因数 + +利用`辗转相除法`,我们可以很方便地求得两个数的最大公因数(greatest common divisor,GCD);将两个数相乘再除以最大公因数即可得到最小公倍数(least common multiple, LCM)。 + + + + + +```cpp +int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); +} + +int lcm(int a, int b) { + return a * b / gcd(a, b); +} +``` + + + + +```py +def gcd(a: int, b: int) -> int: + return a if b == 0 else gcd(b, a % b) + +def lcm(a: int, b: int) -> int: + return (a * b) // gcd(a, b) +``` + + + + + +进一步地,我们也可以通过扩展欧几里得算法(extended gcd)在求得 a 和 b 最大公因数的同时,也得到它们的系数 x 和 y,从而使 ax + by = gcd(a, b)。因为 Python 中 int 只能按值传递,我们可以用一个长度固定为 1 的 list() 来进行传递引用的操作。 + + + + +```cpp +int xGCD(int a, int b, int &x, int &y) { + if (b == 0) { + x = 1, y = 0; + return a; + } + int x_inner, y_inner; + int gcd = xGCD(b, a % b, x_inner, y_inner); + x = y_inner, y = x_inner - (a / b) * y_inner; + return gcd; +} +``` + + + + +```py +def xGCD(a: int, b: int, x: List[int], y: List[int]) -> int: + if b == 0: + x[0], y[0] = 1, 0 + return a + x_inner, y_inner = [0], [0] + gcd = xGCD(b, a % b, x_inner, y_inner) + x[0], y[0] = y_inner, x_inner - (a / b) * y_inner + return gcd +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/8-3-prime-numbers.mdx b/leetcode_101/docs/8-mathematical-solutions/8-3-prime-numbers.mdx new file mode 100644 index 00000000..fc8855f8 --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-3-prime-numbers.mdx @@ -0,0 +1,138 @@ +--- +sidebar_position: 40 +--- + +# 8.3 质数 + +质数又称素数,指的是指在大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的自然数。值得注意的是,每一个数都可以分解成质数的乘积。 + + +## [204. Count Primes](https://leetcode.com/problems/count-primes/) + +### 题目描述 + +给定一个数字 n,求小于 n 的质数的个数。 + +### 输入输出样例 + +输入一个整数,输出也是一个整数,表示小于输入数的质数的个数。 + +``` +Input: 10 +Output: 4 +``` + +在这个样例中,小于 10 的质数只有 [2,3,5,7]。 + +### 题解 + +`埃拉托斯特尼筛法`(Sieve of Eratosthenes,简称埃氏筛法)是非常常用的,判断一个整数是否是质数的方法。并且它可以在判断一个整数 n 时,同时判断所小于 n 的整数,因此非常适合这道题。其原理也十分易懂:从 1 到 n 遍历,假设当前遍历到 m,则把所有小于 n 的、且是 m 的倍数的整数标为和数;遍历完成后,没有被标为和数的数字即为质数。 + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int count = n - 2; // 去掉不是质数的1 + for (int i = 2; i < n; ++i) { + if (primes[i]) { + for (int j = 2 * i; j < n; j += i) { + if (primes[j]) { + primes[j] = false; + --count; + } + } + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + count = n - 2 # 去掉不是质数的1 + for i in range(2, n): + if primes[i]: + for j in range(2 * i, n, i): + if primes[j]: + primes[j] = False + count -= 1 + return count +``` + + + + + +利用质数的一些性质,我们可以进一步优化该算法。 + + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int sqrtn = sqrt(n); + int count = n / 2; // 偶数一定不是质数 + int i = 3; + // 最小质因子一定小于等于开方数。 + while (i <= sqrtn) { + // 向右找倍数,注意避免偶数和重复遍历。 + for (int j = i * i; j < n; j += 2 * i) { + if (primes[j]) { + --count; + primes[j] = false; + } + } + i += 2; + // 向右前进查找位置,注意避免偶数和重复遍历。 + while (i <= sqrtn && !primes[i]) { + i += 2; + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + sqrtn = sqrt(n) + count = n // 2 # 偶数一定不是质数 + i = 3 + # 最小质因子一定小于等于开方数。 + while i <= sqrtn: + # 向右找倍数,注意避免偶数和重复遍历。 + for j in range(i * i, n, 2 * i): + if primes[j]: + count -= 1 + primes[j] = False + i += 2 + # 向右前进查找位置,注意避免偶数和重复遍历。 + while i <= sqrtn and not primes[i]: + i += 2 + return count +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/8-4-number-processing.mdx b/leetcode_101/docs/8-mathematical-solutions/8-4-number-processing.mdx new file mode 100644 index 00000000..67853aa2 --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-4-number-processing.mdx @@ -0,0 +1,318 @@ +--- +sidebar_position: 41 +--- + +# 8.4 数字处理 + +## [504. Base 7](https://leetcode.com/problems/base-7/) + +### 题目描述 + +给定一个十进制整数,求它在七进制下的表示。 + +### 输入输出样例 + +输入一个整数,输出一个字符串,表示其七进制。 + +``` +Input: 100 +Output: "202" +``` + +在这个样例中,100 的七进制表示法来源于 101 = 2 * 49 + 0 * 7 + 2 * 1。 + +### 题解 + +`进制转换`类型的题,通常是利用除法和取模(mod)来进行计算,同时也要注意一些细节,如负数和零。如果输出是数字类型而非字符串,则也需要考虑是否会超出整数上下界。 + + + + +```cpp +string convertToBase7(int num) { + if (num == 0) { + return "0"; + } + string base7; + bool is_negative = num < 0; + num = abs(num); + while (num) { + int quotient = num / 7, remainder = num % 7; + base7 = to_string(remainder) + base7; + num = quotient; + } + return is_negative ? "-" + base7 : base7; +} +``` + + + + +```py +def convertToBase7(num: int) -> str: + if num == 0: + return "0" + base7 = "" + is_negative = num < 0 + num = abs(num) + while num: + quotient, remainder = num // 7, num % 7 + base7 = str(remainder) + base7 + num = quotient + return "-" + base7 if is_negative else base7 +``` + + + + + +## [172. Factorial Trailing Zeroes](https://leetcode.com/problems/factorial-trailing-zeroes/) + +### 题目描述 + +给定一个非负整数,判断它的阶乘结果的结尾有几个 0。 + +### 输入输出样例 + +输入一个非负整数,输出一个非负整数,表示输入的阶乘结果的结尾有几个 0。 + +``` +Input: 12 +Output: 2 +``` + +在这个样例中,12 != 479001600 的结尾有两个 0。 + +### 题解 + +每个尾部的 0 由 2 × 5 =10 而来,因此我们可以把阶乘的每一个元素拆成质数相乘,统计有多少个 2 和 5。明显的,质因子 2 的数量远多于质因子 5 的数量,因此我们可以只统计阶乘结果里有多少个质因子 5。 + + + + +```cpp +int trailingZeroes(int n) { + return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); +} +``` + + + + +```py +def trailingZeroes(n: int) -> int: + return 0 if n == 0 else n // 5 + trailingZeroes(n // 5) +``` + + + + + +## [415. Add Strings](https://leetcode.com/problems/add-strings/) + +### 题目描述 + +给定两个由数字组成的字符串,求它们相加的结果。 + +### 输入输出样例 + +输入是两个字符串,输出是一个整数,表示输入的数字和。 + +``` +Input: num1 = "99", num2 = "1" +Output: 100 +``` + +因为相加运算是从后往前进行的,所以可以先翻转字符串,再逐位计算。这种类型的题考察的是细节,如进位、位数差等等。 + +### 题解 + + + + + + +```cpp +string addStrings(string num1, string num2) { + string added_str; + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + int len1 = num1.length(), len2 = num2.length(); + if (len1 <= len2) { + swap(num1, num2); + swap(len1, len2); + } + int add_bit = 0; + for (int i = 0; i < len1; ++i) { + int cur_sum = + (num1[i] - ’0’) + (i < len2 ? num2[i] - ’0’ : 0) + add_bit; + added_str += to_string(cur_sum % 10); + add_bit = cur_sum >= 10; + } + if (add_bit) { + added_str += "1"; + } + reverse(added_str.begin(), added_str.end()); + return added_str; +} +``` + + + + +```py +def addStrings(num1: str, num2: str) -> str: + added_str = "" + num1 = num1[::-1] + num2 = num2[::-1] + len1, len2 = len(num1), len(num2) + if len1 <= len2: + num1, num2 = num2, num1 + len1, len2 = len2, len1 + add_bit = 0 + for i in range(len1): + cur_sum = int(num1[i]) + (int(num2[i]) if i < len2 else 0) + add_bit + added_str += str(cur_sum % 10) + add_bit = int(cur_sum >= 10) + if add_bit: + added_str += "1" + return added_str[::-1] +``` + + + + + + +## [326. Power of Three](https://leetcode.com/problems/power-of-three/) + +### 题目描述 + +判断一个数字是否是 3 的次方。 + +### 输入输出样例 + +输入一个整数,输出一个布尔值。 + +``` +Input: n = 27 +Output: true +``` + +### 题解 + +有两种方法,一种是利用对数。设 log3 n =m,如果 n 是 3 的整数次方,那么 m 一定是整数。 + + + + +```cpp +bool isPowerOfThree(int n) { + return fmod(log10(n) / log10(3), 1) == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + return n > 0 and math.fmod(math.log10(n) / math.log10(3), 1) == 0 +``` + + + + + +另一种方法是,因为在 C++ int 范围内 3 的最大次方是 $3^{19} = 1162261467$,如果 n 是 3 的整数次方,那么 1162261467 除以 n 的余数一定是零;反之亦然。然而对于 Python 来说,因为 int 理论上可以取无穷大,我们只能循环判断。 + + + + +```cpp +bool isPowerOfThree(int n) { + return n > 0 && 1162261467 % n == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + if n <= 0: + return False + while n % 3 == 0: + n //= 3 + return n == 1 +``` + + + + + +## [50. Pow(x, n)](https://leetcode.com/problems/powx-n/) + +### 题目描述 + +计算 x 的 n 次方。 + +### 输入输出样例 + +输入一个浮点数表示 x 和一个整数表示 n,输出一个浮点数表示次方结果。 + +``` +Input: x = 2.00000, n = 10 +Output: 1024.00000 +``` + +### 题解 + + +利用递归,我们可以较为轻松地解决本题。注意边界条件的处理。 + + + + +```cpp +double myPow(double x, int n) { + if (n == 0) { + return 1; + } + if (x == 0) { + return 0; + } + if (n == numeric_limits::min()) { + return 1 / (x * myPow(x, numeric_limits::max())); + } + if (n < 0) { + return 1 / myPow(x, -n); + } + if (n % 2 != 0) { + return x * myPow(x, n - 1); + } + double myPowSqrt = myPow(x, n >> 1); + return myPowSqrt * myPowSqrt; +} +``` + + + + +```py +def myPow(x: float, n: int) -> float: + if n == 0: + return 1 + if x == 0: + return 0 + if n < 0: + return 1 / myPow(x, -n) + if n % 2 != 0: + return x * myPow(x, n - 1) + myPowSqrt = myPow(x, n >> 1) + return myPowSqrt * myPowSqrt +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/8-5-random-sampling.mdx b/leetcode_101/docs/8-mathematical-solutions/8-5-random-sampling.mdx new file mode 100644 index 00000000..d2b4c716 --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-5-random-sampling.mdx @@ -0,0 +1,228 @@ +--- +sidebar_position: 42 +--- + +# 8.5 随机与取样 + +## [384. Shuffle an Array](https://leetcode.com/problems/shuffle-an-array/) + +### 题目描述 + +给定一个数组,要求实现两个指令函数。第一个函数“shuffle”可以随机打乱这个数组,第二个函数“reset”可以恢复原来的顺序。 + +### 输入输出样例 + +输入是一个存有整数数字的数组,和一个包含指令函数名称的数组。输出是一个二维数组,表示每个指令生成的数组。 + +``` +Input: nums = [1,2,3], actions: ["shuffle","shuffle","reset"] +Output: [[2,1,3],[3,2,1],[1,2,3]] +``` + +在这个样例中,前两次打乱的结果只要是随机生成即可。 + +### 题解 + +我们采用经典的 `Fisher-Yates 洗牌算法`,原理是通过随机交换位置来实现随机打乱,有正向和反向两种写法,且实现非常方便。注意这里“reset”函数以及 Solution 类的构造函数的实现细节。 + + + + +```cpp +class Solution { + public: + Solution(vector nums) : nums_(nums) {} + + vector reset() { return nums_; } + + vector shuffle() { + vector shuffled(nums_); + int n = nums_.size(); + // 可以使用反向或者正向洗牌,效果相同。 + // 反向洗牌: + for (int i = n - 1; i >= 0; --i) { + swap(shuffled[i], shuffled[rand() % (i + 1)]); + } + // 正向洗牌: + // for (int i = 0; i < n; ++i) { + // int pos = rand() % (n - i); + // swap(shuffled[i], shuffled[i+pos]); + // } + return shuffled; + } + + private: + vector nums_; +}; +``` + + + + +```py +class Solution: + def __init__(self, nums: List[int]): + self.base = nums[:] + + def reset(self) -> List[int]: + return self.base[:] + + def shuffle(self) -> List[int]: + shuffled = self.base[:] + n = len(self.base) + # 可以使用反向或者正向洗牌,效果相同。 + # 反向洗牌: + for i in range(n - 1, -1, -1): + j = random.randint(0, i) + shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + # 正向洗牌: + # for i in range(n): + # j = i + random.randint(0, n - i - 1) + # shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + return shuffled +``` + + + + + +## [528. Random Pick with Weight](https://leetcode.com/problems/random-pick-with-weight/) + +### 题目描述 + +给定一个数组,数组每个位置的值表示该位置的权重,要求按照权重的概率去随机采样。 + +### 输入输出样例 + +输入是一维正整数数组,表示权重;和一个包含指令字符串的一维数组,表示运行几次随机采样。输出是一维整数数组,表示随机采样的整数在数组中的位置。 + +``` +Input: weights = [1,3], actions: ["pickIndex","pickIndex","pickIndex"] +Output: [0,1,1] +``` + +在这个样例中,每次选择的位置都是不确定的,但选择第 0 个位置的期望为 1/4,选择第 1 个位置的期望为 3/4。 + +### 题解 + +我们可以先使用 partial_sum求前缀和(即到每个位置为止之前所有数字的和),这个结果对于正整数数组是单调递增的。每当需要采样时,我们可以先随机产生一个数字,然后使用二分法查找其在前缀和中的位置,以模拟加权采样的过程。这里的二分法可以用 lower_bound 实现。 + +以样例为例,权重数组 [1,3] 的前缀和为 [1,4]。如果我们随机生成的数字为 1,那么 lower_bound 返回的位置为 0;如果我们随机生成的数字是 2、3、4,那么 lower_bound 返回的位置为 1。 + +关于前缀和的更多技巧,我们将在接下来的章节中继续深入讲解。 + + + + +```cpp +class Solution { + public: + Solution(vector weights) : cumsum_(weights) { + partial_sum(cumsum_.begin(), cumsum_.end(), cumsum_.begin()); + } + + int pickIndex() { + int val = (rand() % cumsum_.back()) + 1; + return lower_bound(cumsum_.begin(), cumsum_.end(), val) - + cumsum_.begin(); + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class Solution: + def __init__(self, weights: List[int]): + self.cumsum = weights[:] + for i in range(1, len(weights)): + self.cumsum[i] += self.cumsum[i - 1] + + def pickIndex(self) -> int: + val = random.randint(1, self.cumsum[-1]) + return bisect.bisect_left(self.cumsum, val, 0, len(self.cumsum)) +``` + + + + + +## [382. Linked List Random Node](https://leetcode.com/problems/linked-list-random-node/) + +### 题目描述 + +给定一个单向链表,要求设计一个算法,可以随机取得其中的一个数字。 + +### 输入输出样例 + +输入是一个单向链表,输出是一个数字,表示链表里其中一个节点的值。 + +``` +Input: 1->2->3->4->5 +Output: 3 +``` + +在这个样例中,我们有均等的概率得到任意一个节点,比如 3。 + +### 题解 + +不同于数组,在未遍历完链表前,我们无法知道链表的总长度。这里我们就可以使用水库采样:遍历一次链表,在遍历到第 m 个节点时,有 $\frac{1}{m}$ 的概率选择这个节点覆盖掉之前的节点选择。 + +我们提供一个简单的,对于水库算法随机性的证明。对于长度为 n 的链表的第 m 个节点,最后被采样的充要条件是它被选择,且之后的节点都没有被选择。这种情况发生的概率为 $\frac{1}{m} × \frac{m}{m+1} × \frac{m}{m+2} × · · · × \frac{n−1}{n} = \frac{1}{n}$。因此每个点都有均等的概率被选择。 + +当然,这道题我们也可以预处理链表,遍历一遍之后把它转化成数组。 + + + + +```cpp +class Solution { + public: + Solution(ListNode* node) : head_(node) {} + + int getRandom() { + int pick = head_->val; + ListNode* node = head_->next; + int i = 2; + while (node) { + if (rand() % i == 0) { + pick = node->val; + } + ++i; + node = node->next; + } + return pick; + } + + private: + ListNode* head_; +}; +``` + + + + +```py +class Solution: + def __init__(self, head: Optional[ListNode]): + self.head = head + + def getRandom(self) -> int: + pick = self.head.val + node = self.head.next + i = 2 + while node is not None: + if random.randint(0, i - 1) == 0: + pick = node.val + i += 1 + node = node.next + return pick +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/8-6-exercises.md b/leetcode_101/docs/8-mathematical-solutions/8-6-exercises.md new file mode 100644 index 00000000..f68091ae --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/8-6-exercises.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 43 +--- + +# 8.6 练习 + +## 基础难度 + +### [168. Excel Sheet Column Title](https://leetcode.com/problems/excel-sheet-column-title/) + +7 进制转换的变种题,需要注意的一点是从 1 开始而不是 0。 + +--- + +### [67. Add Binary](https://leetcode.com/problems/add-binary/) + +字符串加法的变种题。 + +--- + +### [238. Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) + +你可以不使用除法做这道题吗?我们很早之前讲过的题目 135 或许能给你一些思路。 + +--- + +## 进阶难度 + +### [462. Minimum Moves to Equal Array Elements II](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/) + +这道题是笔者最喜欢的 LeetCode 题目之一,需要先推理出怎么样移动是最优的,再考虑如何进行移动。你或许需要一些前些章节讲过的算法。 + +--- + +### [169. Majority Element](https://leetcode.com/problems/majority-element/) + +如果想不出简单的解决方法,搜索一下 Boyer-Moore Majority Vote 算法吧。 + +--- + +### [470. Implement Rand10() Using Rand7()](https://leetcode.com/problems/implement-rand10-using-rand7/) + +如何用一个随机数生成器生成另一个随机数生成器?你可能需要利用原来的生成器多次。 + +--- + +### [202. Happy Number](https://leetcode.com/problems/happy-number/) + +你可以简单的用一个 while 循环解决这道题,但是有没有更好的解决办法?如果我们把每个数字想象成一个节点,是否可以转化为环路检测? \ No newline at end of file diff --git a/leetcode_101/docs/8-mathematical-solutions/_category_.json b/leetcode_101/docs/8-mathematical-solutions/_category_.json new file mode 100644 index 00000000..2d1586cc --- /dev/null +++ b/leetcode_101/docs/8-mathematical-solutions/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "8. 巧解数学问题", + "position": 8, + "link": { + "type": "generated-index", + "description": "第 8 章 巧解数学问题" + } +} diff --git a/leetcode_101/docs/9-bitwise-operations/9-1-common-techniques.md b/leetcode_101/docs/9-bitwise-operations/9-1-common-techniques.md new file mode 100644 index 00000000..30f955ca --- /dev/null +++ b/leetcode_101/docs/9-bitwise-operations/9-1-common-techniques.md @@ -0,0 +1,24 @@ +--- +sidebar_position: 44 +--- + +# 9.1 常用技巧 + +`位运算`是算法题里比较特殊的一种类型,它们利用二进制位运算的特性进行一些奇妙的优化和计算。常用的位运算符号包括: + +- `∧`:按位异或 +- `&`:按位与 +- `|`:按位或 +- `~`:取反 +- `<<`:算术左移 +- `>>`:算术右移 + +以下是一些常见的位运算特性,其中 `0s` 和 `1s` 分别表示只由 `0` 或 `1` 构成的二进制数字。 + +``` +x ^ 0s = x x & 0s = 0 x | 0s = x +x ^ 1s = ~x x & 1s = x x | 1s = 1s +x ^ x = 0 x & x = x x | x = x +``` + +除此之外,n & (n - 1) 可以去除 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,减去 1 得到 11110011,这两个数按位与得到 11110000。n & (-n) 可以得到 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,取负得到 00001100,这两个数按位与得到 00000100。还有更多的并不常用的技巧,若读者感兴趣可以自行研究,这里不再赘述。 \ No newline at end of file diff --git a/leetcode_101/docs/9-bitwise-operations/9-2-basic-bitwise-problems.mdx b/leetcode_101/docs/9-bitwise-operations/9-2-basic-bitwise-problems.mdx new file mode 100644 index 00000000..743a16ac --- /dev/null +++ b/leetcode_101/docs/9-bitwise-operations/9-2-basic-bitwise-problems.mdx @@ -0,0 +1,181 @@ +--- +sidebar_position: 45 +--- + +# 9.2 位运算基础问题 + +## [461. Hamming Distance](https://leetcode.com/problems/hamming-distance/) + +### 题目描述 + +给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。 + +### 输入输出样例 + +输入是两个十进制整数,输出是一个十进制整数,表示两个输入数字的汉明距离。 + +``` +Input: x = 1, y = 4 +Output: 2 +``` + +在这个样例中,1 的二进制是 0001,4 的二进制是 0100,一共有两位不同。 + +### 题解 + +对两个数进行按位异或操作,统计有多少个 1 即可。 + + + + +```cpp +int hammingDistance(int x, int y) { + int diff = x ^ y, dist = 0; + while (diff != 0) { + dist += diff & 1; + diff >>= 1; + } + return dist; +} +``` + + + + +```py +def hammingDistance(x: int, y: int) -> int: + diff = x ^ y + dist = 0 + while diff != 0: + dist += diff & 1 + diff = diff >> 1 + return dist +``` + + + + + +## [190. Reverse Bits](https://leetcode.com/problems/reverse-bits/) + +### 题目描述 + +给定一个十进制正整数,输出它在二进制下的翻转结果。 + +### 输入输出样例 + +输入和输出都是十进制正整数。 + +``` +Input: 43261596 (00000010100101000001111010011100) +Output: 964176192 (00111001011110000010100101000000) +``` + +使用算术左移和右移,可以很轻易地实现二进制的翻转。 + +### 题解 + + + + + + +```cpp +uint32_t reverseBits(uint32_t n) { + uint32_t m = 0; + for (int i = 0; i < 32; ++i) { + m <<= 1; + m += n & 1; + n >>= 1; + } + return m; +} +``` + + + + +```py +def reverseBits(n: int) -> int: + m = 0 + for _ in range(32): + m = m << 1 + m += n & 1 + n = n >> 1 + return m +``` + + + + + +## [136. Single Number](https://leetcode.com/problems/single-number/) + +### 题目描述 + +给定一个整数数组,这个数组里只有一个数次出现了一次,其余数字出现了两次,求这个只出现一次的数字。 + +### 输入输出样例 + +输入是一个一维整数数组,输出是该数组内的一个整数。 + +``` +Input: [4,1,2,1,2] +Output: 4 +``` + +### 题解 + +我们可以利用 x ∧ x = 0 和 x ∧ 0 = x 的特点,将数组内所有的数字进行按位异或。出现两次的所有数字按位异或的结果是 0,0 与出现一次的数字异或可以得到这个数字本身。 + + + + +```cpp +int singleNumber(vector& nums) { + int single = 0; + for (int num : nums) { + single ^= num; + } + return single; +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + single = 0 + for num in nums: + single = single ^ num + return single +``` + + + + + +这里我们也可以直接使用 reduce 函数: + + + + +```cpp +int singleNumber(vector& nums) { + return reduce(nums.begin(), nums.end(), 0, + [](int x, int y) { return x ^ y; }); +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + return functools.reduce(lambda x, y: x ^ y, nums) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/9-bitwise-operations/9-3-binary-properties.mdx b/leetcode_101/docs/9-bitwise-operations/9-3-binary-properties.mdx new file mode 100644 index 00000000..51d3b410 --- /dev/null +++ b/leetcode_101/docs/9-bitwise-operations/9-3-binary-properties.mdx @@ -0,0 +1,123 @@ +--- +sidebar_position: 46 +--- + +# 9.3 二进制特性 + +利用二进制的一些特性,我们可以把位运算使用到更多问题上。 + +例如,我们可以利用二进制和位运算输出一个数组的所有子集。假设我们有一个长度为 $n$ 的数组,我们可以生成长度为 $n$ 的所有二进制,1 表示选取该数字,0 表示不选取。这样我们就获得了 $2^n$ 个子集。 + +## [318. Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/) + +### 题目描述 + +给定多个字母串,求其中任意两个字母串的长度乘积的最大值,且这两个字母串不能含有相同字母。 + +### 输入输出样例 + +输入一个包含多个字母串的一维数组,输出一个整数,表示长度乘积的最大值。 + +``` +Input: ["a","ab","abc","d","cd","bcd","abcd"] +Output: 4 +``` + +在这个样例中,一种最优的选择是“ab”和“cd”。 + +### 题解 + +怎样快速判断两个字母串是否含有重复数字呢?可以为每个字母串建立一个长度为 26 的二进制数字,每个位置表示是否存在该字母。如果两个字母串含有重复数字,那它们的二进制表示的按位与不为 0。同时,我们可以建立一个哈希表来存储二进制数字到最长子母串长度的映射关系,比如 ab 和 aab 的二进制数字相同,但是 aab 更长。 + + + + +```cpp +int maxProduct(vector& words) { + unordered_map cache; + int max_prod = 0; + for (const string& word : words) { + int mask = 0, w_len = word.length(); + for (char c : word) { + mask |= 1 << (c - ’a’); + } + cache[mask] = max(cache[mask], w_len); + for (auto [h_mask, h_len] : cache) { + if ((mask & h_mask) == 0) { + max_prod = max(max_prod, w_len * h_len); + } + } + } + return max_prod; +} +``` + + + + +```py +def maxProduct(words: List[str]) -> int: + cache = dict() + max_prod = 0 + for word in words: + mask, w_len = 0, len(word) + for c in word: + mask = mask | (1 << (ord(c) - ord("a"))) + cache[mask] = max(cache.get(mask, 0), w_len) + for h_mask, h_len in cache.items(): + if (mask & h_mask) == 0: + max_prod = max(max_prod, w_len * h_len) + return max_prod +``` + + + + + +## [338. Counting Bits](https://leetcode.com/problems/counting-bits/) + +### 题目描述 + +给定一个非负整数 n,求从 0 到 n 的所有数字的二进制表达中,分别有多少个 1。 + +### 输入输出样例 + +输入是一个非负整数 n,输出是长度为 n +1 的非负整数数组,每个位置 m 表示 m 的二进制里有多少个 1。 + +``` +Input: 5 +Output: [0,1,1,2,1,2] +``` + +### 题解 + +本题可以利用动态规划和位运算进行快速的求解。定义一个数组 dp,其中 dp[i] 表示数字 i 的二进制含有 1 的个数。对于第 i 个数字,如果它二进制的最后一位为 1,那么它含有 1 的个数则为 dp[i-1] + 1;如果它二进制的最后一位为 0,那么它含有 1 的个数和其算术右移结果相同,即 dp[i>>1]。 + + + + +```cpp +vector countBits(int n) { + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) + // 等价于:dp[i] = dp[i & (i - 1)] + 1; + dp[i] = i & 1 ? dp[i - 1] + 1 : dp[i >> 1]; + return dp; +} +``` + + + + +```py +def countBits(n: int) -> List[int]: + dp = [0] * (n + 1) + for i in range(1, n + 1): + # 等价于:dp[i] = dp[i & (i - 1)] + 1 + dp[i] = dp[i - 1] + 1 if i & 1 else dp[i >> 1] + return dp +``` + + + + \ No newline at end of file diff --git a/leetcode_101/docs/9-bitwise-operations/9-4-exercises.md b/leetcode_101/docs/9-bitwise-operations/9-4-exercises.md new file mode 100644 index 00000000..244cacb2 --- /dev/null +++ b/leetcode_101/docs/9-bitwise-operations/9-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 47 +--- + +# 9.4 练习 + +## 基础难度 + +### [268. Missing Number](https://leetcode.com/problems/missing-number/) + +Single Number 的变种题。除了利用二进制,也可以使用高斯求和公式。 + +--- + +### [693. Binary Number with Alternating Bits](https://leetcode.com/problems/binary-number-with-alternating-bits/) + +利用位运算判断一个数的二进制是否会出现连续的 0 和 1。 + +--- + +### [476. Number Complement](https://leetcode.com/problems/number-complement/) + +二进制翻转的变种题。 + +--- + +## 进阶难度 + +### [260. Single Number III](https://leetcode.com/problems/single-number-iii/) + +Single Number 的 follow-up,需要认真思考如何运用位运算求解。 \ No newline at end of file diff --git a/leetcode_101/docs/9-bitwise-operations/_category_.json b/leetcode_101/docs/9-bitwise-operations/_category_.json new file mode 100644 index 00000000..0f6be05e --- /dev/null +++ b/leetcode_101/docs/9-bitwise-operations/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "9. 神奇的位运算", + "position": 9, + "link": { + "type": "generated-index", + "description": "第 9 章 神奇的位运算" + } +} diff --git a/leetcode_101/docs/acknowledgments.md b/leetcode_101/docs/acknowledgments.md new file mode 100644 index 00000000..8dca8d96 --- /dev/null +++ b/leetcode_101/docs/acknowledgments.md @@ -0,0 +1,16 @@ +--- +sidebar_position: 79 +--- + +# 鸣谢名单 + +## 官方唯一指定最强王者赞助 +Yudi Zhang + +## 友情赞助 +排名不分先后:Yujia Chen、Chaoyu Wang、Chunyan Bai、Haoshuo Huang、Wenting Ye、Yuting Wang、Bill Liu、Zhiyu Min、Xuyang Cheng、Keyi Xian、Yihan Zhang、Rui Yan、Mao Cheng、Michael +Wang 等。 + +## GitHub 用户 + +排名不分先后:quweikoala、szlghl1、mag1cianag、woodpenker、yangCoder96、cluckl、shaoshuai-luo、KivenGood、alicegong、hitYunhongXu、shengchen1998、jihchi、hapoyige、hitYunhongXu、h82258652、conan81412B、Mirrorigin、Light-young、XiangYG、xnervwang、sabaizzz、PhoenixChen98、zhang-wang997、corbg118、tracyqwerty、yorhaha、DeckardZ46、Ricardo-609、namu-guwal、hkulyc、jacklanda、View0、HelloYJohn、Corezcy、MoyuST、lutengda、fengshansi 等。 \ No newline at end of file diff --git a/leetcode_101/docs/index.md b/leetcode_101/docs/index.md new file mode 100644 index 00000000..b8b869c5 --- /dev/null +++ b/leetcode_101/docs/index.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 0 +--- + +# LeetCode 101: 力扣刷题指南 (第二版) + +![](https://github.com/changgyhub/leetcode_101/blob/master/misc/cover.jpg?raw=true) + +作者:高畅 Chang Gao + +语言:C++ & Python + +版本:正式版 2.0c,最新版见 GitHub [changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +:::info +一个面向有一定的编程基础,但缺乏刷题经验的读者的教科书和工具书。 +::: + +## 序 + +2019 年底,本书第一版在 GitHub 上正式发布,反响十分热烈。过去的五年,作者积累了大量的工作经验,同时也越来越觉得这本书存在很多纰漏和不完善之处。于是在 2024 年底,作者重新整理了本书的内容,发布了第二版。 + +本书分为算法、数学和数据结构三大部分,包含十五个章节,详细讲解了刷 LeetCode 时常用的技巧。在第一版时,为了强行呼应 "101"(在英文里是入门的意思),作者把题目精简到了 101 道。但现如今面试中可能考察的题型越来越多,所以第二版增加了一些重点题目,方便读者查漏补缺。选题时作者尽量兼顾题目在面试中可能出现的频率、易学性和泛用性。每个章节之后都附带了练习题,作者十分推荐读者在学习完每个章节之后使用这些练习题巩固理解。 + +本书所有常规题目均附有 C++ 和 Python3 题解。由于本书的目的不是学习 C++ 和 Python 语言,作者在行文时不会过多解释语法细节,而且会适当使用一些新 C++ 标准的语法和 Pythonic code。截止 2024 年底,所有的书内代码在 LeetCode 上都是可以正常运行的,并且在保持易读的基础上,几乎都是最快或最省空间的解法。 + +请谨记,刷题只是提高面试乃至工作能力的一小部分。在计算机科学的海洋里,值得探索的东西太多,并不建议您花过多时间刷题。并且要成为一个优秀的计算机科学家,刷题只是入职的敲门砖,提高各种专业技能、打好专业基础、以及了解最新的专业方向或许更加重要。 + +本书是作者本人于闲余时间完成的,可能会有不少纰漏,部分题目的解释可能也存在不详细或者不清楚的情况。欢迎在 GitHub 提 issue 指正,作者会将您加入鸣谢名单(见后记)。另外,如果您有任何建议和咨询,欢迎前往作者的个人网站联系作者。如果需要私信,请通过邮箱或领英发送消息,作者会尽快回复。 + +感谢 GitHub 用户 CyC2018 的 LeetCode 题解,它对于作者早期的整理起到了很大的帮助作用。感谢 ElegantBook 提供的精美 LATEX 模版,使得作者可以轻松地把笔记变成看起来更专业的电子书。另外,第二版书的封面图片是作者于 2024 年 7 月,在旧金山金门大桥北的 Sausalito 小镇海边拍摄。当时还买了一筒三球超大份冰淇淋,可惜实在是太甜了,吃了几口实在是吃不下去,只能扔掉。 + +如果您觉得这本书对您有帮助,不妨打赏一下作者哟! + + + +## 重要声明 + +本书 GitHub 地址:[github.com/changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +由于本书的目的是分享和教学,本书永久免费,也禁止任何营利性利用。欢迎以学术为目的的分享和传阅。由于作者不对 LeetCode 的任何题目拥有版权,一切题目版权以 LeetCode 官方为准,且本书不会展示 LeetCode 付费会员专享题目的内容或相关代码。 + +## 简介 + +打开 LeetCode 网站,如果我们按照题目类型数量分类,最多的几个题型包括数组、动态规划、数学、字符串、树、哈希表、深度优先搜索、二分查找、贪心算法、广度优先搜索、双指针等等。本书将包括上述题型以及网站上绝大多数流行的题型,在按照类型进行分类的同时,也按 +照难易程度进行由浅入深的讲解。 + +第一个大分类是算法。本书先从最简单的贪心算法讲起,然后逐渐进阶到双指针、二分查找、排序算法和搜索算法,最后是难度比较高的动态规划和分治算法。 + +第二个大分类是数学,包括偏向纯数学的数学问题,和偏向计算机知识的位运算问题。这类问题通常用来测试你是否聪敏,实际工作中并不常用,笔者建议可以优先把精力放在其它大类。 + +第三个大分类是数据结构,包括 C++ STL、Python3 自带的数据结构、字符串处理、链表、树和图。其中,链表、树、和图都是用指针表示的数据结构,且前者是后者的子集。最后我们也将介绍一些更加复杂的数据结构,比如经典的并查集和 LRU。 diff --git a/leetcode_101/docusaurus.config.ts b/leetcode_101/docusaurus.config.ts new file mode 100644 index 00000000..f3241be9 --- /dev/null +++ b/leetcode_101/docusaurus.config.ts @@ -0,0 +1,164 @@ +import { themes as prismThemes } from "prism-react-renderer"; +import remarkMath from 'remark-math'; +import rehypeKatex from 'rehype-katex'; +import localSearchPlugin from '@easyops-cn/docusaurus-search-local'; +import type { Config } from "@docusaurus/types"; +import type * as Preset from "@docusaurus/preset-classic"; + +// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) + +const config: Config = { + title: "LeetCode 101 - A Grinding Guide", + tagline: "LeetCode", + favicon: "img/logo.png", + + // Set the production url of your site here + url: "https://noworneverev.github.io/", + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: "/leetcode_101/", + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: "noworneverev", // Usually your GitHub org/user name. + projectName: "leetcode_101", // Usually your repo name. + + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: "zh-CN", + locales: ["en", "zh-TW", "zh-CN"], + localeConfigs: { + en: { + label: "English", + }, + "zh-TW": { + label: "繁體中文", + }, + "zh-CN": { + label: "简体中文", + }, + }, + }, + + presets: [ + [ + "classic", + { + docs: { + routeBasePath: "/", + sidebarPath: "./sidebars.ts", + remarkPlugins: [remarkMath], + rehypePlugins: [rehypeKatex], + }, + blog: false, + theme: { + customCss: "./src/css/custom.css", + }, + } satisfies Preset.Options, + ], + ], + themes: [ + [ + localSearchPlugin, + { + hashed: true, // Ensures search indexes are hashed for cache busting + language: ['en', 'zh'], // Add languages as needed, e.g., ['en', 'zh'] + docsRouteBasePath: '/', + indexDocs: true, + indexBlog: false, + }, + ], + ], + stylesheets: [ + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: + 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', + }, + ], + themeConfig: { + docs: { + sidebar: { + hideable: true, + }, + }, + // Replace with your project's social card + image: "img/docusaurus-social-card.jpg", + navbar: { + title: "LeetCode 101 - A Grinding Guide", + logo: { + alt: "My Site Logo", + src: "img/logo.png", + }, + items: [ + { + type: "localeDropdown", + position: "right", + }, + { + href: "https://github.com/changgyhub/leetcode_101", + label: "GitHub", + position: "right", + }, + ], + }, + footer: { + style: "dark", + // links: [ + // { + // title: "Docs", + // items: [ + // { + // label: "Tutorial", + // to: "/docs/intro", + // }, + // ], + // }, + // { + // title: "Community", + // items: [ + // { + // label: "Stack Overflow", + // href: "https://stackoverflow.com/questions/tagged/docusaurus", + // }, + // { + // label: "Discord", + // href: "https://discordapp.com/invite/docusaurus", + // }, + // { + // label: "X", + // href: "https://x.com/docusaurus", + // }, + // ], + // }, + // { + // title: "More", + // items: [ + // { + // label: "Blog", + // to: "/blog", + // }, + // { + // label: "GitHub", + // href: "https://github.com/facebook/docusaurus", + // }, + // ], + // }, + // ], + copyright: `Copyright © ${new Date().getFullYear()} Chang Gao. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.vsDark, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/leetcode_101/i18n/en/code.json b/leetcode_101/i18n/en/code.json new file mode 100644 index 00000000..a6d25b92 --- /dev/null +++ b/leetcode_101/i18n/en/code.json @@ -0,0 +1,313 @@ +{ + "theme.ErrorPageContent.title": { + "message": "This page crashed.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll back to top", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archive", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archive", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Blog list page navigation", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Newer entries", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Older entries", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Blog post page navigation", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Newer post", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Older post", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.tags.tagsPageLink": { + "message": "View all tags", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "Switch between dark and light mode (currently {mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "dark mode", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "light mode", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription.plurals": { + "message": "1 item|{count} items", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Docs pages", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Previous", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Next", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "One doc tagged|{count} docs tagged", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} with \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Version: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "latest version", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Edit this page", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link to {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " on {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " by {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Last updated{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versions", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.NotFound.title": { + "message": "Page Not Found", + "description": "The title of the 404 page" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.admonition.caution": { + "message": "caution", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "danger", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "note", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "warning", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Close", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Blog recent posts navigation", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "Copied", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Copy code to clipboard", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "Copy", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Toggle word wrap", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "Expand sidebar category '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "Collapse sidebar category '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Languages", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.NotFound.p1": { + "message": "We could not find what you were looking for.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "On this page", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Read more", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Read more about {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "One min read|{readingTime} min read", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "Home page", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Collapse sidebar", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs sidebar", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Back to main menu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Toggle navigation bar", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Expand sidebar", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.blog.post.plurals": { + "message": "One post|{count} posts", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} tagged with \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.blog.author.pageTitle": { + "message": "{authorName} - {nPosts}", + "description": "The title of the page for a blog author" + }, + "theme.blog.authorsList.pageTitle": { + "message": "Authors", + "description": "The title of the authors page" + }, + "theme.blog.authorsList.viewAll": { + "message": "View all authors", + "description": "The label of the link targeting the blog authors page" + }, + "theme.blog.author.noPosts": { + "message": "This author has not written any posts yet.", + "description": "The text for authors with 0 blog post" + }, + "theme.contentVisibility.unlistedBanner.title": { + "message": "Unlisted page", + "description": "The unlisted content banner title" + }, + "theme.contentVisibility.unlistedBanner.message": { + "message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "description": "The unlisted content banner message" + }, + "theme.contentVisibility.draftBanner.title": { + "message": "Draft page", + "description": "The draft content banner title" + }, + "theme.contentVisibility.draftBanner.message": { + "message": "This page is a draft. It will only be visible in dev and be excluded from the production build.", + "description": "The draft content banner message" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Try again", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Skip to main content", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..98a9eb63 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,126 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.tutorialSidebar.category.1. 最易懂的贪心算法": { + "message": "1. The Easiest Greedy Algorithm", + "description": "The label for category 1. 最易懂的贪心算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.1. 最易懂的贪心算法.link.generated-index.description": { + "message": "Chapter 1: The Easiest Greedy Algorithm", + "description": "The generated-index page description for category 1. 最易懂的贪心算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.2. 玩转双指针": { + "message": "2. Mastering Two Pointers", + "description": "The label for category 2. 玩转双指针 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.2. 玩转双指针.link.generated-index.description": { + "message": "Chapter 2: Mastering Two Pointers", + "description": "The generated-index page description for category 2. 玩转双指针 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.3. 居合斩!二分查找": { + "message": "3. Iaido! Binary Search", + "description": "The label for category 3. 居合斩!二分查找 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.3. 居合斩!二分查找.link.generated-index.description": { + "message": "Chapter 3: Iaido! Binary Search", + "description": "The generated-index page description for category 3. 居合斩!二分查找 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.4. 千奇百怪的排序算法": { + "message": "4. Peculiar Sorting Algorithms", + "description": "The label for category 4. 千奇百怪的排序算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.4. 千奇百怪的排序算法.link.generated-index.description": { + "message": "Chapter 4: Peculiar Sorting Algorithms", + "description": "The generated-index page description for category 4. 千奇百怪的排序算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.5. 一切皆可搜索": { + "message": "5. Everything is Searchable", + "description": "The label for category 5. 一切皆可搜索 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.5. 一切皆可搜索.link.generated-index.description": { + "message": "Chapter 5: Everything is Searchable", + "description": "The generated-index page description for category 5. 一切皆可搜索 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.6. 深入浅出动态规划": { + "message": "6. Dynamic Programming Made Simple", + "description": "The label for category 6. 深入浅出动态规划 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.6. 深入浅出动态规划.link.generated-index.description": { + "message": "Chapter 6: Dynamic Programming Made Simple", + "description": "The generated-index page description for category 6. 深入浅出动态规划 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.7. 化繁为简的分治法": { + "message": "7. Simplifying with Divide and Conquer", + "description": "The label for category 7. 化繁为简的分治法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.7. 化繁为简的分治法.link.generated-index.description": { + "message": "Chapter 7: Simplifying with Divide and Conquer", + "description": "The generated-index page description for category 7. 化繁为简的分治法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.8. 巧解数学问题": { + "message": "8. Clever Math Problem Solving", + "description": "The label for category 8. 巧解数学问题 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.8. 巧解数学问题.link.generated-index.description": { + "message": "Chapter 8: Clever Math Problem Solving", + "description": "The generated-index page description for category 8. 巧解数学问题 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.9. 神奇的位运算": { + "message": "9. Magical Bit Manipulation", + "description": "The label for category 9. 神奇的位运算 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.9. 神奇的位运算.link.generated-index.description": { + "message": "Chapter 9: Magical Bit Manipulation", + "description": "The generated-index page description for category 9. 神奇的位运算 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.10. 妙用数据结构": { + "message": "10. Ingenious Use of Data Structures", + "description": "The label for category 10. 妙用数据结构 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.10. 妙用数据结构.link.generated-index.description": { + "message": "Chapter 10: Ingenious Use of Data Structures", + "description": "The generated-index page description for category 10. 妙用数据结构 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.11. 令人头大的字符串": { + "message": "11. Tricky String Problems", + "description": "The label for category 11. 令人头大的字符串 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.11. 令人头大的字符串.link.generated-index.description": { + "message": "Chapter 11: Tricky String Problems", + "description": "The generated-index page description for category 11. 令人头大的字符串 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.12. 指针三剑客之一:链表": { + "message": "12. The Three Musketeers of Pointers: Linked Lists", + "description": "The label for category 12. 指针三剑客之一:链表 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.12. 指针三剑客之一:链表.link.generated-index.description": { + "message": "Chapter 12: The Three Musketeers of Pointers: Linked Lists", + "description": "The generated-index page description for category 12. 指针三剑客之一:链表 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.13. 指针三剑客之二:树": { + "message": "13. The Three Musketeers of Pointers: Trees", + "description": "The label for category 13. 指针三剑客之二:树 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.13. 指针三剑客之二:树.link.generated-index.description": { + "message": "Chapter 13: The Three Musketeers of Pointers: Trees", + "description": "The generated-index page description for category 13. 指针三剑客之二:树 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.14. 指针三剑客之三:图": { + "message": "14. The Three Musketeers of Pointers: Graphs", + "description": "The label for category 14. 指针三剑客之三:图 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.14. 指针三剑客之三:图.link.generated-index.description": { + "message": "Chapter 14: The Three Musketeers of Pointers: Graphs", + "description": "The generated-index page description for category 14. 指针三剑客之三:图 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.15. 更加复杂的数据结构": { + "message": "15. More Complex Data Structures", + "description": "The label for category 15. 更加复杂的数据结构 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.15. 更加复杂的数据结构.link.generated-index.description": { + "message": "Chapter 15: More Complex Data Structures", + "description": "The generated-index page description for category 15. 更加复杂的数据结构 in sidebar tutorialSidebar" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md new file mode 100644 index 00000000..fdd5acb0 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 1 +--- + +# 1.1 Algorithm Explanation + +As the name implies, a `greedy algorithm or greedy strategy` adopts a greedy approach, `ensuring that each step is locally optimal`, thereby resulting in a `globally optimal` solution. + +Let’s take the simplest example: Xiaoming and Xiaowang love apples. Xiaoming can eat five, and Xiaowang can eat three. Given that the orchard has an unlimited supply of apples, calculate the maximum number of apples Xiaoming and Xiaowang can eat together. In this example, the greedy strategy is for each person to eat the maximum number of apples they can. This strategy is locally optimal for each person. Since the global result is the simple sum of local results, and the local results are independent of each other, the locally optimal strategy is also globally optimal. + +Proving that a problem can be solved using a greedy algorithm is sometimes far more complex than actually solving it with the greedy algorithm. Generally, we use greedy algorithms when, after simple operations, there is a clear recursive relationship from local to global, or when the result can be deduced using mathematical induction. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx new file mode 100644 index 00000000..69f20bcf --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx @@ -0,0 +1,146 @@ +--- +sidebar_position: 2 +--- + +# 1.2 Distribution Problem + +## [455. Assign Cookies](https://leetcode.com/problems/assign-cookies/) + +### Problem Description + +There is a group of children and a pile of cookies. Each child has a hunger level, and each cookie has a fullness level. Each child can only eat one cookie, and only if the cookie's fullness level is greater than or equal to the child's hunger level can the child be satisfied. Find the maximum number of children that can be satisfied. + + +### Input and Output Example + +Input two arrays representing the hunger levels of the children and the fullness levels of the cookies. Output the maximum number of children that can be satisfied. + + +``` +Input: [1,2], [1,2,3] +Output: 2 +``` + +In this example, we can feed the two children with any of the combinations [1,2], [1,3], or [2,3]. + + +### Solution Explanation + +Since the child with the lowest hunger level is the easiest to satisfy, we start with this child. To make sure the remaining cookies can satisfy children with higher hunger levels, we should give this child the smallest cookie that meets or exceeds their hunger level. After satisfying this child, we repeat the strategy for the next hungriest child until there are no suitable cookies left. + +In short, the greedy strategy here is to allocate the smallest sufficient cookie to the child with the smallest hunger level among the remaining children. For implementation, since we need to compare sizes, a convenient method is to sort the children and cookies separately. This way, we can start from the child with the smallest hunger and the cookie with the smallest fullness, counting how many pairs meet the requirements. + +:::warning + +Sorting arrays or strings is a common operation to facilitate subsequent size comparisons. The default sorting order is ascending. + +::: + +:::warning + +In later explanations, when we discuss operations on variables in continuous spaces, we will not explicitly distinguish between arrays and strings, as they are essentially ordered sets of variables in continuous space. A string "abc" can be viewed as an array ['a', 'b', 'c']. + +::: + + + + +```cpp +int findContentChildren(vector &children, vector &cookies) { + sort(children.begin(), children.end()); + sort(cookies.begin(), cookies.end()); + int child_i = 0, cookie_i = 0; + int n_children = children.size(), n_cookies = cookies.size(); + while (child_i < n_children && cookie_i < n_cookies) { + if (children[child_i] <= cookies[cookie_i]) { + ++child_i; + } + ++cookie_i; + } + return child_i; +} +``` + + + + +```py +def findContentChildren(children: List[int], cookies: List[int]) -> int: + children.sort() + cookies.sort() + child_i, cookie_i = 0, 0 + n_children, n_cookies = len(children), len(cookies) + while child_i < n_children and cookie_i < n_cookies: + if children[child_i] <= cookies[cookie_i]: + child_i += 1 + cookie_i += 1 + return child_i +``` + + + + + +## [135. Candy](https://leetcode.com/problems/candy/) + +### Problem Description + +A group of children is standing in a row, and each child has a rating. We need to distribute candies to these children, with the rule that if a child has a higher rating than their neighbor, they must receive more candies than that neighbor. Every child must receive at least one candy. Find the minimum number of candies needed. + +### Input and Output Example + +The input is an array representing the ratings of the children. The output is the minimum number of candies required. + +``` +Input: [1,0,2] +Output: 5 +``` +In this example, the minimum distribution of candies is [2,1,2]. + + +### Solution Explanation + +A greedy strategy involving comparative relationships does not always require sorting. Although this problem also uses a greedy strategy, we only need two simple traversals: initialize each child’s candy count to 1; first traverse from left to right, and if a child’s rating is higher than the left neighbor, update the child’s candy count to be one more than the neighbor’s; then traverse from right to left, and if a child’s rating is higher than the right neighbor’s, and the current candy count is not greater than the neighbor’s, update the candy count to be one more than the neighbor’s. With these two passes, the candy distribution will meet the requirements. The greedy strategy here is to consider and update only the relationship with the adjacent side in each pass. + +In the example, we initialize the candy distribution as [1,1,1]. After the first traversal, the result is [1,1,2]. After the second traversal, the result is [2,1,2]. + + + + +```cpp +int candy(vector& ratings) { + int n = ratings.size(); + vector candies(n, 1); + for (int i = 1; i < n; ++i) { + if (ratings[i] > ratings[i - 1]) { + candies[i] = candies[i - 1] + 1; + } + } + for (int i = n - 1; i > 0; --i) { + if (ratings[i] < ratings[i - 1]) { + candies[i - 1] = max(candies[i - 1], candies[i] + 1); + } + } + return accumulate(candies.begin(), candies.end(), 0); +} +``` + + + + +```py +def candy(ratings_list: List[int]) -> int: + n = len(ratings_list) + candies = [1] * n + for i in range(1, n): + if ratings_list[i] > ratings_list[i - 1]: + candies[i] = candies[i - 1] + 1 + for i in range(n - 1, 0, -1): + if ratings_list[i] < ratings_list[i - 1]: + candies[i - 1] = max(candies[i - 1], candies[i] + 1) + return sum(candies) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx new file mode 100644 index 00000000..db7b0b05 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx @@ -0,0 +1,75 @@ +--- +sidebar_position: 3 +--- + +# 1.3 Interval Problem + +## [435. Non-overlapping Intervals](https://leetcode.com/problems/non-overlapping-intervals/) + +### Problem Description + +Given multiple intervals, calculate the minimum number of intervals that need to be removed to make the remaining intervals non-overlapping. Adjacent intervals that meet at endpoints are not considered overlapping. + + +### Input and Output Example + +The input is an array containing multiple subarrays, each with a fixed length of 2, representing the start and end of each interval. The output is an integer indicating the number of intervals that need to be removed. + +``` +Input: [[1,2], [2,4], [1,3]] +Output: 1 +``` +In this example, we can remove the interval [1,3] so that the remaining intervals [[1,2], [2,4]] are non-overlapping. + + +### Solution Explanation + +Finding the minimum number of intervals to remove is equivalent to maximizing the number of non-overlapping intervals we can retain. When selecting intervals to keep, the end point of each interval is critical: the smaller the chosen interval’s end, the more space is left for other intervals, allowing more intervals to be retained. Thus, the greedy strategy we use is to prioritize retaining intervals with smaller end points that do not overlap. + +The specific implementation involves first sorting the intervals in ascending order by their end points (using a lambda function) and then selecting the interval with the smallest end point that does not overlap with the previously chosen interval. + +In the example, the sorted array is [[1,2], [1,3], [2,4]]. According to our greedy strategy, we initialize with the interval [1,2]; since [1,3] overlaps with [1,2], we skip this interval; since [2,4] does not overlap with [1,2], we keep it. Therefore, the final retained intervals are [[1,2], [2,4]]. + +:::warning + +It is necessary to determine whether to sort by the start or end of the intervals based on the specific requirements. + +::: + + + + +```cpp +int eraseOverlapIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end(), + [](vector& a, vector& b) { return a[1] < b[1]; }); + int removed = 0, prev_end = intervals[0][1]; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i][0] < prev_end) { + ++removed; + } else { + prev_end = intervals[i][1]; + } + } + return removed; +} +``` + + + + +```py +def eraseOverlapIntervals(intervals: List[List[int]]) -> int: + intervals.sort(key=lambda x: x[1]) + removed, prev_end = 0, intervals[0][1] + for i in range(1, len(intervals)): + if prev_end > intervals[i][0]: + removed += 1 + else: + prev_end = intervals[i][1] + return removed +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md new file mode 100644 index 00000000..3959bef2 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 4 +--- + +# 1.4 Exercises + +## Basic Difficulty + +### [605. Can Place Flowers](https://leetcode.com/problems/can-place-flowers/) + +What kind of greedy strategy can be used to plant the maximum number of flowers? + +--- + +### [452. Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) + +This problem is very similar to problem 435, but what is the subtle difference? + +--- + +### [763. Partition Labels](https://leetcode.com/problems/partition-labels/) + +To satisfy your greedy strategy, do you need some preprocessing? + +:::warning + +Counting information (such as frequency, count, first appearance position, last appearance position, etc.) before processing the array can significantly reduce the difficulty of the problem. + +::: + +--- + +### [122. Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) + +Among stock trading problems, this is a relatively simple one. Without restricting the number of transactions, how can you achieve the maximum profit? + +--- + +## Advanced Difficulty + +### [406. Queue Reconstruction by Height](https://leetcode.com/problems/queue-reconstruction-by-height/) + +Friendly reminder, this problem may require both sorting and insertion operations. + +--- + +### [665. Non-decreasing Array](https://leetcode.com/problems/non-decreasing-array/) + +Carefully consider whether your greedy strategy remains optimal in all scenarios. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json new file mode 100644 index 00000000..85a7b37f --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "1. The Easiest Greedy Algorithm", + "position": 1, + "link": { + "type": "generated-index", + "description": "Chapter 1: The Easiest Greedy Algorithm" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md new file mode 100644 index 00000000..55bec1f2 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 48 +--- + +# 10.1 C++ STL + +When solving problems, we almost always rely on various data structures to assist us. Therefore, we must familiarize ourselves with the characteristics of each data structure. C++ STL provides several data structures (the actual underlying implementation may vary depending on the compiler): + +1. **Sequence Containers**: Containers that maintain order. + 1. **vector**: A `dynamic array`, one of the most frequently used data structures, ideal for $O(1)$ random access. Since most algorithms have a time complexity greater than $O(n)$, we often use vectors to store various data or intermediate results. As insertion and deletion at the tail have $O(1)$ complexity, it can also be used as a stack. + 2. **list**: A `doubly linked list`, which can also be used as a stack or queue. However, since LeetCode problems often use Nodes to represent linked lists, and linked lists do not support fast random access, this data structure is rarely used. An exception is the classic LRU problem, where the characteristics of linked lists are utilized, as discussed later. + 3. **deque**: A double-ended queue, a powerful data structure that supports $O(1)$ random access and $O(1)$ insertion and deletion at both ends. It can be used as a stack or queue but comes with some overhead. It can also approximate a doubly linked list. + 4. **array**: A fixed-size array, generally not used in competitive programming. + 5. **forward_list**: A singly linked list, which is also generally not used in competitive programming. + +2. **Container Adaptors**: Containers implemented on top of other containers. + 1. **stack**: A `Last In First Out (LIFO)` data structure, implemented using deque by default. It is commonly used for depth-first search, certain string matching problems, and monotonic stack problems. + 2. **queue**: A `First In First Out (FIFO)` data structure, implemented using deque by default. It is commonly used for breadth-first search. + 3. **priority_queue**: A `priority queue (max-heap by default)` data structure, implemented using a vector as a heap. It supports sorting arrays in $O(n \log n)$ time, inserting any value in $O(\log n)$ time, retrieving the maximum value in $O(1)$ time, and deleting the maximum value in $O(\log n)$ time. priority_queue is used to maintain data structures and retrieve maximum values efficiently, and it allows custom comparison functions. For example, by storing negative values or changing the comparison function, a min-heap can be implemented. + +3. **Ordered Associative Containers**: Ordered associative containers. + 1. **set**: An ordered set where elements are unique, implemented using a red-black tree, a specialized Binary Search Tree (BST). It supports sorting arrays in $O(n \log n)$ time, inserting, deleting, or finding any value in $O(\log n)$ time, and retrieving the minimum or maximum value in $O(\log n)$ time. Note that both set and priority_queue can be used to maintain data structures and retrieve maximum or minimum values efficiently, but their time complexities and functionalities differ slightly. For instance, priority_queue does not support arbitrary value deletion by default, whereas set's time complexity for retrieving maximum or minimum values is slightly higher. The choice depends on specific requirements. + 2. **multiset**: A set that allows duplicate elements. + 3. **map**: An `ordered map or ordered table`, which extends set by associating each key with a value. + 4. **multimap**: A map that allows duplicate keys. + +4. **Unordered Associative Containers**: Containers with unordered associations. + 1. **unordered_set**: A `hash set` that allows for $O(1)$ time complexity for insertion, lookup, and deletion of elements. It is commonly used to quickly check if an element exists in the container. + 2. **unordered_multiset**: A hash set that supports duplicate elements. + 3. **unordered_map**: A `hash map` or `hash table` that extends unordered_set by mapping each key to a value. In some cases, if the range of keys is known and small, a vector can be used as a replacement for unordered_map, using the index to represent the key and the value at that index to represent the value. + 4. **unordered_multimap**: A hash map that supports duplicate keys. + +Since this is not a book on C++ fundamentals, more details about STL can be found through further research. Understanding the principles and usage of these data structures is crucial for solving algorithm and data structure problems effectively. + diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx new file mode 100644 index 00000000..deb8157d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx @@ -0,0 +1,227 @@ +--- +sidebar_position: 57 +--- + +# 10.10 Prefix Sum and Integral Image + +A one-dimensional prefix sum (cumulative sum, cumsum) and a two-dimensional integral image (summed-area table, image integral) are techniques used to precompute the sums of one-dimensional segments or two-dimensional rectangles up to each position. This allows for faster calculations and queries. If you need to index values from the prefix sum or integral image, they can be stored in a hash table. If you need to record values for each position, they can be stored in one-dimensional or two-dimensional arrays, often in conjunction with dynamic programming. + +## [303. Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable/) + +### Problem Description + +Design a data structure to quickly query the sum of all numbers between any two positions in a given array. + +### Input and Output Example + +Here is a sample usage of the data structure. + +``` +vector nums{-2,0,3,-5,2,-1}; +NumArray num_array = new NumArray(nums); +num_array.sumRange(0,2); // Result = -2+0+3 = 1. +num_array.sunRange(1,5); // Result = 0+3-5+2-1 = -1. +``` + +### Solution Explanation + +For a one-dimensional array, we can use a prefix sum to solve this problem. First, create a new array `cumsum` of the same length as `nums`, where each position in `cumsum` stores the sum of all numbers in `nums` up to that position. The `cumsum` array can be built using the C++ `partial_sum` function or by iterating through the `nums` array and calculating it using the state transition formula `cumsum[i] = cumsum[i-1] + nums[i]`. To obtain the sum of numbers between positions `i` and `j`, calculate `cumsum[j+1] - cumsum[i]`. + + + + +```cpp +class NumArray { + public: + NumArray(vector nums) : cumsum_(nums.size() + 1, 0) { + partial_sum(nums.begin(), nums.end(), cumsum_.begin() + 1); + } + + int sumRange(int left, int right) { + return cumsum_[right + 1] - cumsum_[left]; + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class NumArray: + def __init__(self, nums: List[int]): + self.cumsum = [0] + nums[:] + for i in range(2, len(self.cumsum)): + self.cumsum[i] += self.cumsum[i - 1] + + def sumRange(self, left: int, right: int) -> int: + return self.cumsum[right + 1] - self.cumsum[left] +``` + + + + + +## [304. Range Sum Query 2D - Immutable](https://leetcode.com/problems/range-sum-query-2d-immutable/) + +### Problem Description + +Design a data structure to quickly query the sum of all numbers within a rectangle defined by any two positions in a given matrix. + +### Input and Output Example + +Here is a sample usage of the data structure. The `sumRegion` function takes four inputs: the row and column of the first point, and the row and column of the second point. + +``` +vector matrix{{3,0,1,4,2}, + {5,6,3,2,1}, + {1,2,0,1,5}, + {4,1,0,1,7}, + {1,0,3,0,5} +}; +NumMatrix num_matrix = new NumMatrix(matrix); +num_matrix.sumRegion(2,1,4,3); // Result = 8. +num_matrix.sumRegion(1,1,2,2); // Result = 11. +``` + +### Solution Explanation + +Similar to prefix sums, we can extend this concept to two dimensions, known as a summed-area table (SAT) or image integral. We can first build an `sat` matrix, where `sat[i][j]` represents the sum of all numbers in the rectangle defined by `(0, 0)` as the top-left corner and `(i-1, j-1)` as the bottom-right corner. + +
+ + ![](10.4.png) + +
Figure 10.4: Problem 304 - Diagram 1 - The left shows the given matrix, and the right shows the summed-area table. The value at the bottom-right corner of the SAT is 5+48+45−40 = 58.
+
+ + +
+ + ![](10.5.png) + +
Figure 10.5: Problem 304 - Diagram 2 - The left shows the given matrix, and the right shows the SAT. The sum of rectangle E equals 58 − 11 − 13 + 3 = 37.
+
+ +As shown in Figure 1, we can compute the `sat` matrix using dynamic programming: `sat[i][j] = matrix[i-1][j-1] + sat[i-1][j] + sat[i][j-1] - sat[i-1][j-1]`, which is the value at the current coordinate plus the sum of the rectangle above it plus the sum of the rectangle to its left minus the overlap (i.e., the top-left rectangle). + +As shown in Figure 2, suppose we need to query the sum of rectangle E. Since `E = D − B − C + A`, we observe that E can be derived using addition and subtraction of SAT values at four positions. Thus, the preprocessing time complexity is $O(mn)$, while the query time complexity is only $O(1)$. + + + + + +```cpp +class NumMatrix { + public: + NumMatrix(vector> matrix) { + int m = matrix.size(), n = matrix[0].size(); + sat_ = vector>(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + sat_[i][j] = matrix[i - 1][j - 1] + sat_[i - 1][j] + + sat_[i][j - 1] - sat_[i - 1][j - 1]; + } + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sat_[row2 + 1][col2 + 1] - sat_[row2 + 1][col1] - + sat_[row1][col2 + 1] + sat_[row1][col1]; + } + + private: + vector> sat_; +}; +``` + + + + +```py +class NumMatrix: + def __init__(self, matrix: List[List[int]]): + m, n = len(matrix), len(matrix[0]) + self.sat = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + self.sat[i][j] = ( + matrix[i - 1][j - 1] + + self.sat[i - 1][j] + + self.sat[i][j - 1] + - self.sat[i - 1][j - 1] + ) + + def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int: + return ( + self.sat[row2 + 1][col2 + 1] + - self.sat[row2 + 1][col1] + - self.sat[row1][col2 + 1] + + self.sat[row1][col1] + ) + +``` + + + + + +## [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) + +### Problem Description + +Given an array, find the number of continuous subarrays whose sum equals $k$. + +### Input and Output Example + +Input is a one-dimensional integer array and an integer value $k$; output is an integer representing the number of subarrays that meet the condition. + +``` +Input: nums = [1,1,1], k = 2 +Output: 2 +``` + +In this example, we can find two subarrays [1,1] that satisfy the condition. + +### Solution Explanation + +This problem also uses prefix sums. The difference here is that we employ a hash table `cache` where the keys are prefix sums and the values are the number of times that prefix sum appears. When iterating to position $i$, if the current prefix sum is `cumsum`, then `cache[cumsum-k]` represents the number of subarrays ending at the current position that satisfy the condition. + + + + +```cpp +int subarraySum(vector& nums, int k) { + int count = 0, cumsum = 0; + unordered_map cache; // + cache[0] = 1; + for (int num : nums) { + cumsum += num; + count += cache[cumsum - k]; + ++cache[cumsum]; + } + return count; +} +``` + + + + +```py +def subarraySum(nums: List[int], k: int) -> int: + count, cur_sum = 0, 0 + cache = {0: 1} # + for num in nums: + cur_sum += num + count += cache.get(cur_sum - k, 0) + cache[cur_sum] = cache.get(cur_sum, 0) + 1 + return count +``` + + + + + diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md new file mode 100644 index 00000000..40680f39 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md @@ -0,0 +1,73 @@ +--- +sidebar_position: 58 +--- + +# 10.11 Exercises + +## Basic Difficulty + +### [566. Reshape the Matrix](https://leetcode.com/problems/reshape-the-matrix/) + +This problem is not particularly challenging; it only requires some patience. + +--- + +### [225. Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues/) + +Using a similar approach, we can also implement a stack using queues. + +--- + +### [503. Next Greater Element II](https://leetcode.com/problems/next-greater-element-ii/) + +A variant of the `Daily Temperatures` problem. + +--- + +### [217. Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) + +Which data structure would allow us to quickly check for duplicates? + +--- + +### [697. Degree of an Array](https://leetcode.com/problems/degree-of-an-array/) + +How can we preprocess an array to correctly and efficiently compute the length of a subarray? + +--- + +### [594. Longest Harmonious Subsequence](https://leetcode.com/problems/longest-harmonious-subsequence/) + +A variant of the `Longest Consecutive Sequence` problem. + +--- + +### [15. 3Sum](https://leetcode.com/problems/3sum/) + +Since the complexity of sorting is $O(n \log n) < O(n^2)$, we can either sort the array first and then perform an $O(n^2)$ pointer search, or directly use a hash table for an $O(n^2)$ search. + +--- + +## Advanced Difficulty + +### [287. Find the Duplicate Number](https://leetcode.com/problems/find-the-duplicate-number/) + +A variant of the `Find Missing Number` problem. Besides marking negative values, are there any other algorithms to solve this? + +--- + +### [313. Super Ugly Number](https://leetcode.com/problems/super-ugly-number/) + +Try solving this using a priority queue. + +--- + +### [870. Advantage Shuffle](https://leetcode.com/problems/advantage-shuffle/) + +If we need to compare relative sizes and the same number can appear multiple times, which data structure should we use? + +--- + +### [307. Range Sum Query - Mutable](https://leetcode.com/problems/range-sum-query-mutable/) + +A variant of the `Prefix Sum` problem. I admit this might be slightly advanced; you might want to look up what a `Segment Tree` is. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md new file mode 100644 index 00000000..c1a2a6b7 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 49 +--- + +# 10.2 Python Common Data Structures + +Similar to C++ STL, Python also provides various data structures (the underlying details may vary depending on the implementation): + +1. **Sequence Containers**: Containers that maintain order. + 1. **list**: A `dynamic array`, one of the most commonly used data structures for $O(1)$ random access. Since most algorithm complexities exceed $O(n)$, lists are frequently used to store data or intermediate results. As adding or removing elements at the end has $O(1)$ complexity, lists can also be used as stacks. + 2. **tuple**: An `immutable list`, where neither the elements nor the length can be modified. + 3. **collections.deque**: A `double-ended queue`, a powerful data structure supporting $O(1)$ random access as well as $O(1)$ insertion and deletion at both ends (making it useful as a stack or queue). It has some overhead but can approximate a doubly linked list. + +2. **Container Adaptors**: Containers built on top of other data structures. + 1. **heapq**: A `min-heap` (a data structure where the smallest element is accessed first), implemented using lists. It supports array sorting in $O(n \log n)$, value insertion in $O(\log n)$, access to the smallest value in $O(1)$, and deletion of the smallest value in $O(\log n)$. `heapq` is often used for maintaining data structures and quickly accessing the smallest value, but it doesn't support custom comparison functions. Typically, we precompute the custom values and store them as tuples, like `(custom_value, index)`, in the heap. This way, tuple comparisons are done from left to right, comparing the custom value first and then the insertion order. + +3. **Ordered Associative Containers**: + 1. **collections.OrderedDict**: `Ordered mapping or ordered table`. Note that "Ordered" here means maintaining the insertion order, unlike C++'s map, which sorts keys by size. `OrderedDict` is particularly useful for implementing LRU (Least Recently Used) caching. + +4. **Unordered Associative Containers**: + 1. **set**: `Hash set`. Allows for fast insertion, lookup, and deletion of elements in O(1) time. Commonly used to quickly check if an element exists in the container. + 2. **dict**: `Hash map or hash table`. Builds upon the set structure by adding key-value mapping. In some scenarios, if the key range is known and small, a list can replace a dict, using indices to represent keys and list values for their corresponding values. + 3. **collections.Counter**: `Counter`. A specialized version of dict that accepts a list and counts the frequency of each element. Keys are the element values, and values are their frequencies. This can serve as a multiset. + +Similarly, since this is not a book on Python internals, readers are encouraged to explore more details about these data structures. Understanding their principles and usage will enable more effective problem-solving in algorithms and data structures. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx new file mode 100644 index 00000000..fa0c98df --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx @@ -0,0 +1,248 @@ +--- +sidebar_position: 50 +--- + +# 10.3 Arrays + +## [448. Find All Numbers Disappeared in an Array](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/) + +### Problem Description + +Given an array of length n containing integers in the range from 1 to n, some integers appear multiple times, while others do not appear at all. Find all integers from 1 to n that are missing in the array. + +### Input and Output Example + +Input is a one-dimensional integer array, and the output is also a one-dimensional integer array representing the numbers that do not appear in the input array. + +``` +Input: [4,3,2,7,8,2,3,1] +Output: [5,6] +``` + +By using the array as a data structure to create n buckets, mark all positions where numbers appear multiple times, and then traverse the array to find the missing numbers. Furthermore, we can directly modify the original array: mark the positions corresponding to the numbers that appear as negative (this maps numbers from 1 to n to indices 0 to n-1), and the indices that remain positive correspond to the missing numbers. + +### Solution Explanation + + + + +```cpp +vector findDisappearedNumbers(vector& nums) { + vector disappeared; + for (int num : nums) { + int pos = abs(num) - 1; + if (nums[pos] > 0) { + nums[pos] = -nums[pos]; + } + } + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] > 0) { + disappeared.push_back(i + 1); + } + } + return disappeared; +} +``` + + + + +```py +def findDisappearedNumbers(nums: List[int]) -> List[int]: + for num in nums: + pos = abs(num) - 1 + if nums[pos] > 0: + nums[pos] = -nums[pos] + return [i + 1 for i in range(len(nums)) if nums[i] > 0] +``` + + + + + +## [48. Rotate Image](https://leetcode.com/problems/rotate-image/) + +### Problem Description + +Given an n × n matrix, rotate it 90 degrees clockwise in place. How can this be done with minimal additional storage space? + +### Input and Output Example + +Both the input and output are two-dimensional integer matrices. + +``` +Input: +[[1,2,3], + [4,5,6], + [7,8,9]] +Output: +[[7,4,1], + [8,5,2], + [9,6,3]] +``` + +### Solution Explanation + +Consider four positions spaced 90 degrees apart each time, and perform an $O(1)$ space rotation. + +
+ + ![](10.1.png) + +
Figure 10.1: Problem 48 - Example of $O(1)$ space rotation, same colors indicate four positions to be swapped
+
+ + + + +```cpp +void rotate(vector>& matrix) { + int pivot = 0, n = matrix.size() - 1; + for (int i = 0; i <= n / 2; ++i) { + for (int j = i; j < n - i; ++j) { + pivot = matrix[j][n - i]; + matrix[j][n - i] = matrix[i][j]; + matrix[i][j] = matrix[n - j][i]; + matrix[n - j][i] = matrix[n - i][n - j]; + matrix[n - i][n - j] = pivot; + } + } +} +``` + + + + +```py +def rotate(matrix: List[List[int]]) -> None: + n = len(matrix) - 1 + for i in range(n // 2 + 1): + for j in range(i, n - i): + pivot = matrix[j][n - i] + matrix[j][n - i] = matrix[i][j] + matrix[i][j] = matrix[n - j][i] + matrix[n - j][i] = matrix[n - i][n - j] + matrix[n - i][n - j] = pivot +``` + + + + + +## [240. Search a 2D Matrix II](https://leetcode.com/problems/search-a-2d-matrix-ii/) + +### Problem Description + +Given a 2D matrix where each row and each column is sorted in ascending order, design a fast algorithm to search for a number in the matrix. + +### Input and Output Example + +The input is a two-dimensional integer matrix and a target integer to search. The output is a boolean value indicating whether the integer exists in the matrix. + +``` +Input: matrix = +[ [1, 4, 7, 11, 15], + [2, 5, 8, 12, 19], + [3, 6, 9, 16, 22], + [10, 13, 14, 17, 24], + [18, 21, 23, 26, 30]], target = 5 +Output: true +``` + +### Solution Explanation + +There is a simple trick for this problem: Start searching from the top-right corner. If the current value is greater than the target, move left; if it is smaller than the target, move down. If you reach the bottom-left corner without finding the target, the value does not exist in the matrix. + + + + +```cpp +bool searchMatrix(vector>& matrix, int target) { + int m = matrix.size(), n = matrix[0].size(); + int i = 0, j = n - 1; + while (i < m && j >= 0) { + if (matrix[i][j] == target) { + return true; + } else if (matrix[i][j] < target) { + ++i; + } else { + --j; + } + } + return false; +} +``` + + + + +```py +def searchMatrix(matrix: List[List[int]], target: int) -> bool: + m, n = len(matrix), len(matrix[0]) + i, j = 0, n - 1 + while i < m and j >= 0: + if matrix[i][j] == target: + return True + if matrix[i][j] < target: + i += 1 + else: + j -= 1 + return False +``` + + + + + +## [769. Max Chunks To Make Sorted](https://leetcode.com/problems/max-chunks-to-make-sorted/) + +### Problem Description + +Given an array of integers containing 0 to n, where each integer appears only once, find the maximum number of chunks you can split the array into such that sorting each chunk results in the entire array being sorted in ascending order. + +### Input and Output Example + +The input is a one-dimensional integer array, and the output is an integer representing the maximum number of chunks. + +``` +Input: [1,0,2,3,4] +Output: 4 +``` + +In this example, the maximum chunks are [1, 0], [2], [3], [4]. + +### Solution Explanation + +Iterate from left to right, keeping track of the current maximum value. Whenever the current maximum value equals the current array index, we can perform a split. + +Why does this algorithm work? If the current maximum value is greater than the current array index, it means there are smaller values on the right that need to be included in the chunk. Since the array contains only unique integers from 0 to n, the current maximum value will never be less than the current index. Therefore, whenever the current maximum value equals the current index, say p, we can successfully make a split. The values between the previous split point q and p will always contain all integers from q+1 to p. + + + + +```cpp +int maxChunksToSorted(vector& arr) { + int chunks = 0, cur_max = 0; + for (int i = 0; i < arr.size(); ++i) { + cur_max = max(cur_max, arr[i]); + chunks += cur_max == i; + } + return chunks; +} +``` + + + + +```py +def maxChunksToSorted(arr: List[int]) -> int: + chunks, cur_max = 0, 0 + for i, num in enumerate(arr): + cur_max = max(cur_max, num) + chunks += cur_max == i + return chunks +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx new file mode 100644 index 00000000..07d6ceb0 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx @@ -0,0 +1,257 @@ +--- +sidebar_position: 51 +--- + +# 10.4 Stacks and Queues + +## [232. Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks/) + +### Problem Description + +Try to implement a queue using stacks. + +### Input and Output Example + +Here is an example of how the data structure is used. + +``` +MyQueue queue = new MyQueue(); +queue.push(1); +queue.push(2); +queue.peek(); // returns 1 +queue.pop(); // returns 1 +queue.empty(); // returns false +``` + +### Solution Explanation + +We can implement a queue using two stacks: since we need a first-in-first-out result, we must reverse the array once using an additional stack. This reversing process can be completed either during insertion or during retrieval. Below is an example of implementing the reversal during retrieval. + + + + +```cpp +class MyQueue { + public: + MyQueue() {} + + void push(int x) { s_in_.push(x); } + + int pop() { + in2out(); + int x = s_out_.top(); + s_out_.pop(); + return x; + } + + int peek() { + in2out(); + return s_out_.top(); + } + + bool empty() { return s_in_.empty() && s_out_.empty(); } + + private: + void in2out() { + if (!s_out_.empty()) { + return; + } + while (!s_in_.empty()) { + int x = s_in_.top(); + s_in_.pop(); + s_out_.push(x); + } + } + + stack s_in_, s_out_; +}; +``` + + + + +```py +class MyQueue: + def __init__(self): + self.s_in = [] + self.s_out = [] + + def _in2out(self): + if len(self.s_out) > 0: + return + while len(self.s_in) > 0: + self.s_out.append(self.s_in.pop()) + + def push(self, x: int) -> None: + self.s_in.append(x) + + def pop(self) -> int: + self._in2out() + return self.s_out.pop() + + def peek(self) -> int: + self._in2out() + return self.s_out[-1] + + def empty(self) -> bool: + return len(self.s_in) == 0 and len(self.s_out) == 0 +``` + + + + + +## [155. Min Stack](https://leetcode.com/problems/min-stack/) + +### Problem Description + +Design a minimum stack that supports not only regular stack operations but also retrieving the minimum value in the stack in $O(1)$ time. + +### Input and Output Example + +Here is an example of how the data structure is used. + +``` +MinStack minStack = new MinStack(); +minStack.push(-2); +minStack.push(0); +minStack.push(-3); +minStack.getMin(); // Returns -3. +minStack.pop(); +minStack.top(); // Returns 0. +minStack.getMin(); // Returns -2. +``` + +### Solution Explanation + +We can maintain an additional stack where the top represents the minimum value of all elements in the main stack. Every time a number is pushed onto the main stack, if it is less than or equal to the top of the auxiliary stack, it is also pushed onto the auxiliary stack, indicating it is a minimum value in the main stack. Similarly, every time a number is popped from the main stack, if it equals the top of the auxiliary stack, the top value of the auxiliary stack is also popped. + +An alternative method, which is simpler to write but has slightly higher time complexity, involves always pushing the minimum value of all elements in the main stack (the smaller of the top value of the auxiliary stack and the new value being pushed) onto the auxiliary stack. Similarly, every pop operation removes the top value from both stacks. This eliminates the need for conditionals but requires inserting and removing a value every time. Here, we only demonstrate the first approach. + + + + +```cpp +class MinStack { + public: + MinStack() {} + + void push(int x) { + s_.push(x); + if (min_s_.empty() || min_s_.top() >= x) { + min_s_.push(x); + } + } + + void pop() { + if (!min_s_.empty() && min_s_.top() == s_.top()) { + min_s_.pop(); + } + s_.pop(); + } + + int top() { return s_.top(); } + + int getMin() { return min_s_.top(); } + + private: + stack s_, min_s_; +}; +``` + + + + +```py +class MinStack: + def __init__(self): + self.s = [] + self.min_s = [] + + def push(self, x: int) -> None: + self.s.append(x) + if len(self.min_s) == 0 or self.min_s[-1] >= x: + self.min_s.append(x) + + def pop(self) -> None: + if len(self.min_s) != 0 and self.s[-1] == self.min_s[-1]: + self.min_s.pop() + self.s.pop() + + def top(self) -> int: + return self.s[-1] + + def getMin(self) -> int: + return self.min_s[-1] +``` + + + + + + +## [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) + +### Problem Description + +Given a string containing only the characters `(`, `)`, `{`, `}`, `[`, and `]`, determine if the input string is valid. A valid string requires that every opening bracket has a corresponding closing bracket of the same type, and the substring enclosed by the brackets is also valid. + +### Input and Output Example + +The input is a string, and the output is a boolean value indicating whether the string is valid. + +``` +Input: "{[]}()" +Output: true +``` + +### Solution Explanation + +Parenthesis matching is a classic problem that can be solved using a stack. As we iterate through the string from left to right, we push every opening bracket onto the stack. When encountering a closing bracket, we check if it matches the top of the stack. If it matches, we pop the stack; otherwise, the string is invalid. + + + + +```cpp +bool isValid(string s) { + stack parsed; + unordered_map matches{{’(’, ’)’}, {’{’, ’}’}, {’[’, ’]’}}; + for (char c : s) { + if (matches.contains(c)) { + parsed.push(c); + continue; + } + if (parsed.empty()) { + return false; + } + if (c != matches[parsed.top()]) { + return false; + } + parsed.pop(); + } + return parsed.empty(); +} +``` + + + + +```py +def isValid(s: str) -> bool: + parsed = [] + matches = {"{": "}", "(": ")", "[": "]"} + for c in s: + if c in matches.keys(): + parsed.append(c) + continue + if len(parsed) == 0: + return False + if c != matches[parsed[-1]]: + return False + parsed.pop() + return len(parsed) == 0 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx new file mode 100644 index 00000000..18668306 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 52 +--- + +# 10.5 Monotonic Stack + +`Monotonic Stack` is a technique that maintains the monotonic increasing (or decreasing) property of a stack to solve comparison problems in $O(n)$ time complexity. + +## [739. Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) + +### Problem Description + +Given the daily temperatures, determine how many days you need to wait for a warmer day. If there is no such day, return 0 for that day. + +### Input and Output Example + +The input is a one-dimensional integer array, and the output is an array of the same length, indicating how many days you need to wait for each day. + +``` +Input: [73, 74, 75, 71, 69, 72, 76, 73] +Output: [1, 1, 4, 2, 1, 1, 0, 0] +``` + +### Solution Explanation + +We can maintain a monotonic decreasing stack that stores the temperatures. To facilitate calculating the day differences, we store indices (dates) instead of the temperatures themselves. As we iterate through the temperature array from left to right, for each day $p$, if the temperature on day $p$ is higher than the temperature of the day stored at the stack top $q$, we pop $q$ and record the waiting days for $q$ as $p - q$. We repeat this process until the temperature of day $p$ is less than or equal to the temperature at the stack top (or the stack becomes empty), then push $p$ into the stack and move to the next day. During this process, the stack always maintains a monotonic decreasing order, avoiding the need for sorting. Finally, if there are remaining indices in the stack, it means those days do not have warmer days in the future. + + + + +```cpp +vector dailyTemperatures(vector& temperatures) { + int n = temperatures.size(); + vector days_to_wait(n, 0); + stack mono_stack; + for (int i = 0; i < n; ++i) { + while (!mono_stack.empty()) { + int j = mono_stack.top(); + if (temperatures[i] <= temperatures[j]) { + break; + } + mono_stack.pop(); + days_to_wait[j] = i - j; + } + mono_stack.push(i); + } + return days_to_wait; +} +``` + + + + +```py +def dailyTemperatures(temperatures: List[int]) -> List[int]: + n = len(temperatures) + days_to_wait = [0] * n + mono_stack = [] + for i in range(n): + while len(mono_stack) > 0: + j = mono_stack[-1] + if temperatures[i] <= temperatures[j]: + break + mono_stack.pop() + days_to_wait[j] = i - j + mono_stack.append(i) + return days_to_wait +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx new file mode 100644 index 00000000..60f32572 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx @@ -0,0 +1,295 @@ +--- +sidebar_position: 53 +--- + +# 10.6 Priority Queue + +`Priority queue` allows retrieving the maximum value in $O(1)$ time and inserting or removing the maximum value in $O(\log n)$ time. + +
+ + ![](10.2.png) + +
Figure 10.2: (Max) Heap, maintaining the "greater than" relationship in the data structure
+
+ +Priority queues are often implemented using heaps. A heap is a complete binary tree in which each node's value is always greater than or equal to its child nodes. When implementing heaps, arrays are often used instead of pointers to build a tree. This is because heaps are complete binary trees, so in an array representation, the parent node of position $i$ is located at $(i-1)/2$, and its two child nodes are located at $2i+1$ and $2i+2$, respectively. + +Here is the implementation of heaps. The two core operations are "swim" and "sink": if a node is greater than its parent node, we swap them; after swapping, it may still be greater than its new parent node, so we continue comparing and swapping, known as "swim." Similarly, if a node is smaller than its parent, it needs to compare and swap downward continuously, known as "sink." If a node has two child nodes, we always swap with the largest child node. + + + + + +```cpp +class Heap { + public: + Heap() {} + // Swim + void swim(int pos) { + int next_pos = (pos - 1) / 2; + while (pos > 0 && heap_[next_pos] < heap_[pos]) { + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = (pos - 1) / 2; + } + } + // Sink + void sink(int pos) { + int n = heap_.size(); + int next_pos = 2 * pos + 1; + while (next_pos < n) { + if (next_pos < n - 1 && heap_[next_pos] < heap_[next_pos + 1]) { + ++next_pos; + } + if (heap_[pos] >= heap_[next_pos]) { + break; + } + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = 2 * pos + 1; + } + } + // Insert any value: place the new number at the last position, then swim. + void push(int k) { + heap_.push_back(k); + swim(heap_.size() - 1); + } + // Delete the maximum value: move the last number to the front, then sink. + void pop() { + heap_[0] = heap_.back(); + heap_.pop_back(); + sink(0); + } + // Retrieve the maximum value. + int top() { return heap_[0]; } + + private: + vector heap_; +}; +``` + + + + +```py +class Heap: + def __init__(self): + self.heap = [] + + # Swim + def swim(self, pos: int): + next_pos = (pos - 1) // 2 + while pos > 0 and self.heap[next_pos] < self.heap[pos]: + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = (pos - 1) // 2 + + # Sink + def sink(self, pos: int): + n = len(self.heap) + next_pos = 2 * pos + 1 + while next_pos < n: + if next_pos < n - 1 and self.heap[next_pos] < self.heap[next_pos + 1]: + next_pos += 1 + if self.heap[pos] >= self.heap[next_pos]: + break + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = 2 * pos + 1 + + # Insert any value: place the new number at the last position, then swim. + def push(self, k: int): + self.heap.append(k) + self.swim(len(self.heap) - 1) + + # Delete the maximum value: move the last number to the front, then sink. + def pop(self): + self.heap[0] = self.heap.pop() + self.sink(0) + + # Retrieve the maximum value. + def top(self) -> int: + return self.heap[0] + +``` + + + + + +By swapping the greater-than and less-than operators in the algorithm, we can also create a priority queue that retrieves the minimum value quickly. + +## [23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) + +### Problem Description + +Given `k` sorted linked lists, try to merge them into one sorted linked list. + +### Input and Output Example + +The input is a one-dimensional array, where each position stores the head node of a linked list; the output is a single linked list. + +``` +Input: +[1->4->5, + 1->3->4, + 2->6] +Output: 1->1->2->3->4->4->5->6 +``` + +### Solution Explanation + +There are multiple ways to solve this problem, such as using a merge sort-like approach to merge the lists pair by pair. Here, we demonstrate a faster method: store all the linked lists in a priority queue and extract the node with the smallest value from the head of all lists at each step until all lists have been completely merged. + +Since the default comparison function of a C++ `priority_queue` is for a max-heap and maintains an increasing order, to get the smallest node values, we need to implement a min-heap. Thus, the comparison function for the heap should maintain a decreasing order, i.e., the lambda function should use the greater-than operator instead of the less-than operator used for increasing order. + + + + +```cpp +ListNode* mergeKLists(vector& lists) { + auto comp = [](ListNode* l1, ListNode* l2) { return l1->val > l2->val; }; + priority_queue, decltype(comp)> pq; + for (ListNode* l : lists) { + if (l) { + pq.push(l); + } + } + ListNode *dummy = new ListNode(0), *cur = dummy; + while (!pq.empty()) { + cur->next = pq.top(); + pq.pop(); + cur = cur->next; + if (cur->next) { + pq.push(cur->next); + } + } + return dummy->next; +} +``` + + + + +```py +def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]: + pq = [] + for idx, l in enumerate(lists): + if l is not None: + # ListNode cannot be hashed, so we directly record its position in lists. + pq.append((l.val, idx)) + heapq.heapify(pq) + + dummy = ListNode() + cur = dummy + + while len(pq) > 0: + _, l_idx = heapq.heappop(pq) + cur.next = lists[l_idx] + cur = cur.next + if cur.next is not None: + lists[l_idx] = lists[l_idx].next + heapq.heappush(pq, (cur.next.val, l_idx)) + + return dummy.next + +``` + + + + + +## [218. The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) + +### Problem Description + +Given the start and end positions along with the height of buildings, return the critical points of the building's silhouette (skyline). + +### Input and Output Example + +The input is a 2D integer array representing each building as `[left, right, height]`; the output is a 2D integer array representing the x and y coordinates of the critical points of the skyline. + +
+ + ![](10.3.png) + +
Figure 10.3: Problem 218 - Example of buildings and their skyline
+
+ +``` +Input: [[2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8]] +Output: [[2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0]] +``` + +### Solution Explanation + +We can use a priority queue to store the height and the right endpoint of each building (using a pair). This helps us identify the next building that raises the skyline and interferes with the previous building's endpoint. + +Since Python's `heapq` implements a min-heap, we store negative values for heights to simulate a max-heap. + +This problem is relatively complex. If you find it challenging to grasp, consider skipping it for now or illustrating examples on paper for better understanding. + + + + +```cpp +vector> getSkyline(vector>& buildings) { + vector> skyline; + priority_queue> pq; // + int i = 0, n = buildings.size(); + int cur_x, cur_h; + while (i < n || !pq.empty()) { + if (pq.empty() || (i < n && buildings[i][0] <= pq.top().second)) { + cur_x = buildings[i][0]; + while (i < n && cur_x == buildings[i][0]) { + pq.emplace(buildings[i][2], buildings[i][1]); + ++i; + } + } else { + cur_x = pq.top().second; + while (!pq.empty() && cur_x >= pq.top().second) { + pq.pop(); + } + } + cur_h = pq.empty() ? 0 : pq.top().first; + if (skyline.empty() || cur_h != skyline.back()[1]) { + skyline.push_back({cur_x, cur_h}); + } + } + return skyline; +} +``` + + + + +```py +def getSkyline(buildings: List[List[int]]) -> List[List[int]]: + skyline = [] + pq = [] # + heapq.heapify(pq) + i, n = 0, len(buildings) + + while i < n or len(pq) > 0: + if len(pq) == 0 or (i < n and buildings[i][0] <= pq[0][1]): + cur_x = buildings[i][0] + while i < n and cur_x == buildings[i][0]: + heapq.heappush(pq, (-buildings[i][2], buildings[i][1])) + i += 1 + else: + cur_x = pq[0][1] + while len(pq) > 0 and cur_x >= pq[0][1]: + heapq.heappop(pq) + + cur_h = -pq[0][0] if len(pq) > 0 else 0 + if len(skyline) == 0 or cur_h != skyline[-1][1]: + skyline.append([cur_x, cur_h]) + + return skyline + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx new file mode 100644 index 00000000..facf24fe --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx @@ -0,0 +1,89 @@ +--- +sidebar_position: 54 +--- + +# 10.7 Double-Ended Queue + +## [239. Sliding Window Maximum](https://leetcode.com/problems/sliding-window-maximum/) + +### Problem Description + +Given an integer array and a sliding window size, find the maximum value in the sliding window at each step. + +### Input and Output Example + +The input consists of a one-dimensional integer array and an integer representing the sliding window size; the output is a one-dimensional integer array representing the maximum value within the window at each step. + +``` +Input: nums = [1,3,-1,-3,5,3,6,7], k = 3 +Output: [3,3,5,5,6,7] +``` + +For this example, the sliding window's maximum value at each position is as follows: + +``` + Window position Max +------------------------- ----- +[1 3 -1] -3 5 3 6 7 3 + 1 [3 -1 -3] 5 3 6 7 3 + 1 3 [-1 -3 5] 3 6 7 5 + 1 3 -1 [-3 5 3] 6 7 5 + 1 3 -1 -3 [5 3 6] 7 6 + 1 3 -1 -3 5 [3 6 7] 7 +``` + +### Solution Explanation + +We can use a deque to manage the sliding window efficiently: + +- As the window slides to the right, remove values from the deque's left end if they exit the window. +- Also, remove all elements from the deque's right end that are smaller than the new rightmost value in the window. + +This ensures that the deque's leftmost element is always the maximum value of the current window. + +Additionally, this approach can be considered an extension of a monotonic stack: the deque maintains a decreasing order from left to right to preserve the size relationship. + + + + +```cpp +vector maxSlidingWindow(vector& nums, int k) { + deque dq; + vector swm; + for (int i = 0; i < nums.size(); ++i) { + if (!dq.empty() && dq.front() == i - k) { + dq.pop_front(); + } + while (!dq.empty() && nums[dq.back()] < nums[i]) { + dq.pop_back(); + } + dq.push_back(i); + if (i >= k - 1) { + swm.push_back(nums[dq.front()]); + } + } + return swm; +} +``` + + + + +```py +def maxSlidingWindow(nums: List[int], k: int) -> List[int]: + dq = collections.deque() + swm = [] + for i, num in enumerate(nums): + if len(dq) > 0 and dq[0] == i - k: + dq.popleft() + while len(dq) > 0 and nums[dq[-1]] < num: + dq.pop() + dq.append(i) + if i >= k - 1: + swm.append(nums[dq[0]]) + return swm +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx new file mode 100644 index 00000000..d0cb8b4b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx @@ -0,0 +1,232 @@ +--- +sidebar_position: 55 +--- + +# 10.8 Hash Table + +A `hash table` (also known as a hash map) uses $O(n)$ space complexity to store data. By leveraging a hash function, it maps positions to achieve approximate $O(1)$ time complexity for insertion, lookup, and deletion operations. Hash tables can be utilized for tasks such as frequency counting and content recording. + +If the elements are finite and their range is small, a fixed-size array can be used to store or count elements. For instance, to count the occurrences of all letters in a string, you can use an array of length 26, where the hash function maps each letter to its position in the alphabet. This approach reduces the space complexity to a constant. + +## [1. Two Sum](https://leetcode.com/problems/two-sum/) + +### Problem Description + +Given an (unsorted) array of integers, find the indices of two numbers that add up to a specific target. Assume that there is exactly one solution. + +### Input and Output Example + +Input is a one-dimensional integer array and a target value. Output is a one-dimensional array of size 2, representing the indices of the two numbers. + +``` +Input: nums = [2, 7, 15, 11], target = 9 +Output: [0, 1] +``` + +In this example, the value at index 0 (2) and the value at index 1 (7) sum up to 9. + +### Solution Explanation + +We can use a hash table to store values we have already seen along with their indices. For each index `i`, we check if `target - nums[i]` exists in the hash table. If it does, it means the two numbers sum up to the target. + + + + +```cpp +vector twoSum(vector& nums, int target) { + unordered_map cache; // + for (int i = 0; i < nums.size(); ++i) { + int num1 = nums[i], num2 = target - num1; + if (cache.contains(num2)) { + return vector{cache[num2], i}; + } + cache[num1] = i; + } + return {}; +} +``` + + + + +```py +def twoSum(nums: List[int], target: int) -> List[int]: + cache = dict() # + for i, num1 in enumerate(nums): + num2 = target - num1 + if num2 in cache: + return [cache[num2], i] + cache[num1] = i + return [] +``` + + + + + +## [128. Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) + +### Problem Description + +Given an array of integers, find the length of the longest consecutive sequence that can be formed using the numbers in the array. + +### Input and Output Example + +Input is an array of integers, and output is an integer representing the length of the consecutive sequence. + +``` +Input: [100, 4, 200, 1, 3, 2] +Output: 4 +``` + +In this example, the longest consecutive sequence is [1,2,3,4]. + +### Solution Explanation + +We can put all the numbers into a hash table and repeatedly pick any value from the hash table. For each value, we remove all its consecutive numbers before and after it, and update the length of the longest consecutive sequence. Repeating this process allows us to find all consecutive number sequences. + + + + +```cpp +int longestConsecutive(vector& nums) { + unordered_set cache(nums.begin(), nums.end()); + int max_len = 0; + while (!cache.empty()) { + int cur = *(cache.begin()); + cache.erase(cur); + int l = cur - 1, r = cur + 1; + while (cache.contains(l)) { + cache.erase(l--); + } + while (cache.contains(r)) { + cache.erase(r++); + } + max_len = max(max_len, r - l - 1); + } + return max_len; +} +``` + + + + +```py +def longestConsecutive(nums: List[int]) -> int: + cache = set(nums) + max_len = 0 + + while len(cache) > 0: + cur = next(iter(cache)) + cache.remove(cur) + + l, r = cur - 1, cur + 1 + while l in cache: + cache.remove(l) + l -= 1 + while r in cache: + cache.remove(r) + r += 1 + + max_len = max(max_len, r - l - 1) + + return max_len + +``` + + + + + +## [149. Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) + +### Problem Description + +Given some points in a 2D plane, find the maximum number of points that lie on the same straight line. + +### Input and Output Example + +Input is a 2D integer array representing the x and y coordinates of each point. Output is an integer representing the maximum number of points on the same line. + +``` +Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] +^ +| +| o +| o o +| o +| o o ++-------------------> +0 1 2 3 4 5 6 +Output: 4 +``` + +In this example, the line $y = 5 - x$ contains four points. + +### Solution Explanation + +For each point, we use a hash table to count the number of points with the same slope relative to that point. A line is uniquely determined by one point and its slope. Additionally, we must account for cases where the slope does not exist and for duplicate coordinates. + +This problem also uses a small optimization: when iterating through each point at position `i`, we only consider points after `i` since points before `i` have already been considered. + + + + +```cpp +int maxPoints(vector>& points) { + int max_count = 0, n = points.size(); + for (int i = 0; i < n; ++i) { + unordered_map cache; // + int same_xy = 1, same_y = 1; + for (int j = i + 1; j < n; ++j) { + if (points[i][1] == points[j][1]) { + ++same_y; + if (points[i][0] == points[j][0]) { + ++same_xy; + } + } else { + double dx = points[i][0] - points[j][0], + dy = points[i][1] - points[j][1]; + ++cache[dx / dy]; + } + } + max_count = max(max_count, same_y); + for (auto item : cache) { + max_count = max(max_count, same_xy + item.second); + } + } + return max_count; +} +``` + + + + +```py +def maxPoints(points: List[List[int]]) -> int: + max_count, n = 0, len(points) + + for i, point1 in enumerate(points): + cache = dict() # + same_xy, same_y = 1, 1 + + for point2 in points[i + 1:]: + if point1[1] == point2[1]: + same_y += 1 + if point1[0] == point2[0]: + same_xy += 1 + else: + dx, dy = point1[0] - point2[0], point1[1] - point2[1] + cache[dx / dy] = cache.get(dx / dy, 0) + 1 + + max_count = max(max_count, same_y) + for count in cache.values(): + max_count = max(max_count, same_xy + count) + + return max_count + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx new file mode 100644 index 00000000..5eaeb542 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 56 +--- + +# 10.9 Multisets and Mappings + +## [332. Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) + +### Problem Description + +Given a person's flight records with departure and arrival airports, starting from JFK, determine the flight order. If there are multiple possibilities, return the lexicographically smallest sequence. + +### Input and Output Example + +Input is a 2D string array representing pairs of departure and arrival airports; output is a 1D string array representing the flight order. + +``` +Input: [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]] +Output: ["JFK", "MUC", "LHR", "SFO", "SJC"] +``` + +### Solution Explanation + +We can first use a hash table to store the departure and arrival airports, where the key is the departure airport, and the value is a multiset (ordered set) representing the corresponding arrival airports. Since a person may take the same route multiple times, we need to use a multiset to store duplicate values. After storing, we can use a stack/DFS to reconstruct the flight order from the endpoint to the starting point, and then reverse the result to get the order from the start to the endpoint. + +Since Python doesn't have a built-in multiset implementation, we can store an array and sort it. Alternatively, we can use the `Counter` structure, selecting the smallest key each time we search for the next airport. + + + + +```cpp +vector findItinerary(vector>& tickets) { + vector itinerary; + unordered_map> cache; + for (const auto& ticket : tickets) { + cache[ticket[0]].insert(ticket[1]); + } + stack s; + s.push("JFK"); + while (!s.empty()) { + string t = s.top(); + if (cache[t].empty()) { + itinerary.push_back(t); + s.pop(); + } else { + s.push(*cache[t].begin()); + cache[t].erase(cache[t].begin()); + } + } + reverse(itinerary.begin(), itinerary.end()); + return itinerary; +} +``` + + + + +```py +def findItinerary(tickets: List[List[str]]) -> List[str]: + itinerary = [] + cache = dict() + + for ticket in tickets: + if ticket[0] not in cache: + cache[ticket[0]] = [] + cache[ticket[0]].append(ticket[1]) + + for ticket in cache.keys(): + cache[ticket].sort(reverse=True) + + s = ["JFK"] + while len(s) > 0: + t = s[-1] + if t not in cache or len(cache[t]) == 0: + itinerary.append(t) + s.pop() + else: + t_next = cache[t].pop() + s.append(t_next) + + return list(reversed(itinerary)) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png new file mode 100644 index 00000000..a0f0fc51 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png new file mode 100644 index 00000000..9a10d41c Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png new file mode 100644 index 00000000..bc65f388 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png new file mode 100644 index 00000000..84c2f60e Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png new file mode 100644 index 00000000..310069c9 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json new file mode 100644 index 00000000..5fd3d33c --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "10. Ingenious Use of Data Structures", + "position": 10, + "link": { + "type": "generated-index", + "description": "Chapter 10: Ingenious Use of Data Structures" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md new file mode 100644 index 00000000..76271dfe --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 59 +--- + +# 11.1 Introduction + +Strings can be considered as arrays of characters. Since strings are a frequently used data type in programming, there are many problems related to string manipulation. Below are some common types of such problems. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx new file mode 100644 index 00000000..d7d7bfb6 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx @@ -0,0 +1,351 @@ +--- +sidebar_position: 60 +--- + +# 11.2 String Comparison + +## [242. Valid Anagram](https://leetcode.com/problems/valid-anagram/) + +### Problem Description + +Determine if two strings contain exactly the same characters. + +### Input and Output Example + +Input two strings and output a boolean indicating whether the two strings meet the condition. + +``` +Input: s = "anagram", t = "nagaram" +Output: true +``` + +### Solution Explanation + +We can use a hash table or an array to count the frequency of each character in both strings. If the frequencies match, it means the strings contain the exact same characters. + + + + + +```cpp +bool isAnagram(string s, string t) { + if (s.length() != t.length()) { + return false; + } + vector counts(26, 0); + for (int i = 0; i < s.length(); ++i) { + ++counts[s[i] - ’a’]; + --counts[t[i] - ’a’]; + } + return all_of(counts.begin(), counts.end(), [](int c) { return c == 0; }); +} +``` + + + + +```py +def isAnagram(s: str, t: str) -> bool: + if len(s) != len(t): + return False + counter = Counter(s) + counter.subtract(t) + return all(v == 0 for v in counter.values()) +``` + + + + + +## [205. Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) + +### Problem Description + +Determine if two strings are isomorphic. Two strings are isomorphic if characters in one string can be replaced to get the other string, while ensuring that no two different characters map to the same character. + +### Input and Output Example + +Input two strings and output a boolean indicating whether they meet the condition. + +``` +Input: s = "paper", t = "title" +Output: true +``` + +In this example, by replacing `p`, `a`, `e`, `r` in `s` with `t`, `i`, `l`, `e` respectively, the two strings can become identical. + +### Solution Explanation + +We can reformulate the problem: track the first appearance position of each character in both strings. If the characters at the same position in both strings have the same first appearance position, the strings are isomorphic. + +For example, for "paper" and "title," if we reach the third characters `p` and `t`, we find their first appearances are at the first character, which satisfies the isomorphic condition. We can use a hash table for storage or a fixed-length array of size 128 (for the total number of ASCII characters). + + + + +```cpp +bool isIsomorphic(string s, string t) { + vector s_init(128, 0), t_init(128, 0); + for (int i = 0; i < s.length(); ++i) { + if (s_init[s[i]] != t_init[t[i]]) { + return false; + } + s_init[s[i]] = t_init[t[i]] = i + 1; + } + return true; +} +``` + + + + +```py +def isIsomorphic(s: str, t: str) -> bool: + s_init, t_init = [0] * 128, [0] * 128 + + for i in range(len(s)): + if s_init[ord(s[i])] != t_init[ord(t[i])]: + return False + s_init[ord(s[i])] = t_init[ord(t[i])] = i + 1 + + return True + +``` + + + + + +## [647. Palindromic Substrings](https://leetcode.com/problems/palindromic-substrings/) + +### Problem Description + +Given a string, find how many of its substrings are palindromic. A palindrome is defined as being symmetric from left to right. + +### Input and Output Example + +Input is a string, and output is an integer representing the count of palindromic substrings. + +``` +Input: "aaa" +Output: 6 +``` + +The six palindromic substrings are ["a", "a", "a", "aa", "aa", "aaa"]. + +### Solution Explanation + +We can start from every position in the string and extend to the left and right, counting how many palindromic substrings have the current position as their center. + + + + +```cpp +// Auxiliary function +int extendSubstrings(string s, int l, int r) { + int count = 0, n = s.length(); + while (l >= 0 && r < n && s[l] == s[r]) { + --l; + ++r; + ++count; + } + return count; +} +// Main function +int countSubstrings(string s) { + int count = 0; + for (int i = 0; i < s.length(); ++i) { + count += extendSubstrings(s, i, i); // Odd length + count += extendSubstrings(s, i, i + 1); // Even length + } + return count; +} +``` + + + + +```py +# Auxiliary function +def extendSubstrings(s: str, l: int, r: int) -> int: + count, n = 0, len(s) + while l >= 0 and r < n and s[l] == s[r]: + count += 1 + l -= 1 + r += 1 + return count + +# Main function +def countSubstrings(s: str) -> int: + return sum( + # Odd length + Even length + extendSubstrings(s, i, i) + extendSubstrings(s, i, i + 1) + for i in range(len(s)) + ) + +``` + + + + + +## [696. Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/) + +### Problem Description + +Given a binary string (composed of '0's and '1's), count the number of non-empty substrings where the number of '0's and '1's are equal, and all '0's and '1's must appear consecutively (e.g., "0011", "1100"; but "0101" is not valid). + +### Input and Output Example + +Input is a string, and output is an integer representing the count of valid substrings. + +``` +Input: "00110011" +Output: 6 +``` + +In this example, the six substrings where '0's and '1's are equal are ["0011", "01", "1100", "10", "0011", "01"]. + +### Solution Explanation + +Traverse the string from left to right, keeping track of the length of consecutive characters that are the same as the current character, as well as the length of the consecutive different characters before it. For example, in "00110", the last '0' has: +- A consecutive length of 1 for '0', because there's only one '0' at the end. +- A consecutive length of 2 for '1', because there are two '1's right before it. + +If the length of the consecutive different characters is greater than or equal to the current consecutive length, then there exists exactly one valid substring ending at the current character. + + + + +```cpp +int countBinarySubstrings(string s) { + int prev = 0, cur = 1, count = 0; + for (int i = 1; i < s.length(); ++i) { + if (s[i] == s[i - 1]) { + ++cur; + } else { + prev = cur; + cur = 1; + } + if (prev >= cur) { + ++count; + } + } + return count; +} +``` + + + + +```py +def countBinarySubstrings(s: str) -> int: + prev, cur, count = 0, 1, 0 + + for i in range(1, len(s)): + if s[i] == s[i - 1]: + cur += 1 + else: + prev = cur + cur = 1 + if prev >= cur: + count += 1 + + return count + +``` + + + + + +## [1249. Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/) + +### Problem Description + +Given a string containing letters and parentheses, determine the minimum number of parentheses to remove to make the string valid. + +### Input and Output Example + +Input is a string, and output is a valid string with the longest possible length after removal. + +``` +Input: s = "lee(t(c)o)de)" +Output: "lee(t(c)o)de" +``` + +Returning "lee(t(co)de)" or "lee(t(c)ode)" is also considered correct. + +### Solution Explanation + +Since only one type of parenthesis is involved, we don't necessarily need a stack to track them. Instead, we can use a temporary variable to count how many more left parentheses are present than right parentheses at any position. + +- If this count becomes negative during traversal, it means there are extra right parentheses that need to be removed. +- At the end of the traversal, if the count is positive, it means there are extra left parentheses that need to be removed by traversing from right to left. + +A small optimization here is to first mark all positions that need to be removed and then remove them in one go. + + + + +```cpp +string minRemoveToMakeValid(string s) { + int count = 0, n = s.length(); + char to_delete = '#'; + for (char& c : s) { + if (c == '(') { + ++count; + } else if (c == ')') { + if (count > 0) { + --count; + } else { + c = to_delete; + } + } + } + for (int i = n - 1; i >= 0; --i) { + if (count == 0) break; + if (s[i] == '(') { + s[i] = to_delete; + --count; + } + } + s.erase(remove_if(s.begin(), s.end(), + [to_delete](char c) { return c == to_delete; }), + s.end()); + return s; +} + +``` + + + + +```py +def minRemoveToMakeValid(s: str) -> str: + count, n = 0, len(s) + to_delete = set() + + for i in range(n): + if s[i] == "(": + count += 1 + elif s[i] == ")": + if count > 0: + count -= 1 + else: + to_delete.add(i) + + for i in range(n - 1, -1, -1): + if count == 0: + break + if s[i] == "(": + to_delete.add(i) + count -= 1 + + return "".join(s[i] for i in range(n) if i not in to_delete) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx new file mode 100644 index 00000000..2571954d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx @@ -0,0 +1,129 @@ +--- +sidebar_position: 61 +--- + +# 11.3 String Parsing + +## [227. Basic Calculator II](https://leetcode.com/problems/basic-calculator-ii/) + +### Problem Description + +Given a string containing addition, subtraction, multiplication, and division of integers, calculate the result. Division truncates towards zero. + +### Input and Output Example + +Input is a valid arithmetic string, and output is an integer representing the result. + +``` +Input: " 3+5 / 2 " +Output: 5 +``` + +In this example, since division has a higher priority than addition, the result is 5 rather than 4. + +### Solution Explanation + +If we prepend a `+` sign to the left of the string, it doesn't change the result, and the string can be divided into multiple pairs of ``. This allows us to process the string from left to right. Since multiplication and division have higher precedence than addition and subtraction, we need an intermediate variable to store results of high-priority operations. + +This type of problem also tests edge cases, such as strings without operators or with multiple spaces. + + + + +```cpp +// Helper function to parse a number starting from position i. +int parseNum(const string& s, int& i) { + int num = 0, n = s.length(); + while (i < n && isdigit(s[i])) { + num = 10 * num + (s[i++] - '0'); + } + return num; +} + +// Main function +int calculate(string s) { + char op = '+'; + long global_num = 0, local_num = 0; + int i = -1, n = s.length(); + while (++i < n) { + if (s[i] == ' ') { + continue; + } + long num = parseNum(s, i); + switch (op) { + case '+': + global_num += local_num; + local_num = num; + break; + case '-': + global_num += local_num; + local_num = -num; + break; + case '*': + local_num *= num; + break; + case '/': + local_num /= num; + break; + } + if (i < n) { + op = s[i]; + } + } + return global_num + local_num; +} + +``` + + + + +```py +from typing import Tuple + +# Helper function to parse a number starting from position i. +# Returns (number, next position i) +def parseNum(s: str, i: int) -> Tuple[int, int]: + num, n = 0, len(s) + while i < n and s[i].isdigit(): + num = 10 * num + int(s[i]) + i += 1 + return (num, i) + +# Main function +def calculate(s: str) -> int: + op = "+" + global_num, local_num = 0, 0 + i, n = 0, len(s) + + while i < n: + if s[i] == " ": + i += 1 + continue + + num, i = parseNum(s, i) + + match op: + case "+": + global_num += local_num + local_num = num + case "-": + global_num += local_num + local_num = -num + case "*": + local_num *= num + case "/": + # int() performs truncation towards zero, unlike // for negatives. + local_num = int(local_num / num) + + if i < n: + op = s[i] + i += 1 + + return global_num + local_num + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx new file mode 100644 index 00000000..f52314bc --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx @@ -0,0 +1,106 @@ +--- +sidebar_position: 62 +--- + +# 11.4 String Matching + +## [28. Implement strStr()](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/) + +### Problem Description + +Determine whether a string is a substring of another string, and return its starting index. + +### Input and Output Example + +Input a parent string and a substring, and output an integer representing the position of the substring in the parent string. Return -1 if it doesn't exist. + +``` +Input: haystack = "hello", needle = "ll" +Output: 2 +``` + +### Solution Explanation + +We can use the famous Knuth-Morris-Pratt (KMP) algorithm to achieve matching in $O(m + n)$ time using dynamic programming. Here we define the `dp` array where `dp[i]` represents the longest prefix of `needle` that is also a suffix ending at position `i`. For example, for `needle = "ababaca"`, the `dp` array is `[-1, -1, 0, 1, 2, -1, 0]`, indicating the longest matches: [None, None, "a", "ab", "aba", None, "a"]. + +This problem is complex, and beginners may skip it temporarily. + + + + +```cpp +// Auxiliary function +vector computeDp(const string &needle) { + int n = needle.length(); + vector dp(n, -1); + for (int j = 1, k = -1; j < n; ++j) { + while (k > -1 && needle[k + 1] != needle[j]) { + k = dp[k]; // If mismatch, backtrack to the previous prefix + } + if (needle[k + 1] == needle[j]) { + ++k; // Match found, increase the match length + } + dp[j] = k; // Update the prefix match position + } + return dp; +} +// Main function +int strStr(const string &haystack, const string &needle) { + int m = haystack.length(), n = needle.length(); + vector dp = computeDp(needle); + for (int i = 0, k = -1; i < m; ++i) { + while (k > -1 && needle[k + 1] != haystack[i]) { + k = dp[k]; // If mismatch, backtrack to the previous match + } + if (needle[k + 1] == haystack[i]) { + ++k; / Match found, increase the match length + } + if (k == n - 1) { + return i - n + 1; // Match complete + } + } + return -1; +} +``` + + + + +```py +from typing import List + +# Auxiliary function +def computeDp(needle: str) -> List[int]: + n = len(needle) + dp = [-1] * n + k = -1 + for j in range(1, n): + while k > -1 and needle[k + 1] != needle[j]: + k = dp[k] # If mismatch, backtrack to the previous prefix + if needle[k + 1] == needle[j]: + k += 1 # Match found, increase the match length + dp[j] = k # Update the prefix match position + return dp + +# Main function +def strStr(haystack: str, needle: str) -> int: + m, n = len(haystack), len(needle) + if n == 0: + return 0 # Edge case for an empty needle + + dp = computeDp(needle) + k = -1 + for i in range(m): + while k > -1 and needle[k + 1] != haystack[i]: + k = dp[k] # If mismatch, backtrack to the previous match + if needle[k + 1] == haystack[i]: + k += 1 # Match found, increase the match length + if k == n - 1: + return i - n + 1 # Match complete + return -1 + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md new file mode 100644 index 00000000..c0d8083e --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 63 +--- + +# 11.5 Exercises + +## Basic Difficulty + +### [409. Longest Palindrome](https://leetcode.com/problems/longest-palindrome/) + +Calculate the maximum length of a palindrome string that can be constructed from a set of characters. Auxiliary data structures can be used for counting. + +--- + +### [3. Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) + +Compute the length of the longest substring without repeating characters. Similarly, auxiliary data structures can be used for tracking character occurrences. + +--- + +## Advanced Difficulty + +### [772. Basic Calculator III](https://leetcode.com/problems/basic-calculator-iii/) + +A follow-up to Problem 227. Highly recommended for practice. + +--- + +### [5. Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/) + +Similar to the subsequence problems discussed earlier, subarray or substring problems can often be solved using dynamic programming. Start by implementing a $O(n^2)$ solution with dynamic programming, then explore Manacher's Algorithm, which can solve the problem in $O(n)$ time. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json new file mode 100644 index 00000000..f81fb7bd --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "11. Tricky String Problems", + "position": 11, + "link": { + "type": "generated-index", + "description": "Chapter 11: Tricky String Problems" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md new file mode 100644 index 00000000..a0c1c3ef --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 64 +--- + +# 12.1 Data Structure Introduction + +A (singly) `linked list` is a data structure composed of nodes and pointers. Each node contains a value and a pointer to the next node. As a result, many linked list problems can be solved using recursion. Unlike arrays, a linked list cannot directly access the value of any node; it must traverse through pointers to reach the desired node. Similarly, the length of a linked list cannot be determined unless it is fully traversed or tracked using another data structure. LeetCode’s default representation of a linked list is as follows. + + + + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + + + + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + + + + + +When performing operations on a linked list, especially when deleting nodes, issues with memory or pointers often arise due to directly modifying the current node. Two techniques can help mitigate these problems: + +1. Try to operate on the next node rather than the current node itself. +2. Create a dummy node that points to the head of the current linked list. This ensures that even if all nodes in the original list are deleted, the dummy node persists, and you can safely return `dummy->next`. + +:::warning + +In most algorithm problems, explicit memory deletion is unnecessary. When solving LeetCode problems, you can simply adjust pointers without deallocating memory. However, in real-world software engineering, it is recommended to explicitly free unused memory or use smart pointers to manage it efficiently. + +::: \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx new file mode 100644 index 00000000..80920253 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx @@ -0,0 +1,272 @@ +--- +sidebar_position: 65 +--- + +# 12.2 Basic Operations on Linked Lists + +## [206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) + +### Problem Description + +Reverse a linked list. + +### Input and Output Example + +Input a linked list, output the reversed linked list. + +``` +Input: 1->2->3->4->5->nullptr +Output: 5->4->3->2->1->nullptr +``` + +### Solution Explanation + +Reversing a linked list is a fundamental skill that must be mastered. We provide two approaches—recursive and iterative. It's recommended to learn both. + +Recursive Approach: + + + + +```cpp +ListNode* reverseList(ListNode* head, ListNode* head_prev = nullptr) { + if (head == nullptr) { + return head_prev; + } + ListNode* head_next = head->next; + head->next = head_prev; + return reverseList(head_next, head); +} +``` + + + + +```py +def reverseList( + head: Optional[ListNode], head_prev: Optional[ListNode] = None +) -> Optional[ListNode]: + if head is None: + return head_prev + head_next = head.next + head.next = head_prev + return reverseList(head_next, head) +``` + + + + + +The non-recursive implementation is as follows: + + + + +```cpp +ListNode* reverseList(ListNode* head) { + ListNode *head_prev = nullptr, *head_next; + while (head) { + head_next = head->next; + head->next = head_prev; + head_prev = head; + head = head_next; + } + return head_prev; +} +``` + + + + +```py +def reverseList(head: Optional[ListNode]) -> Optional[ListNode]: + head_prev = None + while head is not None: + head_next = head.next + head.next = head_prev + head_prev = head + head = head_next + return head_prev +``` + + + + + +## [21. Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) + +### Problem Description + +Given two sorted linked lists, merge them into one sorted linked list. + +### Input and Output Example + +Input: Two linked lists. +Output: A linked list representing the merged result. + +``` +Input: 1->2->4, 1->3->4 +Output: 1->1->2->3->4->4 +``` + +### Solution Explanation + +We provide both recursive and non-recursive implementations. +The recursive implementation is as follows: + + + + +```cpp +ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (l2 == nullptr) { + return l1; + } + if (l1 == nullptr) { + return l2; + } + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } + l2->next = mergeTwoLists(l1, l2->next); + return l2; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + if l1 is None or l2 is None: + return l1 or l2 + if l1.val < l2.val: + l1.next = mergeTwoLists(l1.next, l2) + return l1 + l2.next = mergeTwoLists(l1, l2.next) + return l2 +``` + + + + + +The non-recursive implementation is as follows: + + + + +```cpp +ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode *dummy = new ListNode(0), *node = dummy; + while (l1 && l2) { + if (l1->val < l2->val) { + node->next = l1; + l1 = l1->next; + } else { + node->next = l2; + l2 = l2->next; + } + node = node->next; + } + node->next = l1 == nullptr ? l2 : l1; + return dummy->next; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + dummy = ListNode() + head = dummy + + while l1 and l2: + if l1.val < l2.val: + dummy.next = l1 + l1 = l1.next + else: + dummy.next = l2 + l2 = l2.next + dummy = dummy.next + + dummy.next = l1 or l2 + return head.next + +``` + + + + + +## [24. Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) + +### Problem Description + +Given a linked list, swap every two adjacent nodes. + +### Input and Output Example + +Input a linked list, output the linked list after swapping nodes in pairs. + +``` +Input: 1->2->3->4 +Output: 2->1->4->3 +``` + +### Solution Explanation + +Use pointers to perform the swap operation. The problem is not very difficult, but requires careful attention. + + + + +```cpp +ListNode* swapPairs(ListNode* head) { + ListNode *node1 = head, *node2; + if (node1 && node1->next) { + node2 = node1->next; + node1->next = node2->next; + node2->next = node1; + head = node2; + while (node1->next && node1->next->next) { + node2 = node1->next->next; + node1->next->next = node2->next; + node2->next = node1->next; + node1->next = node2; + node1 = node2->next; + } + } + return head; +} +``` + + + + +```py +def swapPairs(head: Optional[ListNode]) -> Optional[ListNode]: + node1 = head + if node1 is not None and node1.next is not None: + node2 = node1.next + node1.next = node2.next + node2.next = node1 + head = node2 + while node1.next is not None and node1.next.next is not None: + node2 = node1.next.next + node1.next.next = node2.next + node2.next = node1.next + node1.next = node2 + node1 = node2.next + return head +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx new file mode 100644 index 00000000..3c2843b8 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx @@ -0,0 +1,143 @@ +--- +sidebar_position: 66 +--- + +# 12.3 Other Linked List Techniques + +## [160. Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists/) + +### Problem Description + +Given two linked lists, determine if they intersect at a point and find the intersecting node. + +### Input and Output Example + +Input consists of two linked lists, output is a node. If there is no intersection, return `nullptr`. + +``` +Input: +A: a1 -> a2 + | + v + c1 -> c2 -> c3 + ^ + | +B: b1 -> b2 -> b3 +Output: c1 +``` + +### Solution Explanation + +Assume the distance from the head of linked list A to the intersection is `a`, the distance from the head of linked list B to the intersection is `b`, and the distance from the intersection to the end of the lists is `c`. + +We use two pointers starting at the heads of the two linked lists and move them forward at the same speed. When a pointer reaches the end of a list, it continues from the head of the other list. With this approach, both pointers will meet at the intersection node after `a + b + c` steps. + + + + +```cpp +ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + ListNode *l1 = headA, *l2 = headB; + while (l1 != l2) { + l1 = l1 != nullptr ? l1->next : headB; + l2 = l2 != nullptr ? l2->next : headA; + } + return l1; +} +``` + + + + +```py +def getIntersectionNode( + headA: ListNode, headB: ListNode +) -> Optional[ListNode]: + l1 = headA + l2 = headB + while l1 != l2: + l1 = l1.next if l1 is not None else headB + l2 = l2.next if l2 is not None else headA + return l1 +``` + + + + + +## [234. Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/) + +### Problem Description + +Determine if a linked list is a palindrome using $O(1)$ space complexity. + +### Input and Output Example + +Input: A linked list. +Output: A boolean indicating whether the linked list is a palindrome. + +``` +Input: 1->2->3->2->1 +Output: true +``` + +### Solution Explanation + +First, use a slow and fast pointer to find the middle of the linked list. Then split the list into two halves. Reverse the second half and compare the two halves for equality. + + + + +```cpp +bool isPalindrome(ListNode* head) { + if (head == nullptr || head->next == nullptr) { + return true; + } + ListNode *slow = head, *fast = head; + while (fast->next && fast->next->next) { + slow = slow->next; + fast = fast->next->next; + } + slow->next = reverseList(slow->next); // Refer to problem 206. + slow = slow->next; + while (slow != nullptr) { + if (head->val != slow->val) { + return false; + } + head = head->next; + slow = slow->next; + } + return true; +} +``` + + + + +```py +def isPalindrome(head: Optional[ListNode]) -> bool: + if head is None or head.next is None: + return True + + slow, fast = head, head + + while fast.next is not None and fast.next.next is not None: + slow = slow.next + fast = fast.next.next + + slow.next = reverseList(slow.next) # Refer to problem 206. + slow = slow.next + + while slow is not None: + if head.val != slow.val: + return False + head = head.next + slow = slow.next + + return True + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md new file mode 100644 index 00000000..c73fb065 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 67 +--- + +# 12.4 Exercises + +## Basic Difficulty + +### [83. Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) + +Although LeetCode doesn't enforce it, we still recommend freeing memory, especially when the problem requires deletion. + +--- + +### [328. Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/) + +This problem is actually quite simple; don’t overcomplicate it. + +--- + +### [19. Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/) + +Since we can use the fast and slow pointer technique to find the midpoint, we can also use a similar approach to locate the nth node from the end, without a second traversal. + +--- + +## Advanced Difficulty + +### [148. Sort List](https://leetcode.com/problems/sort-list/) + +After using fast and slow pointers to find the midpoint of the linked list, you can perform merge sort on it. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json new file mode 100644 index 00000000..921d0a45 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "12. The Three Musketeers of Pointers: Linked Lists", + "position": 12, + "link": { + "type": "generated-index", + "description": "Chapter 12: The Three Musketeers of Pointers: Linked Lists" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx new file mode 100644 index 00000000..f7af25dc --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx @@ -0,0 +1,36 @@ +--- +sidebar_position: 68 +--- + +# 13.1 Data Structure Introduction + +As an upgraded version of the (single) linked list, the trees we commonly encounter are typically `binary trees`, where each node has at most two child nodes. Unless otherwise specified, trees are assumed to have no circular structures. LeetCode's default representation of trees is as follows: + + + + +```cpp +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode(int x) : val(x), left(NULL), right(NULL) {} +}; +``` + + + + +```py +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right +``` + + + + + +It can be seen that the primary difference compared to a linked list is the addition of a pointer for a second child node. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx new file mode 100644 index 00000000..f7fa7117 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx @@ -0,0 +1,481 @@ +--- +sidebar_position: 69 +--- + +# 13.2 Tree Recursion + +For simple recursion problems, some LeetCode experts prefer to write one-line code, solving problems with a single line. While we will showcase such solutions, beginners are still advised to use multi-line if-else statements. + +In many cases, the recursive implementation for trees is similar to the recursive implementation for depth-first search. Hence, this book does not differentiate between the two. + +## [104. Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) + +### Problem Description + +Find the maximum depth of a binary tree. + +### Input and Output Example + +The input is a binary tree, and the output is an integer representing the maximum depth of the tree. + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: 3 +``` + +### Solution Explanation + +Using recursion, we can easily determine the maximum depth. + + + + +```cpp +int maxDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + return max(maxDepth(root->left), maxDepth(root->right)) + 1; +} +``` + + + + +```py +def maxDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + return max(maxDepth(root.left), maxDepth(root.right)) + 1 +``` + + + + + +## [110. Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) + +### Problem Description + +Determine whether a binary tree is balanced. A balanced tree is defined as a tree in which the maximum depth difference between any two child nodes of a node is no greater than 1. + +### Input and Output Example + +The input is a binary tree, and the output is a boolean indicating whether the tree is balanced. + +``` +Input: + 1 + / \ + 2 2 + / \ + 3 3 + / \ +4 4 +Output: false +``` + +### Solution Explanation + +The solution is similar to calculating the maximum depth of a tree but with two key differences: + +1. The depth of the subtrees must be calculated first before performing the comparison. +2. If an imbalance is detected while processing a subtree, return -1 immediately to signal imbalance. This allows ancestor nodes to avoid redundant checks. (In this problem, determining imbalance is straightforward by taking the absolute difference, but avoiding redundant computations is crucial in scenarios involving more costly comparisons.) + + + + +```cpp +// Auxiliary function +int balancedDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + int left = balancedDepth(root->left); + int right = balancedDepth(root->right); + if (left == -1 || right == -1 || abs(left - right) > 1) { + return -1; + } + return max(left, right) + 1; +} +// Main function +bool isBalanced(TreeNode* root) { return balancedDepth(root) != -1; } +``` + + + + +```py +# Auxiliary function +def balancedDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + left = balancedDepth(root.left) + right = balancedDepth(root.right) + if left == -1 or right == -1 or abs(left - right) > 1: + return -1 + return max(left, right) + 1 + +# Main function +def isBalanced(root: Optional[TreeNode]) -> bool: + return balancedDepth(root) != -1 + +``` + + + + + +## [543. Diameter of Binary Tree](https://leetcode.com/problems/diameter-of-binary-tree/) + +### Problem Description + +Find the longest diameter of a binary tree. The diameter is defined as the undirected distance between any two nodes in the binary tree. + +### Input and Output Example + +Input is a binary tree, and output is an integer representing the longest diameter. + +``` +Input: + 1 + / \ + 2 3 + / \ + 4 5 +Output: 3 +``` + +In this example, the longest diameter is [4,2,1,3] and [5,2,1,3]. + +### Solution Explanation + +We can use recursion to solve this problem. It's important to note that when processing a subtree, the updated longest diameter and the returned value from the recursion are different. + +The updated longest diameter refers to the diameter passing through the root of the subtree (i.e., the sum of the lengths of the left and right subtrees). The function's return value, however, is the longest diameter with the root of the subtree as an endpoint (i.e., the length of one side of the subtree). This return value design allows the parent node's longest diameter to be updated recursively. + + + + +```cpp +// Auxiliary function +int updateDiameter(TreeNode* node, int& diameter) { + if (node == nullptr) { + return 0; + } + int left = updateDiameter(node->left, diameter); + int right = updateDiameter(node->right, diameter); + diameter = max(diameter, left + right); + return max(left, right) + 1; +} +// Main function +int diameterOfBinaryTree(TreeNode* root) { + int diameter = 0; + updateDiameter(root, diameter); + return diameter; +} +``` + + + + +```py +# Auxiliary function +def updateDiameter(node: Optional[TreeNode], diameter: List[int]) -> int: + if node is None: + return 0 + left = updateDiameter(node.left, diameter) + right = updateDiameter(node.right, diameter) + diameter[0] = max(diameter[0], left + right) + return max(left, right) + 1 + +# Main function +def diameterOfBinaryTree(root: Optional[TreeNode]) -> int: + diameter = [0] + updateDiameter(root, diameter) + return diameter[0] + +``` + + + + + +## [437. Path Sum III](https://leetcode.com/problems/path-sum-iii/) + +### Problem Description + +Given a binary tree of integers, find the number of paths where the sum of the node values equals a given target. + +### Input and Output Example + +Input is a binary tree and a target integer. Output is an integer representing the number of paths that satisfy the condition. + +``` +Input: sum = 8, tree = + 10 + / \ + 5 -3 + / \ \ + 3 2 11 + / \ \ + 3 -2 1 +Output: 3 +``` + +In this example, there are three paths where the sum equals 8: `[[5,3],[5,2,1],[-3,11]]`. + +### Solution Explanation + +When recursively processing each node, consider two scenarios: +1. If the current node is included in the path, subsequent nodes must be added continuously, or the path stops. +2. If the current node is not included, restart the path calculation from its left and right children. + +A convenient way to handle this is to create an auxiliary function specifically for calculating paths that start from the current node. + + + + +```cpp +// Auxiliary function +// Use long long to prevent overflow with large test cases; int is usually sufficient. +long long pathSumStartWithRoot(TreeNode* root, long long targetSum) { + if (root == nullptr) { + return 0; + } + return (root->val == targetSum) + + pathSumStartWithRoot(root->left, targetSum - root->val) + + pathSumStartWithRoot(root->right, targetSum - root->val); +} +// Main function +int pathSum(TreeNode* root, int targetSum) { + if (root == nullptr) { + return 0; + } + return pathSumStartWithRoot(root, targetSum) + + pathSum(root->left, targetSum) + pathSum(root->right, targetSum); +} +``` + + + + +```py +# Auxiliary function +def pathSumStartWithRoot(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + int(root.val == targetSum) + + pathSumStartWithRoot(root.left, targetSum - root.val) + + pathSumStartWithRoot(root.right, targetSum - root.val) + ) + +# Main function +def pathSum(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + pathSumStartWithRoot(root, targetSum) + + pathSum(root.left, targetSum) + + pathSum(root.right, targetSum) + ) + +``` + + + + + +## [101. Symmetric Tree](https://leetcode.com/problems/symmetric-tree/) + +### Problem Description + +Determine whether a binary tree is symmetric. + +### Input and Output Example + +Input a binary tree, output a boolean indicating whether the tree is symmetric. + +``` +Input: + 1 + / \ + 2 2 + / \ / \ +3 4 4 3 +Output: true +``` + +### Solution Explanation + +Determining whether a tree is symmetric is equivalent to checking if its left and right subtrees are symmetric. A common approach for such problems is the "four-step method": +1. If both subtrees are null, they are symmetric. +2. If one subtree is null and the other is not, they are not symmetric. +3. If the root values of the two subtrees are not equal, they are not symmetric. +4. Based on symmetry requirements, recursively process the subtrees. + + + + +```cpp +// Auxiliary function +bool isLeftRightSymmetric(TreeNode* left, TreeNode* right) { + if (left == nullptr && right == nullptr) { + return true; + } + if (left == nullptr or right == nullptr) { + return false; + } + if (left->val != right->val) { + return false; + } + return isLeftRightSymmetric(left->left, right->right) && + isLeftRightSymmetric(left->right, right->left); +} +// Main function +bool isSymmetric(TreeNode* root) { + if (root == nullptr) { + return true; + } + return isLeftRightSymmetric(root->left, root->right); +} +``` + + + + +```py +# Auxiliary function +def isLeftRightSymmetric( + left: Optional[TreeNode], right: Optional[TreeNode] +) -> bool: + if left is None and right is None: + return True + if left is None or right is None: + return False + if left.val != right.val: + return False + return ( + isLeftRightSymmetric(left.left, right.right) and + isLeftRightSymmetric(left.right, right.left) + ) + +# Main function +def isSymmetric(root: Optional[TreeNode]) -> bool: + if root is None: + return True + return isLeftRightSymmetric(root.left, root.right) + +``` + + + + + +## [1110. Delete Nodes And Return Forest](https://leetcode.com/problems/delete-nodes-and-return-forest/) + +### Problem Description + +Given an integer binary tree and some integers, delete the nodes corresponding to these integers and return the remaining subtrees. + +### Input and Output Example + +Input is an integer binary tree and a one-dimensional integer array. Output is an array where each position contains a subtree (its root node). + +``` +Input: to_delete = [3,5], tree = + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 +Output: [ + 1 + / + 2 + / +4 ,6 ,7] +``` + +### Solution Explanation + +The key details in this problem include how to recursively handle the original tree and when to disconnect pointers. Additionally, to efficiently find nodes to delete, you can create a hash table for quick lookup. It is highly recommended that readers attempt to implement this problem after reviewing the solution to deepen their understanding and application of recursion. + + + + +```cpp +// Auxiliary function +TreeNode* moveNodesToForest(TreeNode* root, unordered_set& undeleted, + vector& forest) { + if (root == nullptr) { + return nullptr; + } + root->left = moveNodesToForest(root->left, undeleted, forest); + root->right = moveNodesToForest(root->right, undeleted, forest); + if (undeleted.contains(root->val)) { + if (root->left != nullptr) { + forest.push_back(root->left); + } + if (root->right != nullptr) { + forest.push_back(root->right); + } + root = nullptr; + } + return root; +} +// Main function +vector delNodes(TreeNode* root, vector& to_delete) { + vector forest; + unordered_set undeleted(to_delete.begin(), to_delete.end()); + root = moveNodesToForest(root, undeleted, forest); + if (root != nullptr) { + forest.push_back(root); + } + return forest; +} +``` + + + + +```py +# Auxiliary function +def moveNodesToForest( + root: Optional[TreeNode], undeleted: Set[int], forest: List[TreeNode] +) -> Optional[TreeNode]: + if root is None: + return None + + root.left = moveNodesToForest(root.left, undeleted, forest) + root.right = moveNodesToForest(root.right, undeleted, forest) + + if root.val in undeleted: + if root.left is not None: + forest.append(root.left) + if root.right is not None: + forest.append(root.right) + root = None + + return root + +# Main function +def delNodes(root: Optional[TreeNode], to_delete: List[int]) -> List[TreeNode]: + forest = [] + undeleted = set(to_delete) + root = moveNodesToForest(root, undeleted, forest) + if root is not None: + forest.append(root) + return forest + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx new file mode 100644 index 00000000..ca3c5b3e --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx @@ -0,0 +1,92 @@ +--- +sidebar_position: 70 +--- + +# 13.3 Level Order Traversal + +We can use Breadth-First Search (BFS) for level order traversal. Note that it is unnecessary to use two queues to separately store the current layer's nodes and the next layer's nodes. At the beginning of each layer's traversal, the number of nodes in the current queue equals the number of nodes in the current layer. By controlling the traversal to only process that many nodes, we ensure that the traversal covers only the current layer. + +## [637. Average of Levels in Binary Tree](https://leetcode.com/problems/average-of-levels-in-binary-tree/) + +### Problem Description + +Given a binary tree, compute the average value of nodes at each level. + +### Input and Output Example + +Input is a binary tree, and the output is a one-dimensional array representing the average value of nodes at each level. + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: [3, 14.5, 11] +``` + +### Solution Explanation + +Using Breadth-First Search, we can conveniently calculate the average value for each level. + + + + +```cpp +vector averageOfLevels(TreeNode* root) { + vector level_avg; + if (root == nullptr) { + return level_avg; + } + queue q; + q.push(root); + int count = q.size(); + while (count > 0) { + double level_sum = 0; + for (int i = 0; i < count; ++i) { + TreeNode* node = q.front(); + q.pop(); + level_sum += node->val; + if (node->left != nullptr) { + q.push(node->left); + } + if (node->right != nullptr) { + q.push(node->right); + } + } + level_avg.push_back(level_sum / count); + count = q.size(); + } + return level_avg; +} +``` + + + + +```py +def averageOfLevels(root: Optional[TreeNode]) -> List[float]: + level_avg = [] + if root is None: + return level_avg + q = collections.deque() + q.append(root) + count = len(q) + while count > 0: + level_sum = 0 + for _ in range(count): + node = q.popleft() + level_sum += node.val + if node.left is not None: + q.append(node.left) + if node.right is not None: + q.append(node.right) + level_avg.append(level_sum / count) + count = len(q) + return level_avg +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx new file mode 100644 index 00000000..3ac5f766 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx @@ -0,0 +1,255 @@ +--- +sidebar_position: 71 +--- + +# 13.4 Preorder, Inorder, and Postorder Traversals + +Preorder traversal, inorder traversal, and postorder traversal are three ways to traverse a binary tree using Depth-First Search (DFS). They differ only in the order of node visits, while the rest remains the same. Consider the following binary tree: + +``` + 1 + / \ + 2 3 + / \ \ +4 5 6 +``` + +In **preorder traversal**, the parent node is visited first, followed by the left node and then the right node. The traversal order is [1 2 4 5 3 6]. + + + + +```cpp +void preorder(TreeNode* root) { + visit(root); + preorder(root->left); + preorder(root->right); +} +``` + + + + +```py +def preorder(root: TreeNode): + visit(root) + preorder(root.left) + preorder(root.right) +``` + + + + + +In **inorder traversal**, the left node is visited first, followed by the parent node and then the right node. The traversal order is [4 2 5 1 3 6]. + + + + +```cpp +void inorder(TreeNode* root) { + inorder(root->left); + visit(root); + inorder(root->right); +} +``` + + + + +```py +def inorder(root: TreeNode): + inorder(root.left) + visit(root) + inorder(root.right) +``` + + + + + +In **postorder traversal**, the left node is visited first, followed by the right node and then the parent node. The traversal order is [4 5 2 6 3 1]. + + + + +```cpp +void postorder(TreeNode* root) { + postorder(root->left); + postorder(root->right); + visit(root); +} +``` + + + + +```py +def postorder(root: TreeNode): + postorder(root.left) + postorder(root.right) + visit(root) +``` + + + + + +## [105. Construct Binary Tree from Preorder and Inorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) + +### Problem Description + +Given the preorder and inorder traversal results of a binary tree, reconstruct the tree. It is guaranteed that there are no duplicate values in the tree nodes. + +### Input and Output Example + +Input consists of two 1D arrays representing the preorder and inorder traversal results of the tree. Output is the reconstructed binary tree. + +``` +Input: preorder = [4,9,20,15,7], inorder = [9,4,15,20,7] +Output: + 4 + / \ + 9 20 + / \ + 15 7 +``` + +### Solution Explanation + +Using the provided example, the first node in the preorder traversal is `4`, indicating that `4` is the root node. In the inorder traversal, locating `4` provides the following insights: + +- The left subarray in the inorder traversal corresponds to the left subtree. It contains `1` node (`9`), which maps to the next `1` element in the preorder traversal after `4`. +- The right subarray in the inorder traversal corresponds to the right subtree. It contains `3` nodes (`15`, `20`, `7`), which map to the last `3` elements in the preorder traversal. + +With this information, the left and right subtrees can be recursively reconstructed. To simplify locating values, a hash map can be used to preprocess the inorder traversal results. + + + + +```cpp +// Auxiliary function +TreeNode* reconstruct(unordered_map& io_map, vector& po, int l, + int r, int mid_po) { + if (l > r) { + return nullptr; + } + int mid_val = po[mid_po]; + int mid_io = io_map[mid_val]; + int left_len = mid_io - l + 1; + TreeNode* node = new TreeNode(mid_val); + node->left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1); + node->right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len); + return node; +} +// Main function +TreeNode* buildTree(vector& preorder, vector& inorder) { + unordered_map io_map; + for (int i = 0; i < inorder.size(); ++i) { + io_map[inorder[i]] = i; + } + return reconstruct(io_map, preorder, 0, preorder.size() - 1, 0); +} +``` + + + + +```py +# Auxiliary function +def reconstruct( + io_map: Dict[int, int], po: List[int], l: int, r: int, mid_po: int +) -> Optional[TreeNode]: + if l > r: + return None + mid_val = po[mid_po] + mid_io = io_map[mid_val] + left_len = mid_io - l + 1 + node = TreeNode(mid_val) + node.left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1) + node.right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len) + return node + +# Main function +def buildTree(preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + io_map = {val: i for i, val in enumerate(inorder)} + return reconstruct(io_map, preorder, 0, len(preorder) - 1, 0) + +``` + + + + + +## [144. Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) + +### Problem Description + +Implement a binary tree preorder traversal without using recursion. + +### Input and Output Example + +Input is a binary tree, and the output is an array representing the preorder traversal of the binary tree. + +``` +Input: + 1 + \ + 2 + / + 3 +Output: [1,2,3] +``` + +### Solution Explanation + +Since recursion inherently uses a stack, we can simulate the preorder traversal using an explicit stack. Note the order of stack operations. + + + + +```cpp +vector preorderTraversal(TreeNode* root) { + vector po; + if (root == nullptr) { + return po; + } + stack s; + s.push(root); + while (!s.empty()) { + TreeNode* node = s.top(); + s.pop(); + po.push_back(node->val); + if (node->right) { + s.push(node->right); // Push the right child first, then the left child, to ensure the left subtree is traversed first. + } + if (node->left) { + s.push(node->left); + } + } + return po; +} +``` + + + + +```py +def preorderTraversal(root: Optional[TreeNode]) -> List[int]: + po = [] + if root is None: + return po + s = [root] + while len(s) > 0: + node = s.pop() + po.append(node.val) + if node.right is not None: + s.append(node.right) # Push the right child first, then the left child, to ensure the left subtree is traversed first. + if node.left is not None: + s.append(node.left) + return po +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx new file mode 100644 index 00000000..b34b772d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx @@ -0,0 +1,188 @@ +--- +sidebar_position: 72 +--- + +# 13.5 Binary Search Tree + +A `Binary Search Tree` (BST) is a special type of binary tree: for every parent node, all nodes in its left subtree have values less than or equal to the parent's value, and all nodes in its right subtree have values greater than or equal to the parent's value. Therefore, for a BST, we can determine whether a value exists in $O(\log n)$ time: starting from the root, move to the left if the current node's value is greater than the target value, or move to the right if it's smaller. Additionally, since a BST is ordered, an in-order traversal of the tree results in a sorted array. + +For example, the tree below is a BST, and its in-order traversal yields [1, 2, 3, 4, 5, 6]. + +``` + 4 + / \ + 2 5 + / \ \ +1 3 6 +``` + +## [99. Recover Binary Search Tree](https://leetcode.com/problems/recover-binary-search-tree/) + +### Problem Description + +Given a binary search tree, where two nodes have been swapped by mistake, restore the tree to its correct structure. + +### Input and Output Example + +The input is a binary search tree where two nodes have been swapped, and the output is the corrected tree. + +``` +Input: + 3 + / \ +1 4 + / + 2 +Output: + 2 + / \ +1 4 + / + 3 +``` + +In this example, 2 and 3 were swapped by mistake. + +### Solution Explanation + +We can perform an in-order traversal of the BST and use a `prev` pointer to keep track of the previous node during traversal. If the current node's value is less than the `prev` node's value, it indicates an order mismatch that needs correction. + +- If there's only one mismatch in the entire traversal, it means the two swapped nodes are adjacent. +- If there are two mismatches, the two non-adjacent nodes are swapped and need correction. + + + + +```cpp +// Auxiliary function +void inorder(TreeNode* root, TreeNode*& mistake1, TreeNode*& mistake2, + TreeNode*& prev) { + if (root == nullptr) { + return; + } + inorder(root->left, mistake1, mistake2, prev); + if (prev != nullptr && root->val < prev->val) { + if (mistake1 == nullptr) { + mistake1 = prev; + } + mistake2 = root; + } + prev = root; + inorder(root->right, mistake1, mistake2, prev); +} +// Main function +void recoverTree(TreeNode* root) { + TreeNode *mistake1 = nullptr, *mistake2 = nullptr, *prev = nullptr; + inorder(root, mistake1, mistake2, prev); + if (mistake1 != nullptr && mistake2 != nullptr) { + swap(mistake1->val, mistake2->val); + } +} +``` + + + + +```py +# Auxiliary function +# In Python, it is not straightforward to pass pointers directly in auxiliary functions. Therefore, we use a list of length 1 to simulate passing by reference. +def inorder( + root: Optional[TreeNode], + mistake1=List[Optional[TreeNode]], + mistake2=List[Optional[TreeNode]], + prev=List[Optional[TreeNode]], +): + if root is None: + return + inorder(root.left, mistake1, mistake2, prev) + if prev[0] is not None and root.val < prev[0].val: + if mistake1[0] is None: + mistake1[0] = prev[0] + mistake2[0] = root + prev[0] = root + inorder(root.right, mistake1, mistake2, prev) + +# Main function +def recoverTree(root: Optional[TreeNode]) -> None: + mistake1, mistake2, prev = [None], [None], [None] + inorder(root, mistake1, mistake2, prev) + if mistake1[0] is not None and mistake2[0] is not None: + mistake1[0].val, mistake2[0].val = mistake2[0].val, mistake1[0].val +``` + + + + + +## [669. Trim a Binary Search Tree](https://leetcode.com/problems/trim-a-binary-search-tree/) + +### Problem Description + +Given a binary search tree and two integers L and R, where L < R, trim the tree so that all nodes in the tree have values within the range [L, R]. + +### Input and Output Example + +Input is a binary search tree and two integers L and R. Output is the trimmed binary search tree. + +``` +Input: L = 1, R = 3, tree = + 3 + / \ + 0 4 + \ + 2 + / + 1 +Output: + 3 + / + 2 + / +1 +``` + +### Solution Explanation + +By leveraging the properties of a binary search tree, we can efficiently solve this problem using recursion. + + + + +```cpp +TreeNode* trimBST(TreeNode* root, int low, int high) { + if (root == nullptr) { + return root; + } + if (root->val > high) { + return trimBST(root->left, low, high); + } + if (root->val < low) { + return trimBST(root->right, low, high); + } + root->left = trimBST(root->left, low, high); + root->right = trimBST(root->right, low, high); + return root; +} +``` + + + + +```py +def trimBST( + root: Optional[TreeNode], low: int, high: int +) -> Optional[TreeNode]: + if root is None: + return None + if root.val > high: + return trimBST(root.left, low, high) + if root.val < low: + return trimBST(root.right, low, high) + root.left = trimBST(root.left, low, high) + root.right = trimBST(root.right, low, high) + return root +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx new file mode 100644 index 00000000..8b68bfdb --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx @@ -0,0 +1,137 @@ +--- +sidebar_position: 73 +--- + +# 13.6 Trie + +A Trie is a tree-like data structure used to determine whether a string exists or whether it has a specific prefix. + +
+ + ![](13.1.png) + +
Fig. 13.1: Trie storing words A, to, tea, ted, ten, i, in, and inn, along with their frequencies
+
+ +Why use a Trie for such problems? Suppose we have a dictionary storing nearly 10,000 words. Even with a hash table, searching for a word can be computationally expensive, and supporting prefix-based searches becomes difficult. However, since the length of an English word, `n`, is usually less than 10, using a Trie allows searches to be completed in $O(n)$—approximately $O(1)$ time—with minimal additional overhead. + +## [208. Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) + +### Problem Description + +Create a Trie that supports fast insertion of words, word lookup, and prefix lookup. + +### Input and Output Example + +Below is an example of how to use the data structure. + +``` +Trie trie = new Trie(); +trie.insert("apple"); +trie.search("apple"); // true +trie.search("app"); // false +trie.startsWith("app"); // true +trie.insert("app"); +trie.search("app"); // true +``` + +### Solution Explanation + +Here is the typical implementation of a Trie. + + + + +```cpp +struct TrieNode { + bool word_ends; + vector children; + TrieNode() : word_ends(false), children(26, nullptr) {} +}; + +class Trie { + public: + Trie() : root_(new TrieNode()) {} + + void insert(string word) { + TrieNode* node = root_; + for (char c : word) { + int pos = c - ’a’; + if (node->children[pos] == nullptr) { + node->children[pos] = new TrieNode(); + } + node = node->children[pos]; + } + node->word_ends = true; + } + + bool search(string word) { + TrieNode* node = root_; + for (char c : word) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr && node->word_ends; + } + + bool startsWith(string prefix) { + TrieNode* node = root_; + for (char c : prefix) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr; + } + + private: + TrieNode* root_; +}; +``` + + + + +```py +class TrieNode: + def __init__(self): + self.word_ends = False + self.children = [None] * 26 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word: str) -> None: + node = self.root + for c in word: + pos = ord(c) - ord("a") + if node.children[pos] is None: + node.children[pos] = TrieNode() + node = node.children[pos] + node.word_ends = True + + def search(self, word: str) -> bool: + node = self.root + for c in word: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None and node.word_ends + + def startsWith(self, prefix: str) -> bool: + node = self.root + for c in prefix: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md new file mode 100644 index 00000000..b4123e0a --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 74 +--- + +# 13.7 Exercises + +## Basic Difficulty + +### [226. Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) + +With a clever use of recursion, you can complete this task in just five lines. + +--- + +### [617. Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees/) + +Similarly, recursion can easily handle this task. + +--- + +### [572. Subtree of Another Tree](https://leetcode.com/problems/subtree-of-another-tree/) + +This is the sister problem of Symmetric Tree, and the implementation is very similar. + +--- + +### [404. Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) + +How can you determine if a node is a left leaf? One feasible approach is to pass an additional parameter to the helper function indicating whether the current node is a left child of its parent. + +--- + +### [513. Find Bottom Left Tree Value](https://leetcode.com/problems/find-bottom-left-tree-value/) + +What condition must the bottom-left node satisfy? How can we locate it based on this condition? + +--- + +### [538. Convert BST to Greater Tree](https://leetcode.com/problems/convert-bst-to-greater-tree/) + +Try to solve this problem using a specific traversal method, visiting each node exactly once. + +--- + +### [235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) + +Using the unique properties of a BST, this problem can be solved quite easily. + +--- + +### [530. Minimum Absolute Difference in BST](https://leetcode.com/problems/minimum-absolute-difference-in-bst/) + +Remember the traversal method we discussed for BSTs? + +--- + +## Advanced Difficulty + +### [1530. Number of Good Leaf Nodes Pairs](https://leetcode.com/problems/number-of-good-leaf-nodes-pairs/) + +A variation of problem 543. Pay attention in the helper function: the global variable should be updated based on the number of valid pairs of distances between left and right subtrees, while the return value is the height of all valid leaf nodes (+1) from both subtrees. + +--- + +### [889. Construct Binary Tree from Preorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) + +Given any two traversal results, we can reconstruct the tree structure. + +--- + +### [106. Construct Binary Tree from Inorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) + +Given any two traversal results, we can reconstruct the tree structure. + +--- + +### [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) + +Since preorder, inorder, and postorder traversals are implemented using recursion, and recursion inherently uses a stack, we can always use a stack to implement them. + +--- + +### [145. Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) + +Since preorder, inorder, and postorder traversals are implemented using recursion, and recursion inherently uses a stack, we can always use a stack to implement them. + +--- + +### [236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) + +Now it’s not a BST but a general binary tree. What should we do? + +--- + +### [109. Convert Sorted List to Binary Search Tree](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) + +Convert a sorted linked list into a BST. To ensure the BST remains balanced, we need to find the middle point of the list. + +--- + +### [897. Increasing Order Search Tree](https://leetcode.com/problems/increasing-order-search-tree/) + +Flatten a BST into a linked list. Be cautious about the order of pointer manipulations to avoid creating loops. + +--- + +### [653. Two Sum IV - Input is a BST](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/) + +Ah, this problem might trick you. + +--- + +### [450. Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/) + +When you locate the node to delete, consider different cases: whether the node is a leaf, has only one child, or has two children. It’s recommended to reclaim memory at the same time. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13.1.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13.1.png new file mode 100644 index 00000000..06c168c6 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/13.1.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/_category_.json new file mode 100644 index 00000000..a3026f20 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/13-trees/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "13. The Three Musketeers of Pointers: Trees", + "position": 13, + "link": { + "type": "generated-index", + "description": "Chapter 13: The Three Musketeers of Pointers: Trees" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx new file mode 100644 index 00000000..ac08203f --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx @@ -0,0 +1,16 @@ +--- +sidebar_position: 75 +--- + +# 14.1 Data Structure Introduction + +As the third member of the pointer triumvirate, graphs are an advanced version of trees. A `graph` can be classified as directed or undirected, cyclic or acyclic, and connected or disconnected. A tree is essentially a connected, undirected, acyclic graph. Another common type of graph is the `Directed Acyclic Graph (DAG)`. + +
+ + ![](14.1.png) + +
Figure 14.1: Example of a Directed Acyclic Graph
+
+ +There are two common ways to represent a graph. Suppose there are `n` nodes and `m` edges in the graph. The first method is the `adjacency matrix`: we can create an `n × n` matrix `G`, where `G[i][j] = 1` if node `i` is connected to node `j`, and `0` otherwise. For an undirected graph, the matrix is symmetric, i.e., `G[i][j] = G[j][i]`. The second method is the `adjacency list`: we can create an array of size `n`, where each index `i` stores an array or linked list representing the nodes connected to node `i`. The adjacency matrix requires more memory but allows for faster edge lookup, whereas the adjacency list is more space-efficient but does not support quick edge existence checks. Additionally, we can use an `m × 2` matrix to store all the edges directly. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx new file mode 100644 index 00000000..12fa3fb6 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx @@ -0,0 +1,90 @@ +--- +sidebar_position: 76 +--- + +# 14.2 Bipartite Graph + +The `bipartite graph` algorithm, also known as the `coloring method`, uses a breadth-first search (BFS). A graph is bipartite if its nodes can be colored using two colors such that no two adjacent nodes have the same color. + +## [785. Is Graph Bipartite?](https://leetcode.com/problems/is-graph-bipartite/) + +### Problem Description + +Given a graph, determine if it is bipartite. + +### Input and Output Example + +The input is a graph represented as an adjacency list (e.g., position `0` in the adjacency list is `[1,3]`, indicating node `0` is connected to nodes `1` and `3`). The output is a boolean value indicating whether the graph is bipartite. + +``` +Input: [[1,3], [0,2], [1,3], [0,2]] +0----1 +| | +| | +3----2 +Output: true +``` + +In this example, we can partition the nodes into two groups: `{0,2}` and `{1,3}`. + +### Solution Explanation + +Using a queue and breadth-first search (BFS), we can color unvisited nodes and check whether adjacent nodes share the same color. In the code, `0` represents unvisited nodes, and `1` and `2` represent the two different colors. + + + + +```cpp +bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n, 0); + queue q; + for (int i = 0; i < n; ++i) { + if (color[i] == 0) { + q.push(i); + color[i] = 1; + } + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int j : graph[node]) { + if (color[j] == 0) { + q.push(j); + color[j] = color[node] == 2 ? 1 : 2; + } else if (color[j] == color[node]) { + return false; + } + } + } + } + return true; +} +``` + + + + +```py +def isBipartite(graph: List[List[int]]) -> bool: + n = len(graph) + color = [0] * n + q = collections.deque() + + for i in range(n): + if color[i] == 0: + q.append(i) + color[i] = 1 + while len(q) > 0: + node = q.popleft() + for j in graph[node]: + if color[j] == 0: + q.append(j) + color[j] = 1 if color[node] == 2 else 2 + elif color[j] == color[node]: + return False + return True +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx new file mode 100644 index 00000000..1fa8fa8e --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 77 +--- + +# 14.3 Topological Sort + +`Topological Sort` is a common algorithm used to order nodes in a directed acyclic graph (DAG). Given $N$ nodes in a DAG, the goal is to arrange them in a linear sequence such that if node $i$ points to node $j$, then $i$ appears before $j$ in the sequence. The result of a topological sort is not unique as long as the above condition is satisfied. + +## [210. Course Schedule II](https://leetcode.com/problems/course-schedule-ii/) + +### Problem Description + +Given $N$ courses and their prerequisites, determine an order in which all the courses can be completed. + +### Input and Output Example + +The input consists of a positive integer representing the number of courses and a 2D array representing directed edges (e.g., `[1,0]` indicates course 1 must be taken after course 0). The output is a 1D array representing a topological order. + +``` +Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] +Output: [0,1,2,3] +``` + +In this example, another valid order could be `[0,2,1,3]`. + +### Solution Explanation + +e can first build an adjacency matrix to represent the graph, facilitating direct lookups. Note that we reverse all edges, so if course $i$ points to course $j$, it means course $i$ must be completed before course $j$. This aligns with our intuitive understanding of prerequisites. + +Topological sorting can be viewed as a special case of breadth-first search (BFS): + +1. Traverse all nodes and enqueue nodes with an in-degree of $0$ (i.e., nodes without prerequisites). +2. While processing the queue: + - Add the current node to the sorted order. + - Decrease the in-degree of all nodes it points to by $1$. + - If a node’s in-degree becomes $0$, enqueue it. +3. When the queue is empty, the nodes are either fully sorted, or a cycle exists in the graph, preventing all courses from being completed. + + + + +```cpp +vector findOrder(int numCourses, vector>& prerequisites) { + vector> graph(numCourses, vector()); + vector indegree(numCourses, 0), schedule; + for (const auto& pr : prerequisites) { + graph[pr[1]].push_back(pr[0]); + ++indegree[pr[0]]; + } + queue q; + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] == 0) { + q.push(i); + } + } + while (!q.empty()) { + int u = q.front(); + q.pop(); + schedule.push_back(u); + for (int v : graph[u]) { + --indegree[v]; + if (indegree[v] == 0) { + q.push(v); + } + } + } + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] != 0) { + return vector(); + } + } + return schedule; +} +``` + + + + +```py +def findOrder(numCourses: int, prerequisites: List[List[int]]) -> List[int]: + graph = [[] for _ in range(numCourses)] + indegree = [0] * numCourses + schedule = [] + + for pr_from, pr_to in prerequisites: + graph[pr_to].append(pr_from) + indegree[pr_from] += 1 + + q = collections.deque([i for i, deg in enumerate(indegree) if deg == 0]) + + while len(q) > 0: + u = q.popleft() + schedule.append(u) + for v in graph[u]: + indegree[v] -= 1 + if indegree[v] == 0: + q.append(v) + + return schedule if all(deg == 0 for deg in indegree) else [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md new file mode 100644 index 00000000..1c0d256d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md @@ -0,0 +1,27 @@ +--- +sidebar_position: 78 +--- + +# 14.4 Exercises + +## Basic Difficulty + +--- + +### [1059. All Paths from Source Lead to Destination](https://leetcode.com/problems/all-paths-from-source-lead-to-destination/) + +虽然使用深度优先搜索可以解决大部分的图遍历问题,但是注意判断是否陷入了环路。 + +--- + +## Advanced Difficulty + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +笔者其实已经把这道题的题解写好了,才发现这道题是需要解锁才可以看的题目。为了避免版权纠纷,故将其移至练习题内。本题考察最小生成树(minimum spanning tree, MST)的求法,通常可以用两种方式求得:Prim’s Algorithm,利用优先队列选择最小的消耗;以及 Kruskal’s Algorithm,排序后使用并查集。 + +--- + +### [882. Reachable Nodes In Subdivided Graph](https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/) + +这道题笔者考虑了很久,最终决定把它放在练习题而非详细讲解。本题是经典的节点最短距离问题,常用的算法有 Bellman-Ford 单源最短路算法,以及 Dijkstra 无负边单源最短路算法。虽然经典,但是 LeetCode 很少有相关的题型,因此这里仅供读者自行深入学习。 \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14.1.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14.1.png new file mode 100644 index 00000000..46ebed1b Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/14.1.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/_category_.json new file mode 100644 index 00000000..0d316bd1 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/14-graphs/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "14. The Three Musketeers of Pointers: Graphs", + "position": 14, + "link": { + "type": "generated-index", + "description": "Chapter 14: The Three Musketeers of Pointers: Graphs" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md new file mode 100644 index 00000000..1237fceb --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 75 +--- + +# 15.1 Introduction + +So far, we have explored a wide range of data structures, including the "pointer trio" (linked list, tree, and graph) and C++'s built-in STL library. For certain problems, it is necessary not only to utilize multiple data structures but also to nest and integrate them, enabling more complex and efficient operations. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx new file mode 100644 index 00000000..5e786f67 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx @@ -0,0 +1,140 @@ +--- +sidebar_position: 76 +--- + +# 15.2 Union-Find + +`Union-Find` (disjoint set) is a data structure used for dynamic connectivity problems. It efficiently connects two points and determines whether two points are connected. Given `n` nodes, we initialize the parent of each node to itself. To connect nodes `i` and `j`, we attach the smaller rank's parent to the larger rank's parent (union by rank). To check if two nodes are connected, we find their ancestors and determine if they are the same, applying path compression to speed up subsequent queries. + +
+ + ![](15.1.png) + +
Figure 15.1: Union-Find Example. `union` merges two sets by rank, and `find` retrieves a node's ancestor while compressing paths.
+
+ +## [684. Redundant Connection](https://leetcode.com/problems/redundant-connection/) + +### Problem Description + +In an undirected graph, find an edge that, when removed, leaves the graph as a tree (i.e., acyclic and connected). If there are multiple solutions, return the edge appearing last in the input. + +### Input and Output Example + +The input is a 2D array representing all edges (pairs of nodes), and the output is a 1D array representing the edge to remove. + +``` +Input: [[1,2], [1,3], [2,3]] + 1 + / \ +2 - 3 +Output: [2,3] +``` + +### Solution Explanation + +Since we need to determine whether two nodes are repeatedly connected, we can solve this problem using the Union-Find data structure. The detailed implementation is as follows: + + + + +```cpp +class Solution { + public: + vector findRedundantConnection(vector>& edges) { + n_ = edges.size(); + id_ = vector(n_); + depth_ = vector(n_, 1); + for (int i = 0; i < n_; ++i) { + id_[i] = i; + } + for (auto& edge : edges) { + int i = edge[0], j = edge[1]; + if (linked(i - 1, j - 1)) { + return vector{i, j}; + } + connect(i - 1, j - 1); + } + return vector(); + } + + private: + int find(int i) { + // Path Compression + while (i != id_[i]) { + id_[i] = id_[id_[i]]; + i = id_[i]; + } + return i; + } + + void connect(int i, int j) { + i = find(i), j = find(j); + if (i == j) { + return; + } + // Union by Rank + if (depth_[i] <= depth_[j]) { + id_[i] = j; + depth_[j] = max(depth_[j], depth_[i] + 1); + } else { + id_[j] = i; + depth_[i] = max(depth_[i], depth_[j] + 1); + } + } + + bool linked(int i, int j) { return find(i) == find(j); } + + int n_; + vector id_; + vector depth_; +}; +``` + + + + +```py +class Solution: + def __init__(self): + self.n = 0 + self.id = None + self.depth = None + + def find(self, i: int) -> int: + # Path Compression + while i != self.id[i]: + self.id[i] = self.id[self.id[i]] + i = self.id[i] + return i + + def connect(self, i: int, j: int): + i = self.find(i) + j = self.find(j) + if i == j: + return + # Union by Rank + if self.depth[i] <= self.depth[j]: + self.id[i] = j + self.depth[j] = max(self.depth[j], self.depth[i] + 1) + else: + self.id[j] = i + self.depth[i] = max(self.depth[i], self.depth[j] + 1) + + def linked(self, i: int, j: int) -> bool: + return self.find(i) == self.find(j) + + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + self.n = len(edges) + self.id = list(range(self.n)) + self.depth = [1] * self.n + for i, j in edges: + if self.linked(i - 1, j - 1): + return [i, j] + self.connect(i - 1, j - 1) + return [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx new file mode 100644 index 00000000..e4642b88 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx @@ -0,0 +1,257 @@ +--- +sidebar_position: 77 +--- + +# 15.3 Composite Data Structures + +This type of problem often uses a hash table or ordered map for auxiliary record-keeping to speed up lookups; paired with arrays or linked lists for continuous data storage to expedite sequential selection or value deletion. + +## [146. LRU Cache](https://leetcode.com/problems/lru-cache/) + +### Problem Description + +Design a fixed-size Least Recently Used Cache (LRU). When inserting data into a non-full cache or updating/retrieving existing data in the cache, mark the data as recently used. When the cache is full, evict the least recently used data, insert the new data, and mark it as recently used. + +### Input and Output Example + +Here is an example of calling this data structure. Given a cache with size `n`, store data using the least recently used strategy. + +``` +LRUCache cache = new LRUCache( 2 /* capacity */ ); +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // Output value 1 +cache.put(3, 3); // Evict key 2 +cache.get(2); // Output value -1 (not found) +cache.put(4, 4); // Evict key 1 +cache.get(1); // Output value -1 (not found) +cache.get(3); // Output value 3 +cache.get(4); // Output value 4 +``` + +### Solution Explanation + +We use a linked list to store the keys and values, with the order of the linked list representing the least-to-most recently used sequence. The most recently used data resides at the head of the list. Additionally, a hash table is used for lookups, where the key corresponds to the data key and the value points to the corresponding pointer/iterator in the linked list. On every cache hit (successful lookup), the corresponding node is moved to the head of the linked list. + + + + +```cpp +class LRUCache { + public: + LRUCache(int capacity) : n_(capacity) {} + + int get(int key) { + auto it = key_to_cache_it_.find(key); + if (it == key_to_cache_it_.end()) { + return -1; + } + cache_.splice(cache_.begin(), cache_, it->second); + return it->second->second; + } + + void put(int key, int value) { + auto it = key_to_cache_it_.find(key); + if (it != key_to_cache_it_.end()) { + it->second->second = value; + return cache_.splice(cache_.begin(), cache_, it->second); + } + cache_.insert(cache_.begin(), make_pair(key, value)); + key_to_cache_it_[key] = cache_.begin(); + if (cache_.size() > n_) { + key_to_cache_it_.erase(cache_.back().first); + cache_.pop_back(); + } + } + + private: + list> cache_; + unordered_map>::iterator> key_to_cache_it_; + int n_; +}; +``` + + + + +```py +class Node: + def __init__(self, key=-1, val=-1): + self.key = key + self.val = val + self.prev = None + self.next = None + +class LinkedList: + def __init__(self): + self.dummy_start = Node() + self.dummy_end = Node() + self.dummy_start.next = self.dummy_end + self.dummy_end.prev = self.dummy_start + + def appendleft(self, node) -> Node: + left, right = self.dummy_start, self.dummy_start.next + node.next = right + right.prev = node + left.next = node + node.prev = left + return node + + def remove(self, node) -> Node: + left, right = node.prev, node.next + left.next = right + right.prev = left + return node + + def move_to_start(self, node): + return self.appendleft(self.remove(node)) + + def pop(self): + return self.remove(self.dummy_end.prev) + + def peek(self): + return self.dummy_end.prev.val + +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.key_to_node = dict() + self.cache_nodes = LinkedList() + + def get(self, key: int) -> int: + if key not in self.key_to_node: + return -1 + node = self.key_to_node[key] + self.cache_nodes.move_to_start(node) + return node.val + + def put(self, key: int, value: int) -> None: + if key in self.key_to_node: + node = self.cache_nodes.remove(self.key_to_node[key]) + node.val = value + else: + node = Node(key, value) + self.key_to_node[key] = node + self.cache_nodes.appendleft(node) + if len(self.key_to_node) > self.n: + self.key_to_node.pop(self.cache_nodes.pop().key) +``` + + + + + +In Python, we can directly use the `OrderedDict` function to implement LRU, which significantly simplifies the problem. However, the author encourages readers to carefully study the explanation above to understand the core principles behind LRU implementation. + + +```py +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.cache = {} + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + self.cache[key] = self.cache.pop(key) + return self.cache[key] + + def put(self, key: int, value: int) -> None: + if key in self.cache: + self.cache.pop(key) + self.cache[key] = value + if len(self.cache) > self.n: + self.cache.pop(next(iter(self.cache))) +``` + +## [380. Insert Delete GetRandom O(1)](https://leetcode.com/problems/insert-delete-getrandom-o1/) + +### Problem Description + +Design a data structure that supports insertion, deletion, and random access, all in $O(1)$ time complexity. + +### Input and Output Example + +Here is an example of how the data structure is used: + +``` +RandomizedSet randomizedSet = new RandomizedSet(); +randomizedSet.insert(1); +randomizedSet.remove(2); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 50% 1, 50% 2 +randomizedSet.remove(1); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 100% 2 +``` + +### Solution Explanation + +We use an array to store the inserted numbers and a hash table to track their positions. When inserting a number, we add it directly to the array and record its position in the hash table. When deleting a number, we swap the current last element of the array with the element to be removed and update the hash table. For random access, we can simply select any position in the array. + + + + +```cpp +class RandomizedSet { + public: + bool insert(int val) { + if (v_to_k_.contains(val)) { + return false; + } + v_to_k_[val] = nums_.size(); + nums_.push_back(val); + return true; + } + + bool remove(int val) { + if (!v_to_k_.contains(val)) { + return false; + } + v_to_k_[nums_.back()] = v_to_k_[val]; + nums_[v_to_k_[val]] = nums_.back(); + v_to_k_.erase(val); + nums_.pop_back(); + return true; + } + + int getRandom() { return nums_[rand() % nums_.size()]; } + + private: + unordered_map v_to_k_; + vector nums_; +}; +``` + + + + +```py +class RandomizedSet: + def __init__(self): + self.nums = [] + self.v_to_k = {} + + def insert(self, val: int) -> bool: + if val in self.v_to_k: + return False + self.v_to_k[val] = len(self.nums) + self.nums.append(val) + return True + + def remove(self, val: int) -> bool: + if val not in self.v_to_k: + return False + self.v_to_k[self.nums[-1]] = self.v_to_k[val] + self.nums[self.v_to_k[val]] = self.nums[-1] + del self.v_to_k[val] + self.nums.pop() + return True + + def getRandom(self) -> int: + return self.nums[random.randint(0, len(self.nums) - 1)] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md new file mode 100644 index 00000000..74a99c00 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 78 +--- + +# 15.4 Exercises + +## Basic Difficulty + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +Solve this problem again using union-find and Kruskal’s Algorithm. + +--- + +## Advanced Difficulty + +### [432. All O`one Data Structure](https://leetcode.com/problems/all-oone-data-structure/) + +Design a data structure that supports increaseKey, decreaseKey, getMaxKey, and getMinKey, all in $O(1)$ time complexity. + +--- + +### [716. Max Stack](https://leetcode.com/problems/max-stack/) + +Design a stack that supports push, pop, top, getMax, and popMax. You can use a method similar to LRU to reduce time complexity, but since we need to get the maximum value, which data structure should replace the unordered_map? diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png new file mode 100644 index 00000000..6a2df359 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json new file mode 100644 index 00000000..b4f85a5a --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "15. More Complex Data Structures", + "position": 15, + "link": { + "type": "generated-index", + "description": "Chapter 15: More Complex Data Structures" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md new file mode 100644 index 00000000..49f37f03 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md @@ -0,0 +1,21 @@ +--- +sidebar_position: 5 +--- + +# 2.1 Algorithm Explanation + +The two-pointer technique is primarily used for traversing arrays, where two pointers point to different elements to collaborate on a task. It can also be extended to multiple pointers across multiple arrays. + +If two pointers point to the same array and move in the same direction without intersecting, this is also known as a sliding window (the area between the two pointers represents the current window), often used for interval searching. + +If two pointers point to the same array but move in opposite directions, they can be used for searching, especially when the array is sorted. + +In C++, pay attention to the position of `const` as it affects the pointer’s behavior: + +```cpp +int x; +int * p1 = &x; // The pointer and the value can both be modified +const int * p2 = &x; // The pointer can be modified, but the value cannot (const int) +int * const p3 = &x; // The pointer cannot be modified (* const), but the value can +const int * const p4 = &x; // Neither the pointer nor the value can be modified +``` diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx new file mode 100644 index 00000000..b13d8cd6 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx @@ -0,0 +1,73 @@ +--- +sidebar_position: 6 +--- + +# 2.2 Two Sum + +## [167. Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) + +### Problem Description + +Find two numbers in an ascending integer array such that their sum equals a given value. There is exactly one solution. + + +### Input and Output Example + +The input is an array (`numbers`) and a target value (`target`). The output is the positions of the two numbers, starting from 1. + +``` +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +``` + +In this example, the sum of the first number (2) and the second number (7) equals the target value (9). + +### Solution Explanation + +Since the array is sorted, we can use a two-pointer approach with pointers moving in opposite directions to find these two numbers. One pointer starts at the smallest element, on the far left of the array, moving right; the other starts at the largest element, on the far right of the array, moving left. + +If the sum of the elements pointed to by the two pointers equals the target, then they are the solution. If the sum is less than the target, we move the left pointer one position to the right to increase the sum. If the sum is greater than the target, we move the right pointer one position to the left to decrease the sum. + +It can be proven that for a sorted array with a solution, the two-pointer approach will always reach the optimal solution. Here’s the proof: Assume the positions of the solution are `l` and `r`. If the left pointer is to the left of `l` and the right pointer has already moved to `r`, the sum of the two values will be less than the target, so the left pointer will continue moving right until it reaches `l`. Similarly, if the right pointer is to the right of `r` and the left pointer has already moved to `l`, the sum will be greater than the target, so the right pointer will move left until it reaches `r`. Thus, the two pointers will converge at `l` and `r`, as no other scenario prevents this convergence. + + + + +```cpp +vector twoSum(vector& numbers, int target) { + int l = 0, r = numbers.size() - 1, two_sum; + while (l < r) { + two_sum = numbers[l] + numbers[r]; + if (two_sum == target) { + break; + } + if (two_sum < target) { + ++l; + } else { + --r; + } + } + return vector{l + 1, r + 1}; +} +``` + + + + +```py +def twoSum(numbers: List[int], target: int) -> List[int]: + l, r = 0, len(numbers) - 1 + while l < r: + two_sum = numbers[l] + numbers[r] + if two_sum == target: + break + if two_sum < target: + l += 1 + else: + r -= 1 + return [l + 1, r + 1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx new file mode 100644 index 00000000..0c2c3dbf --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx @@ -0,0 +1,68 @@ +--- +sidebar_position: 7 +--- + +# 2.3 Merging Two Sorted Arrays + +## [88. Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) + +### Problem Description + +Given two sorted arrays, merge them into one array. + +### Input and Output Example + +The input consists of two arrays and their respective lengths `m` and `n`. The length of the first array is extended to `m + n`, with the extra `n` positions filled with `0`s. The task is to merge the second array into the first array without allocating additional space. + + +``` +Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 +Output: nums1 = [1,2,2,3,5,6] +``` + + +### Solution Explanation + +Since both arrays are already sorted, we can place two pointers at the end of each array: at the `(m - 1)` position of `nums1` and the `(n - 1)` position of `nums2`. Each time, copy the larger number to the end of `nums1` and move the pointer one position to the left. + +To keep track of `nums1`'s end position, we also need a third pointer for copying. In the following code, we use `m` and `n` as pointers for the two arrays and create an additional pointer, `pos`, initially set to `m + n - 1`. Each time we move `m` or `n` to the left, we also move `pos` to the left. Note that if all numbers from `nums1` have been copied, don't forget to continue copying numbers from `nums2`; if all numbers from `nums2` have been copied, the remaining numbers in `nums1` do not need to change as they are already sorted. + +In the C++ solution, we use the `++` and `--` shorthand: both `a++` and `++a` increment `a` by 1, but `a++` returns the original value of `a`, while `++a` returns `a + 1`. If you only want to increase `a` without needing a return value, either syntax is fine (`++a` is slightly faster in unoptimized code). + + + + +```cpp +void merge(vector& nums1, int m, vector& nums2, int n) { + int pos = m-- + n-- - 1; + while (m >= 0 && n >= 0) { + nums1[pos--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; + } + while (n >= 0) { + nums1[pos--] = nums2[n--]; + } +} +``` + + + + +```py +def merge(nums1: List[int], m: int, nums2: List[int], n: int) -> None: + pos = m + n - 1 + m -= 1 + n -= 1 + while m >= 0 and n >= 0: + if nums1[m] > nums2[n]: + nums1[pos] = nums1[m] + m -= 1 + else: + nums1[pos] = nums2[n] + n -= 1 + pos -= 1 + nums1[: n + 1] = nums2[: n + 1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx new file mode 100644 index 00000000..9376d1de --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx @@ -0,0 +1,110 @@ +--- +sidebar_position: 8 +--- + +# 2.4 Sliding Window + +## [76. Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) + +### Problem Description + +Given two strings `s` and `t`, find the length of the shortest contiguous substring in `s` that contains all characters of `t`. The solution must have a time complexity of no more than $O(n)$. + + +### Input and Output Example + +The input consists of two strings `s` and `t`, and the output is a substring of `s`. If no solution exists, return an empty string. + + +``` +Input: s = "ADOBECODEBANC", t = "ABC" +Output: "BANC" +``` + +In this example, the shortest substring in `s` that contains one `A`, one `B`, and one `C` is "BANC". + + +### Solution Explanation + +This problem can be solved using the sliding window technique. Two pointers, `l` and `r`, both move from the leftmost to the rightmost position, with `l` always positioned at or before `r`. In the C++ solution, two arrays of length 128, `valid` and `freq`, are used to map characters (ASCII contains only 128 characters). The `valid` array indicates whether a character exists in `t`, and the `freq` array indicates the number of characters in `t` that are still missing in the sliding window of `s`: a positive value indicates missing characters, while a negative value indicates surplus characters. In the Python solution, the `Counter` data structure is used to simultaneously track characters in `t` and their missing quantities (a dictionary can also be used instead). + +Even though the solution contains a `while` loop nested inside a `for` loop, the `while` loop moves the `l` pointer from left to right only once, so the total time complexity remains $O(n)$. + + + + +```cpp +string minWindow(string s, string t) { + vector valid(128, false); + vector freq(128, 0); + // Count characters in t. + for (int i = 0; i < t.length(); ++i) { + valid[t[i]] = true; + ++freq[t[i]]; + } + // Move the sliding window and update statistics. + int count = 0; + int min_l = -1, min_length = -1; + for (int l = 0, r = 0; r < s.length(); ++r) { + if (!valid[s[r]]) { + continue; + } + // Add the character at position r to frequency stats and check if t's missing characters are filled. + if (--freq[s[r]] >= 0) { + ++count; + } + // If the sliding window contains all characters from t, try to move l to find the shortest substring. + while (count == t.length()) { + if (min_length == -1 || r - l + 1 < min_length) { + min_l = l; + min_length = r - l + 1; + } + // Remove the character at position l from stats and check if t's corresponding character is missing again. + if (valid[s[l]] && ++freq[s[l]] > 0) { + --count; + } + ++l; + } + } + return min_length == -1 ? "" : s.substr(min_l, min_length); +} +``` + + + + +```py +def minWindow(s: str, t: str) -> str: + # Count characters in t. Equivalent to: + # freq = dict() + # for c in t: + # freq[c] = freq.get(c, 0) + 1 + freq = Counter(t) + # Move the sliding window and update statistics. + count = 0 + min_l, min_length = None, None + l = 0 + for r in range(len(s)): + if s[r] not in freq: + continue + # Add the character at position r to frequency stats and check if t's missing characters are filled. + freq[s[r]] -= 1 + if freq[s[r]] >= 0: + count += 1 + # If the sliding window contains all characters from t, try to move l to find the shortest substring. + while count == len(t): + if min_length is None or r - l + 1 < min_length: + min_l = l + min_length = r - l + 1 + # Remove the character at position l from stats and check if t's corresponding character is missing again. + if s[l] in freq: + freq[s[l]] += 1 + if freq[s[l]] > 0: + count -= 1 + l += 1 + return "" if min_length is None else s[min_l: min_l + min_length] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx new file mode 100644 index 00000000..9ef4a08f --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx @@ -0,0 +1,98 @@ +--- +sidebar_position: 9 +--- + +# 2.5 Fast and Slow Pointers + +## [142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/) + +### Problem Description + +Given a linked list, if there is a cycle, find the starting point of the cycle. + +### Input and Output Example + +The input is a linked list, and the output is a node in the linked list. If there is no cycle, return a null pointer. +In this example, the node with the value 2 is the starting point of the cycle. +If not otherwise specified, LeetCode uses the following data structure to represent a linked list. + +![alt](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png) + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + +### Solution Explanation + +For the problem of detecting cycles in a linked list, there is a universal solution—the fast and slow pointer method (Floyd’s Cycle Detection Algorithm). Given two pointers, named slow and fast, both start at the head of the list. Each time, fast moves two steps, and slow moves one step. If fast reaches the end, it means there is no cycle. If fast can move indefinitely, it means there is a cycle, and slow and fast will eventually meet. When slow and fast meet for the first time, move fast back to the head of the list, and let both slow and fast move one step at a time. When slow and fast meet for the second time, the meeting node is the starting point of the cycle. + +:::warning + +For problems where you only need to determine the presence of a cycle, you can also use a hash table to check for duplicates. + +::: + + + + + +```cpp +ListNode *detectCycle(ListNode *head) { + ListNode *slow = head, *fast = head; + bool is_first_cycle = true; + // Detect the cycle. + while (fast != slow || is_first_cycle) { + if (fast == nullptr || fast->next == nullptr) { + return nullptr; + } + fast = fast->next->next; + slow = slow->next; + is_first_cycle = false; + } + // Find the node. + fast = head; + while (fast != slow) { + slow = slow->next; + fast = fast->next; + } + return fast; +} +``` + + + + +```py +def detectCycle(head: Optional[ListNode]) -> Optional[ListNode]: + slow = head + fast = head + is_first_cycle = True + # Detect the cycle. + while fast != slow or is_first_cycle: + if fast is None or fast.next is None: + return None + fast = fast.next.next + slow = slow.next + is_first_cycle = False + # Find the node. + fast = head + while fast != slow: + fast = fast.next + slow = slow.next + return fast +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md new file mode 100644 index 00000000..540d2e45 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 10 +--- + +# 2.6 Exercises + +## Basic Difficulty + +### [633. Sum of Square Numbers](https://leetcode.com/problems/sum-of-square-numbers/) + +A variation of the Two Sum problem. + +--- + +### [680. Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) + +Another variation of the Two Sum problem. + +--- + +### [524. Longest Word in Dictionary through Deleting](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/) + +A variation of the Merge Sorted Array problem. + +--- + +## Advanced Difficulty + +### [340. Longest Substring with At Most K Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/) + +Requires the use of additional data structures to facilitate tracking the current character states. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json new file mode 100644 index 00000000..175a1be9 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "2. Mastering Two Pointers", + "position": 2, + "link": { + "type": "generated-index", + "description": "Chapter 2: Mastering Two Pointers" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md new file mode 100644 index 00000000..651e3f75 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 11 +--- + +# 3.1 Algorithm Explanation + +`Binary search`, also known as `bisection` or `halving search` (binary search, bisect), reduces the complexity of a search operation by dividing the search interval into two parts at each step and only proceeding with one part. For an array of length $O(n)$, the time complexity of binary search is $O(\log n)$. + +For example, given a sorted array $\{3,4,5,6,7\}$, we want to find out if 4 is in this array. During the first bisection, we consider the median 5. Since 5 is greater than 4, if 4 exists in this array, it must be in the left half of the array. Thus, our search interval becomes $\{3,4,5\}$. (Note: Depending on the specific case and your problem-solving habits, 5 may or may not be included, but this does not affect the time complexity.) In the second bisection, the new median 4 is exactly the number we are looking for. Therefore, for an array of length 5, we only performed 2 searches. In contrast, a linear search might require up to 5 checks in the worst-case scenario. + +Binary search can also be mathematically defined. Given a monotonic function $f(t)$ in the interval $[a, b]$, if $f(a)$ and $f(b)$ have opposite signs, there must be a solution $c$ such that $f(c) = 0$. In the earlier example, $f(t)$ is a discrete function $f(t) = t + 2$, and checking if 4 exists is equivalent to solving $f(t) - 4 = 0$. Since $f(1) - 4 = 3 - 4 = -1 < 0$ and $f(5) - 4 = 7 - 4 = 3 > 0$, and the function is monotonically increasing in this interval, we can use binary search to solve the problem. If the interval is reduced to a single number and no solution exists in that interval, it means there is no discrete solution, i.e., 4 is not in the array. + +In implementation, whether the interval is defined as open or closed at the ends does not matter in most cases. Beginners may find it tricky to decide this. Here are two tips: first, try to consistently use one approach, such as left-closed-right-open (commonly used in C++, Python, etc.) or left-closed-right-closed (convenient for boundary handling). Second, while solving problems, think about whether your method will lead to an infinite loop when the interval is reduced to one or two elements. If it does, consider switching to another approach. + +Binary search can also be viewed as a special case of the two-pointer technique, but we usually differentiate the two. In two-pointer problems, the pointers typically move step by step, whereas in binary search, the pointers move by halving the interval at each step. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx new file mode 100644 index 00000000..758cfd0a --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx @@ -0,0 +1,103 @@ +--- +sidebar_position: 12 +--- + +# 3.2 Calculating Square Root + +## [69. Sqrt(x)](https://leetcode.com/problems/sqrtx/) + +### Problem Description + +Given a non-negative integer `x`, calculate its square root and round it down to the nearest integer. + +### Input and Output Example + +The input is an integer, and the output is also an integer. + +``` +Input: 8 +Output: 2 +``` + +The square root of 8 is 2.82842..., and rounding it down gives 2. + + +### Solution Explanation + +We can think of this problem as: given a non-negative integer `x`, find the solution to $f(t) = t^2 − x = 0$. Since we only consider $t ≥ 0$, $f(t)$ is monotonically increasing in its domain. Given that $f(0) = −x ≤ 0$ and $f(x) = x^2 − x ≥ 0$, we can use binary search on the interval $[0, x]$ to find the solution where $f(t) = 0$. Here, we adopt a left-closed, right-closed approach. + +In the C++ solution, using $mid = (l + r) / 2$ might result in overflow due to $l + r$, so we use $mid = l + (r − l) / 2$ instead. Directly calculating $mid ∗ mid$ might also overflow, so we compare $mid$ with $x / mid$ instead. + + + + +```cpp +int mySqrt(int x) { + int l = 1, r = x, mid, x_div_mid; + while (l <= r) { + mid = l + (r - l) / 2; + x_div_mid = x / mid; + if (mid == x_div_mid) { + return mid; + } + if (mid < x_div_mid) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return r; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + l, r = 1, x + while l <= r: + mid = (l + r) // 2 + mid_sqr = mid**2 + if mid_sqr == x: + return mid + if mid_sqr < x: + l = mid + 1 + else: + r = mid - 1 + return r +``` + + + + + +Additionally, this problem can be solved using a faster algorithm—`Newton's Iterative Method`. The formula is $t_{n+1} = t_n - \frac{f(t_n)}{f'(t_n)}$. For $f(t) = t^2 − x = 0$, the iteration formula becomes $t_{n+1} = \frac{t_n + \frac{x}{t_n}}{2}$. + + + + +```cpp +int mySqrt(int x) { + long t = x; + while (t * t > x) { + t = (t + x / t) / 2; + } + return t; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + t = x + while t**2 > x: + t = (t + x // t) // 2 + return t +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx new file mode 100644 index 00000000..3d4fec5c --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx @@ -0,0 +1,109 @@ +--- +sidebar_position: 13 +--- + +# 3.3 Find Range + +## [34. Find First and Last Position of Element in Sorted Array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/) + +### Problem Description + +Given a sorted integer array and a target value, find the first and last positions where the target value appears. + +### Input and Output Example + +The input is an array and a value, and the output is the positions of the first and last appearances of the target value (starting from 0). If the value does not exist in the array, both return values should be -1. + +``` +Input: nums = [5,7,7,8,8,10], target = 8 +Output: [3,4] +``` + +The number 8 first appears at position 3 and last appears at position 4. + + +### Solution Explanation + +This problem can be seen as implementing C++'s `lower_bound` and `upper_bound` functions or Python's `bisect_left` and `bisect_right` functions. Here, we use a left-closed, right-open interval approach, but a left-closed, right-closed interval would also work. + + + + + +```cpp +int lowerBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] < target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +int upperBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +vector searchRange(vector &nums, int target) { + if (nums.empty()) { + return vector{-1, -1}; + } + int lower = lowerBound(nums, target); + int upper = upperBound(nums, target) - 1; + if (lower == nums.size() || nums[lower] != target) { + return vector{-1, -1}; + } + return vector{lower, upper}; +} +``` + + + + +```py +def lowerBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] < target: + l = mid + 1 + else: + r = mid + return l + +def upperBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] <= target: + l = mid + 1 + else: + r = mid + return l + +def searchRange(nums: List[int], target: int) -> List[int]: + if not nums: + return [-1, -1] + lower = lowerBound(nums, target) + upper = upperBound(nums, target) - 1 + if lower == len(nums) or nums[lower] != target: + return [-1, -1] + return [lower, upper] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx new file mode 100644 index 00000000..e495cf1b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 14 +--- + +# 3.4 Find Maximum + +## [162. Find Peak Element](https://leetcode.com/problems/find-peak-element/) + +### Problem Description + +Given an array, a maximum is defined as a number that is greater than both of its neighbors. Find the position of any maximum. There may be multiple maxima in the array, and you can return any of them. The required time complexity is $O(\log n)$. + +### Input and Output Example + +The input is an array, and the output is the position of a maximum. + + +``` +Input: nums = [1,2,3,1] +Output: 2 +``` + +The maximum 3 appears at position 2. + + +### Solution Explanation + +To achieve $O(\log n)$ time complexity, we can use binary search on the array. If the endpoints are not maxima, and the current midpoint is not a maximum, then one of its sides must contain a maximum. + + + + + +```cpp +int findPeakElement(vector& nums) { + int n = nums.size(); + if (n == 1) { + return 0; + } + if (nums[0] > nums[1]) { + return 0; + } + if (nums[n - 1] > nums[n - 2]) { + return n - 1; + } + int l = 1, r = n - 2, mid; + while (l <= r) { + mid = l + (r - l) / 2; + if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1]) { + return mid; + } else if (nums[mid] > nums[mid - 1]) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return -1; +} +``` + + + + +```py +def findPeakElement(self, nums: List[int]) -> int: + n = len(nums) + if n == 1: + return 0 + if nums[0] > nums[1]: + return 0 + if nums[n - 1] > nums[n - 2]: + return n - 1 + l, r = 1, n - 2 + while l <= r: + mid = (l + r) // 2 + if nums[mid] > nums[mid + 1] and nums[mid] > nums[mid - 1]: + return mid + elif nums[mid] > nums[mid - 1]: + l = mid + 1 + else: + r = mid - 1 + return -1 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx new file mode 100644 index 00000000..93668f56 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx @@ -0,0 +1,99 @@ +--- +sidebar_position: 15 +--- + +# 3.5 Search in Rotated Array + +## [81. Search in Rotated Sorted Array II](https://leetcode.com/problems/search-in-rotated-sorted-array-ii/) + +### Problem Description + +An originally sorted array is connected end-to-end and then broken at some position (e.g., [1,2,2,3,4,5] → [2,3,4,5,1,2], broken between the first and second positions). We call this a rotated array. Given a target value, determine whether this value exists in the rotated array. + +### Input and Output Example + +The input is an array and a value, and the output is a boolean indicating whether the target exists in the array. + +``` +Input: nums = [2,5,6,0,0,1,2], target = 0 +Output: true +``` + +Even though the array is rotated, we can still use its sorted property to perform binary search. At the current midpoint, if its value is less than or equal to the right endpoint, the right interval is sorted. Otherwise, the left interval is sorted. If the target value is in the sorted interval, continue the binary search in that interval. Otherwise, proceed with the other interval. Here, we adopt a left-closed, right-closed interval approach. + + +### Solution Explanation + + + + + + +```cpp +bool search(vector& nums, int target) { + int l = 0, r = nums.size() - 1; + while (l <= r) { + int mid = l + (r - l) / 2; + if (nums[mid] == target) { + return true; + } + if (nums[mid] == nums[l]) { + // Cannot determine which interval is sorted, but l cannot be target. + ++l; + } else if (nums[mid] == nums[r]) { + // Cannot determine which interval is sorted, but r cannot be target. + --r; + } else if (nums[mid] < nums[r]) { + // Right interval is sorted. + if (target > nums[mid] && target <= nums[r]) { + l = mid + 1; + } else { + r = mid - 1; + } + } else { + // Left interval is sorted. + if (target >= nums[l] && target < nums[mid]) { + r = mid - 1; + } else { + l = mid + 1; + } + } + } + return false; +} +``` + + + + +```py +def search(nums: List[int], target: int) -> bool: + l, r = 0, len(nums) - 1 + while l <= r: + mid = (l + r) // 2 + if nums[mid] == target: + return True + if nums[mid] == nums[l]: + # Cannot determine which interval is sorted, but l cannot be target. + l += 1 + elif nums[mid] == nums[r]: + # Cannot determine which interval is sorted, but r cannot be target. + r -= 1 + elif nums[mid] < nums[r]: + # Right interval is sorted. + if nums[mid] < target <= nums[r]: + l = mid + 1 + else: + r = mid - 1 + else: + # Left interval is sorted. + if nums[l] <= target < nums[mid]: + r = mid - 1 + else: + l = mid + 1 + return False +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md new file mode 100644 index 00000000..19e8c1f6 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 16 +--- + +# 3.6 Exercises + +## Basic Difficulty + +### [154. Find Minimum in Rotated Sorted Array II](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/) + +A variation of the rotated array problem. + +--- + +### [540. Single Element in a Sorted Array](https://leetcode.com/problems/single-element-in-a-sorted-array/) + +What changes occur in the parity (odd/even positions) of values before and after the unique element? + +--- + +## Advanced Difficulty + +### [4. Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) + +Requires binary search on both arrays simultaneously. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json new file mode 100644 index 00000000..546acc0d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "3. Iaido! Binary Search", + "position": 3, + "link": { + "type": "generated-index", + "description": "Chapter 3: Iaido! Binary Search" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx new file mode 100644 index 00000000..fb119c89 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx @@ -0,0 +1,148 @@ +--- +sidebar_position: 17 +--- + +# 4.1 Common Sorting Algorithms + +Although sorting can be achieved in C++ and Python using the `sort` function and it is rare to write sorting algorithms manually during coding challenges, understanding various sorting algorithms helps deepen your knowledge of basic algorithms and solve problems derived from these algorithms. Here, we introduce two sorting algorithms with a time complexity of $O(n \log n)$: `Quick Sort` and `Merge Sort`. The former is generally faster, while the latter ensures that elements with the same value maintain their relative order in the array (i.e., it is a "stable sort"). + + +## Quicksort + +The principle of Quick Sort is straightforward: for an unsorted segment, we randomly choose a position as the pivot and rearrange the elements such that all numbers smaller than the pivot are moved to its left and all numbers larger than the pivot are moved to its right. After this operation, we recursively perform Quick Sort on the segments to the left and right of the pivot. It can be proven that if the pivot is chosen randomly, the average complexity of this algorithm is $O(n \log n)$, while the worst-case complexity is $O(n^2)$. + +We use a left-closed, right-closed interval approach, initializing with $l = 0, r = n - 1$. + + + + +```cpp +void quickSort(vector &nums, int l, int r) { + if (l >= r) { + return; + } + // Randomly choose a pivot within the current [l, r] interval. + int pivot = l + (rand() % (r - l + 1)); + int pivot_val = nums[pivot]; + // Swap the pivot with the first element. + swap(nums[l], nums[pivot]); + // Traverse inward from both ends of [l+1, r] to find misplaced elements. + int i = l + 1, j = r; + while (true) { + while (i < j && nums[j] >= pivot_val) { + --j; + } + while (i < j && nums[i] <= pivot_val) { + ++i; + } + if (i == j) { + break; + } + // Swap the misplaced elements. + swap(nums[i], nums[j]); + } + // Swap the pivot back to its correct position. + int new_pivot = nums[i] <= nums[l] ? i : i - 1; + swap(nums[l], nums[new_pivot]); + quickSort(nums, l, new_pivot - 1); + quickSort(nums, new_pivot + 1, r); +} +``` + + + + +```py +def quickSort(nums: List[int], l: int, r: int) -> None: + if l >= r: + return + # Randomly choose a pivot within the current [l, r] interval. + pivot = random.randint(l, r) + pivot_val = nums[pivot] + # Swap the pivot with the first element. + nums[l], nums[pivot] = nums[pivot], nums[l] + # Traverse inward from both ends of [l+1, r] to find misplaced elements. + i, j = l + 1, r + while True: + while i < j and nums[j] >= pivot_val: + j -= 1 + while i < j and nums[i] <= pivot_val: + i += 1 + if i == j: + break + # Swap the misplaced elements. + nums[i], nums[j] = nums[j], nums[i] + # Swap the pivot back to its correct position. + new_pivot = i if nums[i] <= nums[l] else i - 1 + nums[l], nums[new_pivot] = nums[new_pivot], nums[l] + quickSort(nums, l, new_pivot - 1) + quickSort(nums, new_pivot + 1, r) +``` + + + + + +## Merge Sort + +Merge Sort is a classic divide-and-conquer algorithm, which we will elaborate on in later sections. In short, for an unsorted segment, we first sort its left and right halves separately and then merge the two halves ("conquer"). Sorting each half can be achieved recursively by further splitting each half into two parts ("divide"). + +We use a left-closed, right-closed interval approach, initializing with $l = 0, r = n - 1$, and pre-allocate an array cache of the same size as nums to store intermediate results. + + + + +```cpp +void mergeSort(vector &nums, vector &cache, int l, int r) { + if (l >= r) { + return; + } + // Divide. + int mid = l + (r - l) / 2; + mergeSort(nums, cache, l, mid); + mergeSort(nums, cache, mid + 1, r); + // Conquer. + // Use two pointers, i and j, to traverse the left [l, mid] and right [mid+1, r] halves. + int i = l, j = mid + 1; + for (int pos = l; pos <= r; ++pos) { + if (j > r || (i <= mid && nums[i] <= nums[j])) { + cache[pos] = nums[i++]; + } else { + cache[pos] = nums[j++]; + } + } + // Copy the sorted elements back to nums. + for (int pos = l; pos <= r; ++pos) { + nums[pos] = cache[pos]; + } +} +``` + + + + +```py +def mergeSort(nums: List[int], cache: List[int], l: int, r: int) -> None: + if l >= r: + return + # Divide. + mid = (l + r) // 2 + mergeSort(nums, cache, l, mid) + mergeSort(nums, cache, mid + 1, r) + # Conquer. + # Use two pointers, i and j, to traverse the left [l, mid] and right [mid+1, r] halves. + i, j = l, mid + 1 + for pos in range(l, r + 1): + if j > r or (i <= mid and nums[i] <= nums[j]): + cache[pos] = nums[i] + i += 1 + else: + cache[pos] = nums[j] + j += 1 + # Copy the sorted elements back to nums. + nums[l:r+1] = cache[l:r+1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx new file mode 100644 index 00000000..0b5e669d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx @@ -0,0 +1,78 @@ +--- +sidebar_position: 18 +--- + +# 4.2 Quick Select + +## [215. Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) + +### Problem Description + +In an unsorted array, find the $k$-th largest element. + +### Input and Output Example + +Input an array and a target value $k$, output the $k$-th largest element. The problem guarantees there is always a solution. + +``` +Input: [3,2,1,5,6,4] and k = 2 +Output: 5 +``` + +### Solution Explanation + +`Quick Select` is commonly used to solve k-th element problems, achieving an average time complexity of $O(n)$ and space complexity of $O(1)$. Its implementation is similar to Quick Sort, but it only focuses on finding the $k$-th largest pivot without sorting the rest of the elements. Like Quick Sort, Quick Select generally requires shuffling the array first to avoid a worst-case time complexity of $O(n^2)$. + +If we directly use the Quick Sort code above, it may approach the time limit on LeetCode. Instead, we can trade space for time by directly storing elements greater than, less than, and equal to the pivot to minimize swaps. + + + + +```cpp +int findKthLargest(vector nums, int k) { + int pivot = rand() % nums.size(); + int pivot_val = nums[pivot]; + vector larger, equal, smaller; + for (int num : nums) { + if (num > pivot_val) { + larger.push_back(num); + } else if (num < pivot_val) { + smaller.push_back(num); + } else { + equal.push_back(num); + } + } + if (k <= larger.size()) { + return findKthLargest(larger, k); + } + if (k > larger.size() + equal.size()) { + return findKthLargest(smaller, k - larger.size() - equal.size()); + } + return pivot_val; +} +``` + + + + +```py +def findKthLargest(nums: List[int], k: int) -> int: + pivot_val = random.choice(nums) + larger, equal, smaller = [], [], [] + for num in nums: + if num > pivot_val: + larger.append(num) + elif num < pivot_val: + smaller.append(num) + else: + equal.append(num) + if k <= len(larger): + return findKthLargest(larger, k) + if k > len(larger) + len(equal): + return findKthLargest(smaller, k - len(larger) - len(equal)) + return pivot_val +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx new file mode 100644 index 00000000..1650c126 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx @@ -0,0 +1,83 @@ +--- +sidebar_position: 19 +--- + +# 4.3 Bucket Sort + +## [347. Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) + +### Problem Description + +Given an array, find the top $k$ most frequent elements. + +### Input and Output Example + +Input is an array and a target value $k$. Output is an array of length $k$. + +``` +Input: nums = [1,1,1,1,2,2,3,4], k = 2 +Output: [1,2] +``` + +In this example, the two most frequent numbers are 1 and 2. + +### Solution Explanation + +As the name suggests, `bucket sort` involves creating a bucket for each value, where the bucket records the frequency of that value (or other attributes), and then sorting the buckets. For this example, we first use bucket sort to obtain four buckets [1,2,3,4], with values [4,2,1,1], representing the frequency of each number. + +Next, we sort the buckets by frequency, and the top $k$ buckets are the top $k$ most frequent elements. We can use any sorting algorithm here or even perform another bucket sort, placing each old bucket into new buckets based on frequency. For this example, since the maximum frequency is 4, we create four new buckets [1,2,3,4], which contain the old buckets as follows: [[3,4],[2],[],[1]]. Finally, we iterate from the end to the beginning until we find $k$ old buckets. + +We can use `unordered_map` in C++ or `dict` in Python to implement a hash table. + + + + +```cpp +vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (int num : nums) { + ++counts[num]; + } + unordered_map> buckets; + for (auto [num, count] : counts) { + buckets[count].push_back(num); + } + vector top_k; + for (int count = nums.size(); count >= 0; --count) { + if (buckets.contains(count)) { + for (int num : buckets[count]) { + top_k.push_back(num); + if (top_k.size() == k) { + return top_k; + } + } + } + } + return top_k; +} +``` + + + + +```py +def topKFrequent(nums: List[int], k: int) -> List[int]: + counts = Counter(nums) + buckets = dict() + for num, count in counts.items(): + if count in buckets: + buckets[count].append(num) + else: + buckets[count] = [num] + top_k = [] + for count in range(len(nums), 0, -1): + if count in buckets: + top_k += buckets[count] + if len(top_k) >= k: + return top_k[:k] + return top_k[:k] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md new file mode 100644 index 00000000..0f811934 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 20 +--- + +# 4.4 Exercises + +## Basic Difficulty + +### [451. Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) + +A variant of the bucket sort problem. + +--- + +## Advanced Difficulty + +### [75. Sort Colors](https://leetcode.com/problems/sort-colors/) + +A classic Dutch National Flag problem, testing how to sort three repeated and unordered values. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json new file mode 100644 index 00000000..5c12d644 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "4. Peculiar Sorting Algorithms", + "position": 4, + "link": { + "type": "generated-index", + "description": "Chapter 4: Peculiar Sorting Algorithms" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md new file mode 100644 index 00000000..3466ab7e --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 21 +--- + +# 5.1 Algorithm Explanation + +`Depth First Search (DFS)` and `Breadth First Search (BFS)` are two of the most common priority search methods. They are widely used for searching in structures such as graphs and trees. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx new file mode 100644 index 00000000..034fc8dc --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx @@ -0,0 +1,375 @@ +--- +sidebar_position: 22 +--- + +# 5.2 Depth First Search + +`Depth First Search (DFS)` is a search method where, upon encountering a new node, you immediately traverse that new node. Therefore, traversal requires a `Last In, First Out (LIFO) stack`, which can also be implemented using `recursion`, equivalent to using a stack. In a tree structure, since traversal always invokes the new node, it appears as if progressing in the "depth" direction. In Python, collections.deque can be used to implement the stack in C++. However, in most cases, using vector in C++ or list in Python is preferred as these structures not only support LIFO but also allow random access. + +Consider the following simple tree, starting traversal from node 1. If the traversal order is from the left child to the right child, the process follows the strategy of moving "deeper" first: 1 (starting node) → 2 (deeper left child) → 4 (deeper left child) → 2 (no children, return to parent) → 1 (all children traversed, return to parent) → 3 (deeper right child) → 1 (no children, return to parent) → end (all children traversed). If implemented with a stack, the stack's top element evolves as follows: 1 → 2 → 4 → 3. + + +``` + 1 + / \ + 2 3 + / +4 +``` + +DFS can also be used to `detect cycles`: Record the parent node of each traversed node. If a node is revisited with a different parent, a cycle is detected. Alternatively, topological sorting can identify cycles: if a node has a non-zero in-degree at the end, a cycle exists. + +Sometimes, it is necessary to mark already traversed nodes to avoid redundant searches. This technique is called `state recording` or `memoization`. + +## [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/) + +### Problem Description + +Given a 2D binary grid where `0` represents water and `1` represents land, islands are formed by connected land cells. Each cell is connected only to its adjacent cells (up, down, left, right). Find the maximum area of an island. + + +### Input and Output Example + +Input: a 2D grid; Output: the maximum area of an island. + + +``` +Input: +[[1,0,1,1,0,1,0,1], + [1,0,1,1,0,1,1,1], + [0,0,0,0,0,0,0,1]] +Output: 6 +``` + +The maximum area of an island is 6, located at the far right. + +### Solution Explanation + +This is a standard search problem, ideal for practicing DFS. Typically, DFS problems are divided into a main function for traversing all positions and a helper function for the recursive DFS. While DFS can also be implemented using a stack, recursion is often more convenient for competitive programming due to easier implementation and backtracking. However, in real-world engineering, a stack may be preferable to avoid recursion stack overflow and for easier understanding. + +Below is the stack implementation. A small trick is used for traversal directions: an array `[-1, 0, 1, 0, -1]` represents the four directions (up, down, left, right). You can also explicitly write `[-1, 0]`, `[1, 0]`, `[0, 1]`, `[0, -1]` for clarity. + + + + +```cpp +int maxAreaOfIsland(vector>& grid) { + vector direction{-1, 0, 1, 0, -1}; + int m = grid.size(), n = grid[0].size(), max_area = 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + stack> island; + // Initialize the first node. + int local_area = 1; + grid[i][j] = 0; + island.push({i, j}); + // DFS using stack. + while (!island.empty()) { + auto [r, c] = island.top(); + island.pop(); + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + // Add neighboring nodes that meet the conditions. + if (x >= 0 && x < m && y >= 0 && y < n && + grid[x][y] == 1) { + ++local_area; + grid[x][y] = 0; + island.push({x, y}); + } + } + } + max_area = max(max_area, local_area); + } + } + } + return max_area; +} +``` + + + + +```py +def maxAreaOfIsland(grid: List[List[int]]) -> int: + direction = [-1, 0, 1, 0, -1] + m, n, max_area = len(grid), len(grid[0]), 0 + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + island = [] + # Initialize the first node. + local_area = 1 + grid[i][j] = 0 + island.append((i, j)) + # DFS using stack. + while island: + r, c = island.pop() + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + # Add neighboring nodes that meet the conditions. + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: + local_area += 1 + grid[x][y] = 0 + island.append((x, y)) + max_area = max(max_area, local_area) + return max_area +``` + + + + + +Below, we present the recursive implementation. Be sure to check the boundary conditions when performing recursive searches. This can be done either before calling the auxiliary function or at the beginning of the auxiliary function itself. In this example, we do not use the array [-1, 0, 1, 0, -1] for searching in four directions (up, down, left, and right). Instead, we explicitly write four different recursive functions. Either approach works, and readers can choose to master either one. + + + + + +```cpp +// Auxiliary function. +int dfs(vector>& grid, int r, int c) { + if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size() || + grid[r][c] == 0) { + return 0; + } + grid[r][c] = 0; + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)); +} + +// Main function. +int maxAreaOfIsland(vector>& grid) { + int max_area = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + max_area = max(max_area, dfs(grid, i, j)); + } + } + return max_area; +} +``` + + + + +```py +# Auxiliary function +def dfs(grid: List[List[int]], r: int, c: int) -> int: + if r < 0 or r >= len(grid) or c < 0 or c >= len(grid[0]) or grid[r][c] == 0: + return 0 + grid[r][c] = 0 + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)) + +# Main function +def maxAreaOfIsland(grid: List[List[int]]) -> int: + max_area = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + max_area = max(max_area, dfs(grid, i, j)) + return max_area +``` + + + + + +## [547. Number of Provinces](https://leetcode.com/problems/number-of-provinces/) + +### Problem Description + +Given a 2D 0-1 matrix, if position (i, j) is 1, it means city i and city j belong to the same province. The adjacency relationship between cities is transitive; for example, if city a is connected to city b, and city b is connected to city c, then city a and city c are also connected, meaning they are part of the same province. The task is to calculate the total number of provinces. + +### Input and Output Example + +The input is a 2D matrix, and the output is an integer representing the number of provinces. Since the adjacency relationship is symmetric, the 2D matrix is symmetric. Additionally, each city is part of its own province, so the diagonal values are all 1. + +``` +Input: +[[1,1,0], + [1,1,0], + [0,0,1]] +Output: 2 +``` + +In this example, cities [1, 2] are in one province, and city [3] is in another province. + +### Solution Explanation + +In the previous problem, the graph was represented such that each position represented a node, and each node was adjacent to its top, bottom, left, and right neighbors. In this problem, each row (or column) represents a node, and each column (or row) indicates whether there is an adjacent node. The previous problem had 𝑚 × 𝑛 nodes, each with 4 edges; in this problem, there are 𝑛 nodes, and each node can have up to 𝑛 edges if it is connected to all other cities, or a minimum of 1 edge if it is its own province. Once the graph representation is understood, this problem is essentially the same as the previous one: finding the number of provinces (or clusters of connected nodes). Here, we use a recursive approach. + +:::warning + +For problems involving connected nodes, we can also use the Union-Find algorithm to quickly manage connections and searches. This will be discussed in later sections. + +::: + + + + +```cpp +// Auxiliary function +void dfs(vector>& isConnected, int i, vector& visited) { + visited[i] = true; + for (int j = 0; j < isConnected.size(); ++j) { + if (isConnected[i][j] == 1 && !visited[j]) { + dfs(isConnected, j, visited); + } + } +} + +// Main function +int findCircleNum(vector>& isConnected) { + int n = isConnected.size(), count = 0; + // Prevent revisiting already searched nodes + vector visited(n, false); + for (int i = 0; i < n; ++i) { + if (!visited[i]) { + dfs(isConnected, i, visited); + ++count; + } + } + return count; +} +``` + + + + +```py +# Auxiliary function +def dfs(isConnected: List[List[int]], city: int, visited: Set[int]): + visited.add(city) + for i in range(len(isConnected)): + if isConnected[city][i] == 1 and i not in visited: + dfs(isConnected, i, visited) + +# Main function +def findCircleNum(isConnected: List[List[int]]) -> int: + count = 0 + # Prevent revisiting already searched nodes + visited = set() + for i in range(len(isConnected)): + if i not in visited: + dfs(isConnected, i, visited) + count += 1 + return count +``` + + + + + + +## [417. Pacific Atlantic Water Flow](https://leetcode.com/problems/pacific-atlantic-water-flow/) + +### Problem Description + +Given a 2D matrix of non-negative integers, each position represents the elevation height. Assume that the left and top edges are the Pacific Ocean, and the right and bottom edges are the Atlantic Ocean. Determine the positions from which water can flow down to both the Pacific and Atlantic Oceans. Water can only flow from a higher or equal elevation to a lower or equal elevation. + +### Input and Output Example + +The input is a 2D array of non-negative integers representing the elevation heights. The output is a 2D array where the second dimension has a fixed size of 2, representing the coordinates of positions that satisfy the conditions. + +``` +Input: +Pacific ~ ~ ~ ~ ~ + ~ 1 2 2 3 (5) * + ~ 3 2 3 (4) (4) * + ~ 2 4 (5) 3 1 * + ~ (6) (7) 1 4 5 * + ~ (5) 1 1 2 4 * + * * * * * Atlantic +Output: [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] +``` + +In this example, the areas marked with parentheses are the positions satisfying the condition. + +### Solution Explanation + +The problem requires determining positions from which water can flow to both oceans. If we attempt to search all positions, the complexity could become very high without pruning. Instead, we can reverse the perspective: starting from both oceans and simulating water flowing upwards. By doing so, we only need to search the four edges of the matrix. After completing the search, we iterate through the matrix to identify positions that can be reached from both the Pacific and Atlantic Oceans. + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// Auxiliary function +void dfs(const vector>& heights, vector>& can_reach, + int r, int c) { + if (can_reach[r][c]) { + return; + } + can_reach[r][c] = true; + for (int i = 0; i < 4; ++i) { + int x = r + direction[i], y = c + direction[i + 1]; + if (x >= 0 && x < heights.size() && y >= 0 && y < heights[0].size() && + heights[r][c] <= heights[x][y]) { + dfs(heights, can_reach, x, y); + } + } +} + +// Main function +vector> pacificAtlantic(vector>& heights) { + int m = heights.size(), n = heights[0].size(); + vector> can_reach_p(m, vector(n, false)); + vector> can_reach_a(m, vector(n, false)); + vector> can_reach_p_and_a; + for (int i = 0; i < m; ++i) { + dfs(heights, can_reach_p, i, 0); + dfs(heights, can_reach_a, i, n - 1); + } + for (int i = 0; i < n; ++i) { + dfs(heights, can_reach_p, 0, i); + dfs(heights, can_reach_a, m - 1, i); + } + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (can_reach_p[i][j] && can_reach_a[i][j]) { + can_reach_p_and_a.push_back({i, j}); + } + } + } + return can_reach_p_and_a; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# Auxiliary function +def dfs(heights: List[List[int]], can_reach: List[List[int]], r: int, c: int): + if can_reach[r][c]: + return + can_reach[r][c] = True + for i in range(4): + x, y = r + direction[i], c + direction[i + 1] + if (x >= 0 and x < len(heights) and y >= 0 and y < len(heights[0]) and + heights[x][y] >= heights[r][c]): + dfs(heights, can_reach, x, y) + +# Main function +def pacificAtlantic(heights: List[List[int]]) -> List[List[int]]: + m, n = len(heights), len(heights[0]) + can_reach_p = [[False for _ in range(n)] for _ in range(m)] + can_reach_a = [[False for _ in range(n)] for _ in range(m)] + for i in range(m): + dfs(heights, can_reach_p, i, 0) + dfs(heights, can_reach_a, i, n - 1) + for j in range(n): + dfs(heights, can_reach_p, 0, j) + dfs(heights, can_reach_a, m - 1, j) + return [ + [i, j] for i in range(m) for j in range(n) + if can_reach_p[i][j] and can_reach_a[i][j] + ] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx new file mode 100644 index 00000000..ecc21bf4 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx @@ -0,0 +1,379 @@ +--- +sidebar_position: 23 +--- + +# 5.3 Backtracking + +`Backtracking` is a special case of priority search, also known as the trial-and-error method. It is commonly used in depth-first search when the state of nodes needs to be recorded. Typically, problems involving permutations, combinations, or selections are more conveniently solved using backtracking. + +As the name suggests, the core of backtracking is to backtrack. When reaching a certain node, if we find that the current node (and its child nodes) do not meet the target requirements, we backtrack to the previous node and continue the search, while `restoring the state modified at the current node`. The benefit is that we can modify only the global state of the graph without creating a new graph to store states during each traversal. In terms of implementation, backtracking is similar to regular depth-first search, involving steps like [modifying the current node state]→[recursing into child nodes], but it adds an extra backtracking step, turning it into [modifying the current node state]→[recursing into child nodes]→[restoring the current node state]. + +For readers unfamiliar with backtracking, this explanation might be unclear, which is entirely normal. The following problems are intended to help you understand backtracking. If it’s still confusing, remember two simple principles: `1. Pass states by reference, and 2. Restore all state changes after recursion`. + +There are generally two cases for backtracking modifications: one involves modifying the last output, such as in permutations and combinations, and the other involves modifying visit markers, such as searching for strings in a matrix. + + +## [46. Permutations](https://leetcode.com/problems/permutations/) + +### Problem Description + +Given an array of distinct integers, return all possible permutations. + +### Input and Output Example + +The input is a one-dimensional integer array, and the output is a two-dimensional array representing all permutations of the input array. + +``` +Input: [1,2,3] +Output: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]] +``` + +The order of output does not matter as long as all permutations are included. + +### Solution Explanation + +To generate all permutations, for each position \(i\), we can swap it with any subsequent position, then process position \(i+1\), and so on until the last position is processed. Instead of creating a new array to store the partially swapped numbers at each step, we use backtracking to modify the original array directly. Once recursion is complete, we restore the original state. + +For example, using the input `[1,2,3]`, this method outputs permutations in the order: `[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]]`, ensuring all possible permutations are covered. + + + + + +```cpp +// Helper function. +void backtracking(vector &nums, int level, + vector> &permutations) { + if (level == nums.size() - 1) { + permutations.push_back(nums); // Save the current permutation. + return; + } + for (int i = level; i < nums.size(); ++i) { + swap(nums[i], nums[level]); // Modify current state. + backtracking(nums, level + 1, permutations); // Recur to next level. + swap(nums[i], nums[level]); // Revert current state. + } +} + +// Main function. +vector> permute(vector &nums) { + vector> permutations; + backtracking(nums, 0, permutations); + return permutations; +} +``` + + + + +```py +# Helper function. +def backtracking(nums: List[int], level: int, permutations: List[List[int]]): + if level == len(nums) - 1: + permutations.append(nums[:]) # Save current permutation via shallow copy. + return + for i in range(level, len(nums)): + nums[i], nums[level] = nums[level], nums[i] # Modify current state. + backtracking(nums, level + 1, permutations) # Recur to next level. + nums[i], nums[level] = nums[level], nums[i] # Revert current state. + +# Main function. +def permute(nums: List[int]) -> List[List[int]]: + permutations = [] + backtracking(nums, 0, permutations) + return permutations +``` + + + + + +## [77. Combinations](https://leetcode.com/problems/combinations/) + +### Problem Description + +Given an integer `n` and an integer `k`, find all combinations of `k` numbers chosen from the range `1` to `n`. + +### Input and Output Example + +The input consists of two positive integers `n` and `k`. The output is a two-dimensional array representing all possible combinations. + +``` +Input: n = 4, k = 2 +Output: [[2,4], [3,4], [2,3], [1,2], [1,3], [1,4]] +``` + +The order of the dimensions in the two-dimensional array can be arbitrary. + +### Solution Explanation + +Similar to permutation problems, we can use backtracking. In permutations, backtracking swaps positions, while in combinations, it determines whether to include the current number in the result. + + + + + +```cpp +// Auxiliary function +void backtracking(vector>& combinations, vector& pick, int pos, + int n, int k) { + if (pick.size() == k) { + combinations.push_back(pick); + return; + } + for (int i = pos; i <= n; ++i) { + pick.push_back(i); // Modify the current node state + backtracking(combinations, pick, i + 1, n, k); // Recurse to child nodes + pick.pop_back(); // Restore the current node state + } +} + +// Main function +vector> combine(int n, int k) { + vector> combinations; + vector pick; + backtracking(combinations, pick, 1, n, k); + return combinations; +} +``` + + + + +```py +# Auxiliary function +def backtracking( + combinations: List[List[int]], pick: List[int], pos: int, n: int, k: int +): + if len(pick) == k: + combinations.append(pick[:]) # int is a basic type, shallow copy is sufficient + return + for i in range(pos, n + 1): + pick.append(i) # Modify the current node state + backtracking(combinations, pick, i + 1, n, k) # Recurse to child nodes + pick.pop() # Restore the current node state + +# Main function +def combine(n: int, k: int) -> List[List[int]]: + combinations = [] + pick = [] + backtracking(combinations, pick, 1, n, k) + return combinations +``` + + + + + +## [79. Word Search](https://leetcode.com/problems/word-search/) + +### Problem Description + +Given a grid of letters, where all letters are connected to adjacent letters in four directions (up, down, left, right), determine whether a given word can be found in the grid. + +### Input and Output Example + +The input consists of a 2D character array and a string. The output is a boolean indicating whether the word can be found. + +``` +Input: word = "ABCCED", board = +[[’A’,’B’,’C’,’E’], + [’S’,’F’,’C’,’S’], + [’A’,’D’,’E’,’E’]] +Output: true +``` + +Starting from the top-left corner 'A', we can move right, then down, and finally left to find the continuous sequence "ABCCED". + +### Solution Explanation + +Unlike permutation and combination problems, this problem modifies the visited state. During a depth-first search from any position, we mark the current position as visited to prevent revisiting (e.g., avoid moving right and then back left). After all possibilities are explored, we revert the current position to unvisited to avoid interfering with other searches. Using backtracking, we only need to modify a 2D visited matrix without passing the state as a new object to the recursive function. + + + + + +```cpp +// Auxiliary function +bool backtracking(vector>& board, string& word, + vector>& visited, int i, int j, int word_pos) { + if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || + visited[i][j] || board[i][j] != word[word_pos]) { + return false; + } + if (word_pos == word.size() - 1) { + return true; + } + visited[i][j] = true; // Modify the current node state + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) || + backtracking(board, word, visited, i - 1, j, word_pos + 1) || + backtracking(board, word, visited, i, j + 1, word_pos + 1) || + backtracking(board, word, visited, i, j - 1, word_pos + 1)) { + return true; // Recurse to child nodes + } + visited[i][j] = false; // Restore the current node state + return false; +} + +// Main function +bool exist(vector>& board, string word) { + int m = board.size(), n = board[0].size(); + vector> visited(m, vector(n, false)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (backtracking(board, word, visited, i, j, 0)) { + return true; + } + } + } + return false; +} +``` + + + + +```py +# Auxiliary function +def backtracking(board: List[List[str]], word: str, + visited: List[List[bool]], i: int, j: int, word_pos: int): + if (i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) + or visited[i][j] or board[i][j] != word[word_pos]): + return False + if word_pos == len(word) - 1: + return True + visited[i][j] = True # Modify the current node state + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) or + backtracking(board, word, visited, i - 1, j, word_pos + 1) or + backtracking(board, word, visited, i, j + 1, word_pos + 1) or + backtracking(board, word, visited, i, j - 1, word_pos + 1)): + return True # Recurse to child nodes + visited[i][j] = False # Restore the current node state + return False + +# Main function +def exist(board: List[List[str]], word: str) -> bool: + m, n = len(board), len(board[0]) + visited = [[False for _ in range(n)] for _ in range(m)] + return any([ + backtracking(board, word, visited, i, j, 0) + for i in range(m) for j in range(n) + ]) +``` + + + + + +## [51. N-Queens](https://leetcode.com/problems/n-queens/) + +### Problem Description + +Given an n x n chessboard, determine all possible ways to place n queens so that no two queens attack each other. A queen can attack another queen on the same row, column, or diagonals. + +
+![](n-queens.png) +
Problem 51 - An example solution to the 8-Queens problem
+
+ +### Input and Output Example + +Input is an integer n, output is a 2D list of strings representing all valid chessboard configurations. + +``` +Input: 4 +Output: [ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] +``` + +In this example, dots represent empty squares, and 'Q' represents queens. + +### Solution Explanation + +Similar to finding words in a matrix, this problem involves modifying the state matrix during backtracking. The difference here is that we need to track visited columns, left diagonals, and right diagonals. If we traverse by rows to place queens, we don't need to maintain a separate visited array for rows. + + + + +```cpp +// Auxiliary function +void backtracking(vector> &solutions, vector &board, + vector &column, vector &ldiag, + vector &rdiag, int row) { + int n = board.size(); + if (row == n) { + solutions.push_back(board); + return; + } + for (int i = 0; i < n; ++i) { + if (column[i] || ldiag[n - row + i - 1] || rdiag[row + i]) { + continue; + } + // Modify the current node state + board[row][i] = 'Q'; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = true; + // Recurse to child nodes + backtracking(solutions, board, column, ldiag, rdiag, row + 1); + // Restore the current node state + board[row][i] = '.'; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = false; + } +} + +// Main function +vector> solveNQueens(int n) { + vector> solutions; + vector board(n, string(n, ’.’)); + vector column(n, false); + vector ldiag(2 * n - 1, false); + vector rdiag(2 * n - 1, false); + backtracking(solutions, board, column, ldiag, rdiag, 0); + return solutions; +} +``` + + + + +```py +# Auxiliary function +def backtracking(solutions: List[List[str]], board: List[List[str]], + column: List[bool], ldiag: List[bool], rdiag: List[bool], row: int): + n = len(board) + if row == n: + solutions.append(["".join(row) for row in board]) + return + for i in range(n): + if column[i] or ldiag[n - row + i - 1] or rdiag[row + i]: + continue + # Modify the current node state + board[row][i] = "Q" + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = True + # Recurse to child nodes + backtracking(solutions, board, column, ldiag, rdiag, row + 1) + # Restore the current node state + board[row][i] = "." + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = False + +# Main function +def solveNQueens(n: int) -> List[List[str]]: + solutions = [] + board = [["." for _ in range(n)] for _ in range(n)] + column = [False] * n + ldiag = [False] * (2 * n - 1) + rdiag = [False] * (2 * n - 1) + backtracking(solutions, board, column, ldiag, rdiag, 0) + return solutions +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx new file mode 100644 index 00000000..4293700a --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx @@ -0,0 +1,454 @@ +--- +sidebar_position: 24 +--- + +# 5.4 Breadth-First Search + +`Breadth-First Search` (BFS) differs from Depth-First Search in that it traverses level by level, so it `requires a first-in, first-out queue` instead of the last-in, first-out stack used in DFS. Since BFS processes nodes by levels, it explores nodes in a "broad" manner and is often used for solving shortest path problems. In Python, we can use `collections.deque` to implement the `queue` used in C++. + + +``` + 1 + / \ + 2 3 + / +4 +``` + +It’s important to note that both DFS and BFS can solve `reachability` problems, such as determining if one node is reachable from another. Many people prefer DFS for such problems because it can be quickly implemented using recursion. However, in practical software engineering, recursive implementations are rarely used because they are harder to understand and may cause stack overflow. Since iterative DFS (using a stack) and BFS (using a queue) have similar implementations, the choice between them depends on the specific requirements of the task. Additionally, if custom traversal priorities are needed, we can use priority queues, which will be discussed in the data structures section. + + +## [1091. Shortest Path in Binary Matrix](https://leetcode.com/problems/shortest-path-in-binary-matrix/) + +### Problem Description + +Given a 2D binary matrix where `1` represents obstacles and `0` represents open paths, each position is connected to its eight neighbors. Find the shortest path from the top-left corner to the bottom-right corner. If there is no valid path, return `-1`. + +### Input and Output Example + +Input is a 2D integer array, and the output is an integer representing the shortest distance. + +``` +Input: +[[0,0,1], + [1,1,0], + [1,1,0]] +Output: 4 +``` + +The shortest path is to move right first, then turn and move downward. + +### Solution Explanation + +Using a queue, we can intuitively apply Breadth-First Search (BFS) to determine the minimum number of layers to expand, i.e., the shortest path to the destination. Be careful not to revisit previously searched positions. + + + + + +```cpp +int shortestPathBinaryMatrix(vector>& grid) { + if (grid[0][0] == 1) { + return -1; + } + int m = grid.size(), n = grid[0].size(); + int dist = 0, count; + queue> q; + q.push({0, 0}); + grid[0][0] = -1; // -1 indicates visited + count = q.size(); + while (count > 0) { + ++dist; + while (count--) { + auto [r, c] = q.front(); + q.pop(); + if (r == m - 1 && c == n - 1) { + return dist; + } + for (int dx = -1; dx <= 1; ++dx) { + for (int dy = -1; dy <= 1; ++dy) { + if (dx == 0 && dy == 0) { + continue; + } + int x = r + dx, y = c + dy; + if (x < 0 || y < 0 || x >= m || y >= n || grid[x][y] != 0) { + continue; + } + grid[x][y] = -1; + q.push({x, y}); + } + } + } + count = q.size(); + } + return -1; +} +``` + + + + +```py +def shortestPathBinaryMatrix(grid: List[List[int]]) -> int: + if grid[0][0] == 1: + return -1 + m, n = len(grid), len(grid[0]) + dist = 0 + q = collections.deque() + q.append((0, 0)) + grid[0][0] = -1 # -1表示visited + count = len(q) + while count > 0: + dist += 1 + while count > 0: + count -= 1 + r, c = q.popleft() + if r == m - 1 and c == n - 1: + return dist + for dx in range(-1, 2): + for dy in range(-1, 2): + if dx == 0 and dy == 0: + continue + x, y = r + dx, c + dy + if x < 0 or y < 0 or x >= m or y >= n or grid[x][y] != 0: + continue + grid[x][y] = -1 + q.append((x, y)) + count = len(q) + return -1 +``` + + + + + +## [934. Shortest Bridge](https://leetcode.com/problems/shortest-bridge/) + +### Problem Description + +Given a 2D binary grid where `1` represents land and `0` represents water, each position is connected to its four neighbors. There are exactly two islands in the grid. Find the minimum number of water cells to convert into land to connect the two islands. + +### Input and Output Example + +Input is a 2D integer grid, and the output is a non-negative integer representing the number of water cells to fill. + +``` +Input: +[[1,1,1,1,1], + [1,0,0,0,1], + [1,0,1,0,1], + [1,0,0,0,1], + [1,1,1,1,1]] +Output: 1 +``` + +### Solution Explanation + +This problem can be solved by finding the shortest distance between the two islands. First, identify one of the islands using any search method, then use Breadth-First Search (BFS) to find the shortest distance to the other island. Below is the implementation using Depth-First Search (DFS) to find the first island. + + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// Auxiliary function + +void dfs(queue>& points, vector>& grid, int i, + int j) { + int m = grid.size(), n = grid[0].size(); + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 2) { + return; + } + if (grid[i][j] == 0) { + points.push({i, j}); + return; + } + grid[i][j] = 2; + for (int k = 0; k < 4; ++k) { + dfs(points, grid, i + direction[k], j + direction[k + 1]); + } +} + +// Main function +int shortestBridge(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + queue> points; + // DFS to find the first island, and change all 1s to 2 + bool flipped = false; + for (int i = 0; i < m && !flipped; ++i) { + for (int j = 0; j < n && !flipped; ++j) { + if (grid[i][j] == 1) { + dfs(points, grid, i, j); + flipped = true; + } + } + } + // BFS to find the second island, and change all 0s encountered to 2 + int level = 0; + while (!points.empty()) { + ++level; + int n_points = points.size(); + while (n_points--) { + auto [r, c] = points.front(); + points.pop(); + grid[r][c] = 2; + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + if (grid[x][y] == 2) { + continue; + } + if (grid[x][y] == 1) { + return level; + } + grid[x][y] = 2; + points.push({x, y}); + } + } + } + } + return 0; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# Auxiliary function +def dfs(points: Deque[Tuple[int, int]], grid: List[List[int]], i: int, j: int): + m, n = len(grid), len(grid[0]) + if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 2: + return + if grid[i][j] == 0: + points.append((i, j)) + return + grid[i][j] = 2 + for k in range(4): + dfs(points, grid, i + direction[k], j + direction[k + 1]) + +def shortestBridge(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + points = collections.deque() + # DFS to find the first island, and change all 1s to 2 + flipped = False + for i in range(m): + if flipped: + break + for j in range(n): + if grid[i][j] == 1: + dfs(points, grid, i, j) + flipped = True + break + # BFS to find the second island, and change all 0s encountered to 2 + level = 0 + while len(points) > 0: + level += 1 + points_at_current_level = len(points) + for _ in range(points_at_current_level): + r, c = points.popleft() + grid[r][c] = 2 + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + if x >= 0 and x < m and y >= 0 and y < n: + if grid[x][y] == 2: + continue + if grid[x][y] == 1: + return level + grid[x][y] = 2 + points.append((x, y)) + return level +``` + + + + + +## [126. Word Ladder II](https://leetcode.com/problems/word-ladder-ii/) + +### Problem Description + +Given a start string, an end string, and a word list, determine if you can transform the start string into the end string by changing one character at a time, where every intermediate string must exist in the word list. If possible, output all transformation sequences with the minimum number of changes. + +### Input and Output Example + +Input consists of two strings and a word list, and the output is a 2D string array representing all transformation sequences. + +``` +Input: beginWord = "hit", endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] +Output: +[["hit","hot","dot","dog","cog"], + ["hit","hot","lot","log","cog"]] +``` + +### Solution Explanation + +We can think of the start string, the end string, and all strings in the word list as nodes. If two strings differ by exactly one character, they are connected. Since the problem requires outputting all transformation sequences with the minimum number of changes, we can use breadth-first search (BFS) to compute the shortest path from the start node to the end node. + +We also use a small optimization: instead of performing BFS only from the start node until the end node is found, we perform BFS from both the start node and the end node simultaneously. Each time, we extend the smaller frontier to minimize the total number of nodes explored. For example, if the shortest distance is 4, performing BFS from one end would explore up to $1 + 2 + 4 + 8 + 16 = 31$ nodes, while performing BFS from both ends for two levels would explore only $2 × (1 + 2 + 4) = 14$ nodes. + +After completing the search, we use backtracking to reconstruct all possible paths. + +This problem is somewhat complex and requires careful thought and implementation. LeetCode's time constraints for this problem are very strict, so even the official solutions may sometimes time out. Multiple submissions may be necessary. + + + + + +```cpp +// Auxiliary function +void backtracking(const string &src, const string &dst, + unordered_map> &next_words, + vector &path, vector> &ladder) { + if (src == dst) { + ladder.push_back(path); + return; + } + if (!next_words.contains(src)) { + return; + } + for (const auto &w : next_words[src]) { + path.push_back(w); // Modify the current node state + backtracking(w, dst, next_words, path, ladder); // Recursively process child nodes + path.pop_back(); // Revert the current node state + } +} + +// Main function +vector> findLadders(string beginWord, string endWord, + vector &wordList) { + vector> ladder; + // Use a hash set to store the dictionary for quick lookups. + unordered_set word_dict; + for (const auto &w : wordList) { + word_dict.insert(w); + } + if (!word_dict.contains(endWord)) { + return ladder; + } + word_dict.erase(beginWord); + word_dict.erase(endWord); + // Create two queues for bidirectional BFS from beginWord and endWord, + // expanding the smaller queue each time. + unordered_set q_small{beginWord}, q_large{endWord}; + unordered_map> next_words; + bool reversed_path = false, found_path = false; + while (!q_small.empty()) { + unordered_set q; + for (const auto &w : q_small) { + string s = w; + for (int i = 0; i < s.size(); ++i) { + for (int j = 0; j < 26; ++j) { + s[i] = j + 'a'; + if (q_large.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + found_path = true; + } + if (word_dict.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + q.insert(s); + } + } + s[i] = w[i]; + } + } + if (found_path) { + break; + } + // Avoid revisiting nodes and infinite loops. + for (const auto &w : q) { + word_dict.erase(w); + } + // Update the two queues and maintain size relationship. + if (q.size() <= q_large.size()) { + q_small = q; + } else { + reversed_path = !reversed_path; + q_small = q_large; + q_large = q; + } + } + if (found_path) { + vector path{beginWord}; + backtracking(beginWord, endWord, next_words, path, ladder); + } + return ladder; +} +``` + + + + +```py +# Auxiliary function +def backtracking(src: str, dst: str, next_words: Dict[str, List[str]], + path: List[str], ladder: List[List[str]]): + if src == dst: + ladder.append(path[:]) + return + if src not in next_words: + return + for w in next_words[src]: + path.append(w) # Modify the current node state + backtracking(w, dst, next_words, path, ladder) # Recurse to child nodes + path.pop() # Revert the current node state + +# Main function +def findLadders(beginWord: str, endWord: str, + wordList: List[str]) -> List[List[str]]: + ladder = [] + # Use a hash set to store the dictionary for quick lookups. + word_dict = set(wordList) + if endWord not in word_dict: + return ladder + word_dict = word_dict.difference(set([beginWord, endWord])) + # Create two queues for bidirectional BFS from beginWord and endWord, + # expanding the smaller queue each time. + q_small, q_large = set([beginWord]), set([endWord]) + next_words = dict() + reversed_path, found_path = False, False + while len(q_small) > 0: + q = set() + for w in q_small: + for i in range(len(w)): + for j in range(26): + s = w[:i] + chr(ord("a") + j) + w[i + 1:] + if s in q_large: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + found_path = True + if s in word_dict: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + q.add(s) + if found_path: + break + # Avoid revisiting nodes and infinite loops. + word_dict = word_dict.difference(q) + # Update the two queues and maintain size relationships. + if len(q) <= len(q_large): + q_small = q + else: + reversed_path = not reversed_path + q_small = q_large + q_large = q + + if found_path: + path = [beginWord] + backtracking(beginWord, endWord, next_words, path, ladder) + return ladder +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md new file mode 100644 index 00000000..123840ec --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 25 +--- + +# 5.5 Exercises + +## Basic Difficulty + +### [130. Surrounded Regions](https://leetcode.com/problems/surrounded-regions/) + +Start by filling from the outer edges, then consider the inner regions. + +--- + +### [257. Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) + +Output all paths from the root to the leaves in a binary tree. What is the difference if backtracking is used? + +--- + +## Advanced Difficulty + +### [47. Permutations II](https://leetcode.com/problems/permutations-ii/) + +A follow-up to the permutations problem. How to handle duplicate elements? + +--- + +### [40. Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) + +A follow-up to the combination problem. How to handle duplicate elements? + +--- + +### [37. Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) + +A very classic Sudoku problem that can be solved using backtracking. In fact, there are many advanced search methods and pruning strategies, such as heuristic search, to improve speed for Sudoku-related problems. + +--- + +### [310. Minimum Height Trees](https://leetcode.com/problems/minimum-height-trees/) + +How can this problem be transformed into a search problem? Should depth-first search or breadth-first search be used? \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json new file mode 100644 index 00000000..8811fa48 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "5. Everything is Searchable", + "position": 5, + "link": { + "type": "generated-index", + "description": "Chapter 5: Everything is Searchable" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png new file mode 100644 index 00000000..f6ea0755 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md new file mode 100644 index 00000000..594591cd --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 26 +--- + +# 6.1 Algorithm Explanation + +Here, we quote Wikipedia’s description: "`Dynamic Programming` (DP) is effective in finding the optimal solution for problems with many `overlapping subproblems`. It redefines the problem into subproblems. To avoid repeatedly solving these subproblems, their results are progressively computed and stored, starting from simpler problems until the entire problem is resolved. Therefore, dynamic programming saves the results of recursion and avoids spending time solving the same problems repeatedly. Dynamic programming can only be applied to problems with an `optimal substructure`. The optimal substructure means that the local optimal solution can determine the global optimal solution (this requirement is not always completely met for some problems, so certain approximations may be introduced). Simply put, the problem can be broken down into subproblems to solve." + +In simple terms, dynamic programming differs from other traversal algorithms (e.g., depth-first search or breadth-first search) in that it `stores the solutions of subproblems to avoid redundant calculations`. The key to solving dynamic programming problems lies in finding the `state transition equation`, which allows us to solve the final problem by computing and storing the solutions to subproblems. + +Additionally, we can apply `space optimization` techniques to dynamic programming to reduce space usage. This technique will be introduced in subsequent problems. + +In some cases, dynamic programming can be considered a form of `memoized` traversal. Memoization means that if a subproblem has been solved during traversal, its result can be stored and reused later when the same subproblem is encountered again. Dynamic programming is bottom-up, solving subproblems first and then the parent problem. Memoized traversal is top-down, starting from the parent problem and solving subproblems as they are encountered. If the problem requires only the final state, dynamic programming is more convenient; if the problem requires all possible paths, memoized traversal is more suitable. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx new file mode 100644 index 00000000..cec2501d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx @@ -0,0 +1,252 @@ +--- +sidebar_position: 27 +--- + +# 6.2 Basic Dynamic Programming: One-Dimensional + +## [70. Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) + +### Problem Description + +Given $n$ steps of stairs, you can either take one step or two steps at a time. Determine how many ways there are to climb to the top. + + +### Input and Output Example + +Input is a single number representing the number of steps; output is the total number of ways to climb the stairs. + +``` +Input: 3 +Output: 3 +``` + +In this example, there are three ways to climb the three steps: +1. Take one step three times. +2. Take one step, then two steps. +3. Take two steps, then one step. + +### Solution Explanation + +This is a classic Fibonacci sequence problem. Define an array `dp` where `dp[i]` represents the number of ways to reach the $i^{th}$ step. Since you can either take one step or two steps, the $i^{th}$ step can be reached from the $(i-1)^{th}$ or the $(i-2)^{th}$ step. In other words, the number of ways to reach the $i^{th}$ step is the sum of the ways to reach the $(i-1)^{th}$ and $(i-2)^{th}$ steps. This gives us the state transition equation: `dp[i] = dp[i-1] + dp[i-2]`. Pay attention to the initial conditions. + + +:::warning + +To handle boundary cases conveniently, we can reserve an extra position in the `dp` array to represent the initial state. In this problem, an extra initial position for step 0 is added. + +::: + + + + +```cpp +int climbStairs(int n) { + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + dp = [1] * (n + 1) + for i in range(2, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + return dp[n] +``` + + + + + +Furthermore, we can apply space optimization to dynamic programming. Since dp[i] only depends on dp[i-1] and dp[i-2], we can use just two variables to store dp[i-1] and dp[i-2], reducing the original $O(n)$ space complexity to $O(1)$. + + + + + +```cpp +int climbStairs(int n) { + int prev_prev = 1, prev = 1, cur = 1; + for (int i = 2; i <= n; ++i) { + cur = prev_prev + prev; + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + prev_prev = prev = cur = 1 + for _ in range(2, n + 1): + cur = prev_prev + prev + prev_prev = prev + prev = cur + return cur +``` + + + + + + +## [198. House Robber](https://leetcode.com/problems/house-robber/) + +### Problem Description + +Suppose you are a robber deciding to rob houses along a street, where each house has a different amount of money. If you rob two adjacent houses, an alarm will be triggered. Determine the maximum amount of money you can rob without triggering the alarm. + +### Input and Output Example + +The input is a one-dimensional array `nums` representing the amount of money in each house; the output is the maximum amount of money the robber can steal. + +``` +Input: [2,7,9,3,1] +Output: 12 +``` + +In this example, the optimal way to rob is to rob houses 1, 3, and 5. + +### Solution Explanation + +Define an array `dp`, where `dp[i]` represents the maximum amount of money that can be robbed up to the `i`-th house. To determine the value of `dp[i]`, there are two possible scenarios: + +1. **Do not rob this house**: In this case, the accumulated amount is `dp[i-1]`. +2. **Rob this house**: The previously accumulated maximum amount can only be `dp[i-2]`, because robbing the `i-1`-th house would trigger the alarm. + +Thus, the state transition equation for this problem is: + +$$ +dp[i] = \max(dp[i-1], dp[i-2] + \text{nums}[i-1]) +$$ + + + + +```cpp +int rob(vector& nums) { + int n = nums.size(); + vector dp(n + 1, 0); + dp[1] = nums[0]; + for (int i = 2; i <= n; ++i) { + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]); + } + return dp[n]; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + n = len(nums) + dp = [0] * (n + 1) + dp[1] = nums[0] + for i in range(2, n + 1): + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]) + return dp[n] +``` + + + + + +Similarly, we can optimize space complexity just like in Problem 70. Since `dp[i]` only depends on `dp[i-1]` and `dp[i-2]`, we can use only two variables to store these two values, reducing the original $O(n)$ space complexity to $O(1)$ space complexity. + + + + +```cpp +int rob(vector& nums) { + int prev_prev = 0, prev = 0, cur = 0; + for (int i = 0; i < nums.size(); ++i) { + cur = max(prev_prev + nums[i], prev); + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + prev_prev = prev = cur = 0 + for i in range(len(nums)): + cur = max(prev_prev + nums[i], prev) + prev_prev = prev + prev = cur + return cur +``` + + + + + +## [413. Arithmetic Slices](https://leetcode.com/problems/arithmetic-slices/) + +### Problem Description + +Given an array, calculate the total number of continuous arithmetic subarrays. + +### Input and Output Example + +Input is a one-dimensional array, and output is the number of continuous subarrays that meet the arithmetic condition. + +``` +Input: nums = [1,2,3,4] +Output: 3 +``` + +In this example, the arithmetic subarrays are [1,2,3], [2,3,4], and [1,2,3,4]. + +### Solution Explanation + +Since the requirement is for arithmetic subarrays, it naturally follows that the subarray must satisfy the condition `num[i] - num[i-1] = num[i-1] - num[i-2]`. Here, we define the `dp` array such that `dp[i]` represents the number of subarrays ending at index `i` that satisfy this condition. Because arithmetic subarrays can end at any position, we need to sum up the `dp` array to calculate the total number of subarrays. + + + + + +```cpp +int numberOfArithmeticSlices(vector& nums) { + int n = nums.size(); + vector dp(n, 0); + for (int i = 2; i < n; ++i) { + if (nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]) { + dp[i] = dp[i - 1] + 1; + } + } + return accumulate(dp.begin(), dp.end(), 0); +} +``` + + + + +```py +def numberOfArithmeticSlices(nums: List[int]) -> int: + n = len(nums) + dp = [0] * n + for i in range(2, n): + if nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]: + dp[i] = dp[i - 1] + 1 + return sum(dp) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx new file mode 100644 index 00000000..b0024076 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx @@ -0,0 +1,307 @@ +--- +sidebar_position: 28 +--- + +# 6.3 Basic Dynamic Programming: Two-Dimensional + +## [64. Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/) + +### Problem Description + +Given an $m × n$ non-negative integer matrix, find the path from the top-left to the bottom-right corner with the smallest sum of numbers. You can only move right or down. + +### Input and Output Example + +Input is a two-dimensional array, and output is the sum of the numbers along the optimal path. + +``` +Input: +[[1,3,1], + [1,5,1], + [4,2,1]] +Output: 7 +``` + +In this example, the shortest path is 1->3->1->1->1. + +### Solution Explanation + +We can define a `dp` array of the same dimensions, where `dp[i][j]` represents the sum of numbers along the optimal path from the top-left corner to position `(i, j)`. Since you can only move down or right, the state transition equation is `dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])`, where `grid` represents the original matrix. + + +:::warning + +In Python, initializing multi-dimensional arrays requires caution. Direct initialization using `[[val] * n] * m` creates `m` references to the same `[[val] * n]` object. The correct initialization method is `[[val for _ in range(n)] for _ in range(m)]`. + +::: + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector> dp(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[i][j] = grid[i][j]; + } else if (i == 0) { + dp[i][j] = grid[i][j] + dp[i][j - 1]; + } else if (j == 0) { + dp[i][j] = grid[i][j] + dp[i - 1][j]; + } else { + dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m - 1][n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [[0 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[i][j] = grid[i][j] + elif i == 0: + dp[i][j] = grid[i][j] + dp[i][j - 1] + elif j == 0: + dp[i][j] = grid[i][j] + dp[i - 1][j] + else: + dp[i][j] = grid[i][j] + min(dp[i][j - 1], dp[i - 1][j]) + return dp[m - 1][n - 1] +``` + + + + + +Since each value in the `dp` matrix depends only on the values to its left and above, we can apply space optimization to reduce the `dp` array to one dimension. For the `i-th` row, when iterating to the `j-th` column, since the `j-1-th` column has already been updated, `dp[j-1]` represents the value of `dp[i][j-1]`. Meanwhile, `dp[j]` is yet to be updated, and the current stored value represents the value of `dp[i-1][j]` from the previous row. + +:::warning + +If you are not very familiar with space optimization techniques, it is recommended to first write a solution without space optimization. Apply space optimization only if time permits and you are comfortable with the approach. + +::: + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector dp(n, 0); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[j] = grid[i][j]; + } else if (i == 0) { + dp[j] = grid[i][j] + dp[j - 1]; + } else if (j == 0) { + dp[j] = grid[i][j] + dp[j]; + } else { + dp[j] = grid[i][j] + min(dp[j], dp[j - 1]); + } + } + } + return dp[n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [0 for _ in range(n)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[j] = grid[i][j] + elif i == 0: + dp[j] = grid[i][j] + dp[j - 1] + elif j == 0: + dp[j] = grid[i][j] + dp[j] + else: + dp[j] = grid[i][j] + min(dp[j - 1], dp[j]) + return dp[n - 1] +``` + + + + + + +## [542. 01 Matrix](https://leetcode.com/problems/01-matrix/) + +### Problem Description + +Given a 2D matrix consisting of 0s and 1s, find the distance of each position to the nearest 0. + +### Input and Output Example + +The input is a 2D 0-1 array, and the output is a 2D non-negative integer array of the same size, representing the distance of each position to the nearest 0. + +``` +Input: +[[0,0,0], + [0,1,0], + [1,1,1]] + +Output: +[[0,0,0], + [0,1,0], + [1,2,1]] +``` + +### Solution Explanation + +Typically, as this problem involves finding the nearest position in four directions, many people might initially consider breadth-first search (BFS). However, for a 2D array of size $O(mn)$, performing four-directional BFS for each position results in a worst-case time complexity of $O(m^2n^2)$ (when all entries are 1). + +One approach is to use a 2D boolean array for memoization, ensuring that BFS does not revisit the same position. A simpler approach, however, is to perform a dynamic search from the top-left to the bottom-right, followed by another dynamic search from the bottom-right to the top-left. These two searches efficiently account for all four directions. + + + + + +```cpp +vector> updateMatrix(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + vector> dp(m, vector(n, numeric_limits::max() - 1)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (matrix[i][j] != 0) { + if (i > 0) { + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + } + if (j > 0) { + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } else { + dp[i][j] = 0; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (matrix[i][j] != 0) { + if (i < m - 1) { + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1); + } + if (j < n - 1) { + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1); + } + } + } + } + return dp; +} +``` + + + + +```py +def updateMatrix(matrix: List[List[int]]) -> List[List[int]]: + m, n = len(matrix), len(matrix[0]) + dp = [[sys.maxsize - 1 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if matrix[i][j] != 0: + if i > 0: + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1) + if j > 0: + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1) + else: + dp[i][j] = 0 + for i in range(m - 1, -1, -1): # m-1 to 0, reversed + for j in range(n - 1, -1, -1): # n-1 to 0, reversed + if matrix[i][j] != 0: + if i < m - 1: + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1) + if j < n - 1: + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1) + return dp +``` + + + + + +## [221. Maximal Square](https://leetcode.com/problems/maximal-square/) + +### Problem Description + +Given a 2D binary matrix filled with 0s and 1s, find the largest square containing only 1s and return its area. + +### Input and Output Example + +The input is a 2D binary matrix, and the output is the area of the largest square. + +``` +Input: +[["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"]] +Output: 4 +``` + +### Solution Explanation + +For problems involving finding squares or rectangles in a matrix, a common approach is to define a 2D dp array, where dp[i][j] represents the attribute of the square or rectangle that meets the problem's requirements with (i, j) as the bottom-right corner. In this problem, dp[i][j] represents the side length of the largest square containing only 1s with (i, j) as the bottom-right corner. If the current position is 0, then dp[i][j] = 0. If the current position is 1, assuming dp[i][j] = k, the necessary condition is that dp[i-1][j-1], dp[i][j-1], and dp[i-1][j] must all be at least k − 1; otherwise, (i, j) cannot form a square of area $k^2$. Conversely, if the minimum of these three values is k − 1, then (i, j) can and will form a square of area $k^2$. + + +
+ + ![](6.1.png) + +
Figure 6.1: Problem 221 - The left shows a 0-1 matrix, and the right shows its corresponding dp matrix. The largest square has a side length of 3
+
+ + + + +```cpp +int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + int max_side = 0; + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (matrix[i - 1][j - 1] == ’1’) { + dp[i][j] = + min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1; + } + max_side = max(max_side, dp[i][j]); + } + } + return max_side * max_side; +} +``` + + + + +```py +def maximalSquare(matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1 + return max(max(row) for row in dp) ** 2 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx new file mode 100644 index 00000000..934c6ba1 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx @@ -0,0 +1,350 @@ +--- +sidebar_position: 29 +--- + +# 6.4 Partition Type Problems + +## [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) + +### Problem Description + +Given a positive integer, find the minimum number of perfect square numbers that sum up to the given number. + +### Input and Output Example + +The input is a given positive integer, and the output is also a positive integer, representing the minimum number of perfect square numbers that sum up to the input number. + +``` +Input: n = 13 +Output: 2 +``` + +In this example, the minimal representation of 13 is 4 + 9. + +### Solution Explanation + +For partition-type problems, the dynamic programming state transition equation usually does not depend on adjacent positions but on positions that satisfy the partition condition. We define a 1D array `dp`, where `dp[i]` represents the minimum number of perfect square numbers that sum up to `i`. In this problem, position `i` only depends on positions like $i - j^2$, such as `i - 1`, `i - 4`, `i - 9`, and so on, to meet the perfect square partition condition. Therefore, `dp[i]` can take the minimum value as $1 + \min(dp[i-1], dp[i-4], dp[i-9] · · · )$. Note the handling of boundary conditions. + + + + + +```cpp +int numSquares(int n) { + vector dp(n + 1, numeric_limits::max()); + dp[0] = 0; + for (int i = 1; i <= n; ++i) { + for (int j = 1; j * j <= i; ++j) { + dp[i] = min(dp[i], dp[i - j * j] + 1); + } + } + return dp[n]; +} +``` + + + + +```py +def numSquares(n: int) -> int: + dp = [0] + [sys.maxsize] * n + for i in range(1, n + 1): + for j in range(1, int(floor(sqrt(i))) + 1): + dp[i] = min(dp[i], dp[i - j * j] + 1) + return dp[n] +``` + + + + + +## [91. Decode Ways](https://leetcode.com/problems/decode-ways/) + +### Problem Description + +Given that letters A-Z can be represented as numbers 1-26, find the number of ways a given numeric string can be decoded into valid strings. + +### Input and Output Example + +The input is a numeric string, and the output is the total number of decoding ways that satisfy the conditions. + +``` +Input: "226" +Output: 3 +``` + +In this example, there are three decoding ways: BZ(2 26), VF(22 6), or BBF(2 2 6). + +### Solution Explanation + +This is a classic dynamic programming problem. While not difficult, it requires careful handling of edge cases. Only numbers 1-26 can represent letters, so special conditions such as `0` or adjacent numbers greater than 26 require different state transition formulas, as shown in the code below. + + + + +```cpp +int numDecodings(string s) { + int n = s.length(); + int prev = s[0] - '0'; + if (prev == 0) { + return 0; + } + if (n == 1) { + return 1; + } + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + int cur = s[i - 1] - '0'; + if ((prev == 0 || prev > 2) && cur == 0) { + // 00, 30, 40, ..., 90 are invalid combinations. + return 0; + } + if ((prev < 2 && prev > 0) || (prev == 2 && cur <= 6)) { + // 10, 11, ..., 25, 26. + if (cur == 0) { + // 10, 20 can only be decoded as two-digit numbers. + dp[i] = dp[i - 2]; + } else { + // Can be decoded as a single-digit or two-digit number. + dp[i] = dp[i - 2] + dp[i - 1]; + } + } else { + // Valid, but can only be decoded as a single-digit number. + dp[i] = dp[i - 1]; + } + prev = cur; + } + return dp[n]; +} +``` + + + + +```py +def numDecodings(s: str) -> int: + n = len(s) + prev = ord(s[0]) - ord("0") + if prev == 0: + return 0 + if n == 1: + return 1 + dp = [1] * (n + 1) + for i in range(2, n + 1): + cur = ord(s[i - 1]) - ord("0") + if (prev == 0 or prev > 2) and cur == 0: + # 00, 30, 40, ..., 90 are invalid combinations. + return 0 + if 0 < prev < 2 or (prev == 2 and cur <= 6): + # 10, 11, ..., 25, 26. + if cur == 0: + # 10, 20 can only be decoded as two-digit numbers. + dp[i] = dp[i - 2] + else: + # Can be decoded as a single-digit or two-digit number. + dp[i] = dp[i - 2] + dp[i - 1] + else: + # Valid, but can only be decoded as a single-digit number. + dp[i] = dp[i - 1] + prev = cur + return dp[n] +``` + + + + + +## [139. Word Break](https://leetcode.com/problems/word-break/) + +### Problem Description + +Given a string and a set of strings, determine if there is a way to split the string such that every substring after splitting can be found in the set. + +### Input and Output Example + +``` +Input: s = "applepenapple", wordDict = ["apple", "pen"] +Output: true +``` + +In this example, the string can be split into [“apple”,“pen”,“apple”]. + +### Solution Explanation + +Similar to the problem of splitting into perfect squares, the splitting condition in this problem is determined by the strings in the set. When considering each splitting position, we need to iterate through the set of strings to check if the current position can be successfully split. Note that for position 0, the value needs to be initialized to true. + + + + +```cpp +bool wordBreak(string s, vector& wordDict) { + int n = s.length(); + vector dp(n + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (const string& word : wordDict) { + int m = word.length(); + if (i >= m && s.substr(i - m, m) == word) { + dp[i] = dp[i - m]; + } + // Early pruning to slightly speed up. + // Without pruning, the above line should be dp[i] = dp[i] || dp[i - m]; + if (dp[i]) { + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def wordBreak(s: str, wordDict: List[str]) -> bool: + n = len(s) + dp = [True] + [False] * n + for i in range(1, n + 1): + for word in wordDict: + m = len(word) + if i >= m and s[i - m : i] == word: + dp[i] = dp[i - m] + # Early pruning to slightly speed up. + # Without pruning, the above line should be dp[i] = dp[i] or dp[i-m] + if dp[i]: + break + return dp[n] +``` + + + + + +## [1105. Filling Bookcase Shelves](https://leetcode.com/problems/filling-bookcase-shelves/) + +### Problem Description + +Given an array, where each element represents the width and height of a book, determine the minimum total height of a bookshelf with fixed width, where books are placed in the given order from left to right and top to bottom. + +### Input and Output Example + + +``` +Input: books = [[1,1],[2,3],[2,3],[1,1],[1,1],[1,1],[1,2]], shelfWidth = 4 +Output: 6 +``` + + +
+ + ![](https://assets.leetcode.com/uploads/2019/06/24/shelves.png) + +
Figure 6.2: Bookcase Arrangement Problem - Example Illustration
+
+ +### Solution Explanation + +Let dp[i] represent the minimum total height when placing the i-th book. dp[i] can either represent placing the i-th book on a new row or on the previous row, provided the row width constraint is satisfied. + + + + +```cpp +int minHeightShelves(vector>& books, int shelfWidth) { + int n = books.size(); + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) { + int w = books[i - 1][0], h = books[i - 1][1]; + dp[i] = dp[i - 1] + h; + for (int j = i - 1; j > 0; --j) { + int prev_w = books[j - 1][0], prev_h = books[j - 1][1]; + w += prev_w; + if (w > shelfWidth) { + break; + } + h = max(h, prev_h); + dp[i] = min(dp[i], dp[j - 1] + h); + } + } + return dp[n]; +} +``` + + + + +```py +def minHeightShelves(books: List[List[int]], shelfWidth: int) -> int: + n = len(books) + dp = [0] * (n + 1) + for i, (w, h) in enumerate(books, 1): + dp[i] = dp[i - 1] + h + for j in range(i - 1, 0, -1): + prev_w, prev_h = books[j - 1] + w += prev_w + if w > shelfWidth: + break + h = max(h, prev_h) + dp[i] = min(dp[i], dp[j - 1] + h) + return dp[n] +``` + + + + + +## [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) + +### Problem Description + +Given an array of unique numbers and a target number, find the total number of permutations that sum up to the target. (Although the problem is named "Combination Sum," different orderings of the same combination are considered distinct, so this is essentially a permutation problem.) + + +### Input and Output Example + +``` +Input: nums = [1,2,3], target = 4 +Output: 7 +``` + +The seven different permutations are (1, 1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 3), (2, 1, 1), (2, 2), and (3, 1). + + +### Solution Explanation + +Let dp[i] represent the number of permutations that sum up to i. In the inner loop, we directly consider all valid numbers from the array. Note that in the C++ solution, since summing can easily exceed the `int` limit, we use `double` to store the dp array. + + + + + +```cpp +int combinationSum4(vector& nums, int target) { + vector dp(target + 1, 0); + dp[0] = 1; + for (int i = 1; i <= target; ++i) { + for (int num : nums) { + if (num <= i) { + dp[i] += dp[i - num]; + } + } + } + return dp[target]; +} +``` + + + + +```py +def combinationSum4(nums: List[int], target: int) -> int: + dp = [1] + [0] * target + for i in range(1, target + 1): + dp[i] = sum(dp[i - num] for num in nums if i >= num) + return dp[target] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx new file mode 100644 index 00000000..d12f1592 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx @@ -0,0 +1,190 @@ +--- +sidebar_position: 30 +--- + +# 6.5 Subsequence Problem + +## [300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) + +### Problem Description + +Given an unsorted array of integers, find the length of the longest increasing subsequence. + +:::warning + +According to LeetCode conventions, a subsequence does not need to be contiguous, while a subarray or substring must be contiguous. + +::: + +### Input and Output Example + +Input is a 1D array, and output is a positive integer representing the length of the longest increasing subsequence. + +``` +Input: [10,9,2,5,3,7,101,4] +Output: 4 +``` + +In this example, one of the longest increasing subsequences is [2,3,7,101]. + +### Solution Explanation + +For subsequence problems, a common dynamic programming approach is to define a dp array where dp[i] represents the property of a subsequence ending at index i. After processing each position, summing up the results of all positions will yield the required result. + +In this problem, dp[i] represents the length of the longest subsequence ending at index i. For each position i, if a previous position j has a smaller value than nums[i], we can form a subsequence of length dp[j] + 1 ending at i. To check all possibilities, we use a nested loop with i and j, resulting in a time complexity of $O(n^2)$. + + + + +```cpp +int lengthOfLIS(vector& nums) { + int max_len = 0, n = nums.size(); + vector dp(n, 1); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + if (nums[i] > nums[j]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + max_len = max(max_len, dp[i]); + } + return max_len; +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + n = len(nums) + dp = [1] * n + for i in range(n): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) +``` + + + + + +This problem can also be solved using binary search to reduce the time complexity to $O(n \log n)$. We define a `dp` array where `dp[k]` stores the last number of the longest increasing subsequence of length `k+1`. As we iterate through each position `i`, if the number is larger than all numbers in the `dp` array, we append it to the end of `dp`, indicating that the length of the longest increasing subsequence has increased by 1. If the number lies between two numbers `a` and `b` in the `dp` array, we replace `b` with this number to increase the possibility of forming a longer increasing subsequence. Using this method, the `dp` array is always maintained in increasing order, allowing us to use binary search to speed up the process. + + +For example, for the array [10,9,2,5,3,7,101,4], the updates in each round are as follows: + +``` +num dp +10 [10] +9 [9] +2 [2] +5 [2,5] +3 [2,3] +7 [2,3,7] +101 [2,3,7,101] +4 [2,3,4,101] +``` + +Finally, we determine that the length of the longest increasing subsequence is 4. Note that the final form of the `dp` array does not necessarily represent a valid subsequence, e.g., [2,3,4,101] is not a subsequence, but the previously updated [2,3,7,101] is one of the optimal solutions. + +Similarly, for other problems, if the results of the state transition equation are increasing or decreasing and require insertion or search operations, we can also use binary search to speed up the solution. + + + + +```cpp +int lengthOfLIS(vector& nums) { + vector dp{nums[0]}; + for (int num : nums) { + if (dp.back() < num) { + dp.push_back(num); + } else { + *lower_bound(dp.begin(), dp.end(), num) = num; + } + } + return dp.size(); +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + dp = [nums[0]] + for num in nums: + if dp[-1] < num: + dp.append(num) + else: + dp[bisect.bisect_left(dp, num, 0, len(dp))] = num + return len(dp) +``` + + + + + +## [1143. Longest Commom Subsequence](https://leetcode.com/problems/longest-common-subsequence/) + +### Problem Description + +Given two strings, find the length of their longest common subsequence. + +### Input and Output Example + +Input consists of two strings, and the output is an integer representing the length of their longest common subsequence. + +``` +Input: text1 = "abcde", text2 = "ace" +Output: 3 +``` + +In this example, the longest common subsequence is "ace." + +### Solution Explanation + +For subsequence problems, the second dynamic programming approach defines a dp array where dp[i] represents the property of the subsequence up to position i, without requiring it to end at i. The final result is the last value of the dp array, eliminating the need to compute each position. + +In this problem, we use a 2D array dp, where dp[i][j] represents the length of the longest common subsequence up to position i in the first string and position j in the second string. This makes it straightforward to handle the cases where the letters at these positions are the same or different. + + + + +```cpp +int longestCommonSubsequence(string text1, string text2) { + int m = text1.length(), n = text2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (text1[i - 1] == text2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def longestCommonSubsequence(text1: str, text2: str) -> int: + m, n = len(text1), len(text2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if text1[i - 1] == text2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + return dp[m][n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx new file mode 100644 index 00000000..0a12b00b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx @@ -0,0 +1,422 @@ +--- +sidebar_position: 31 +--- + +# 6.6 Knapsack Problem + +The `knapsack problem` is a combinatorial optimization NP-complete problem: given n items and a knapsack with weight capacity w, where each item has a weight and a value, determine which items to include in the knapsack to maximize the total value. If each item can only be chosen 0 or 1 time, the problem is called the `0-1 knapsack problem`; if there is no limit to the number of items chosen, it is called the `unbounded knapsack problem`. + +We can solve the knapsack problem using dynamic programming. Taking the 0-1 knapsack problem as an example, we define a 2D array `dp` to store the maximum value, where `dp[i][j]` represents the maximum value achievable with the first i items and a knapsack weight limit of j. When processing the i-th item, if we do not include item i in the knapsack, then `dp[i][j] = dp[i-1][j]`, which means the maximum value equals that of the first i-1 items. If we include item i, with weight `weight` and value `value`, then `dp[i][j] = dp[i-1][j-weight] + value`. We take the maximum of these two options during iteration, resulting in a time complexity and space complexity of $O(nw)$. + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +
+ + ![](6.3.png) + +
Figure 6.3: 0-1 Knapsack Problem - State Transition Matrix Example
+
+ +We can further optimize the space complexity of the 0-1 knapsack problem to $O(w)$. As shown in the figure, assume we are currently considering item $i = 2$, with a weight of $weight = 2$ and a value of $value = 3$. For a knapsack capacity of $j$, we have $dp[2][j] = max(dp[1][j], dp[1][j-2] + 3)$. Here, we observe that we always depend only on the information from the previous row $i = 1$, and the results of other items computed earlier are no longer needed. Therefore, we can remove the first dimension of the $dp$ matrix, reducing it to $dp[j] = max(dp[j], dp[j-weight] + value)$ when considering item $i$. It's important to note that we must **traverse in reverse order** for each row. This ensures that the value of $dp[j-weight]$ from the previous row (item $i-1$) is correctly accessed. If traversed in the forward direction (left to right), $dp[j-weight]$ would already be updated to the value of item $i$ before reaching $j$. + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = w; j >= weight; --j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(w, weight - 1, -1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +In the unbounded knapsack problem, an item can be chosen multiple times. As shown in the top part of the figure, assume we are processing item $i = 2$, with a weight of $weight = 2$ and a value of $value = 3$. For a knapsack capacity of $j = 5$, we can fit at most 2 of this item. Thus, our state transition equation becomes $dp[2][5] = max(dp[1][5], dp[1][3] + 3, dp[1][1] + 6)$. If we use this approach and assume infinite knapsack capacity with infinitely small item weight, the number of comparisons would approach infinity, far exceeding the time complexity of $O(nw)$. + +
+ + ![](6.4.png) + +
Figure 6.4: Unbounded Knapsack Problem - State Transition Matrix Example
+
+ +How do we solve this issue? We observe that at $dp[2][3]$, we have already accounted for $dp[1][3]$ and $dp[2][1]$, and at $dp[2][1]$, we have already considered $dp[1][1]$. Therefore, as shown in the bottom part of the figure, for cases involving multiple items, we only need to consider $dp[2][3]$, i.e., $dp[2][5] = max(dp[1][5], dp[2][3] + 3)$. This gives us the state transition equation for the unbounded knapsack problem: $dp[i][j] = max(dp[i-1][j], dp[i][j-w] + v)$, which differs from the 0-1 knapsack problem only in that the second $i-1$ in the state transition equation is replaced by $i$. + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +Similarly, we can use space optimization to reduce the time complexity to $O(w)$. It is important to note that during each row traversal, we must perform a `forward traversal`, as we need to use the information of the current item at column $j-weight$. + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = weight; j <= w; ++j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(weight, w + 1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +:::warning + +When compressing space, should we use `forward` or `backward` traversal? Should items or weights be placed in the outer loop? This depends on the dependency relationships in the state transition equation. Before considering space compression, it is helpful to draw the state transition matrix to better understand how to compress space and which dimension to compress for optimal efficiency. + +::: + +## [416. Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/) + +### Problem Description + +Given a positive integer array, determine whether it can be partitioned into two subsets with equal sums. + +### Input and Output Example + +The input is a one-dimensional positive integer array, and the output is a boolean value indicating whether the array can be partitioned as required. + +``` +Input: [1,5,11,5] +Output: true +``` + +In this example, the array can be partitioned into [1,5,5] and [11]. + +### Solution Explanation + +This problem is equivalent to the 0-1 knapsack problem. Given the total sum of all numbers, `sum`, the goal is to find a subset of numbers whose total equals `sum / 2`. Since there is no need to consider values, a boolean matrix can be used to represent the state transition matrix. Pay attention to the handling of boundary conditions. + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector> dp(n + 1, vector(target + 1, false)); + dp[0][0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j <= target; ++j) { + if (j < nums[i - 1]) { + dp[i][j] = dp[i - 1][j]; + } else { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; + } + } + } + return dp[n][target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [[False for _ in range(target + 1)] for _ in range(n + 1)] + dp[0][0] = True + for i in range(1, n + 1): + for j in range(target + 1): + if j < nums[i - 1]: + dp[i][j] = dp[i - 1][j] + else: + dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]] + return dp[n][target] +``` + + + + + +Similarly, we can perform space compression for this problem. Note that the traversal of the sum of numbers needs to be in reverse order. + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector dp(target + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = target; j >= nums[i - 1]; --j) { + dp[j] = dp[j] || dp[j - nums[i - 1]]; + } + } + return dp[target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [True] + [False] * target + for i in range(1, n + 1): + for j in range(target, nums[i - 1] - 1, -1): + dp[j] = dp[j] or dp[j - nums[i - 1]] + return dp[target] +``` + + + + + +## [474. Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes/) + +### Problem Description + +Given $m$ zeros and $n$ ones, and an array of binary strings, determine the maximum number of given strings that can be formed using these zeros and ones, with each string being used at most once. + +### Input and Output Example + +Input consists of two integers $m$ and $n$, representing the count of zeros and ones respectively, along with a one-dimensional array of strings representing the strings to form; +Output is an integer representing the maximum number of strings that can be formed. + +``` +Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 +Output: 4 +``` + +In this example, we can use 5 zeros and 3 ones to form [“10”, “0001”, “1”, “0”]. + +### Solution Explanation + +This is a multidimensional 0-1 knapsack problem, where there are two constraints: the number of zeros and the number of ones. Below is the implementation of compressing the three-dimensional solution into a two-dimensional space. + + + + +```cpp +int findMaxForm(vector& strs, int m, int n) { + vector> dp(m + 1, vector(n + 1, 0)); + for (const string& s : strs) { + int zeros = 0, ones = 0; + for (char c : s) { + if (c == ’0’) { + ++zeros; + } else { + ++ones; + } + } + for (int i = m; i >= zeros; --i) { + for (int j = n; j >= ones; --j) { + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def findMaxForm(strs: List[str], m: int, n: int) -> int: + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for s in strs: + zeros = len(list(filter(lambda c: c == "0", s))) + ones = len(s) - zeros + for i in range(m, zeros - 1, -1): + for j in range(n, ones - 1, -1): + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) + return dp[m][n] +``` + + + + + +## [322. Coin Change](https://leetcode.com/problems/coin-change/) + +### Problem Description + +Given a list of coin denominations, find the minimum number of coins required to make up a given amount. + +### Input and Output Example + +Input is a one-dimensional integer array representing coin denominations and an integer representing the target amount. Output is an integer indicating the minimum number of coins required. If no solution exists, return -1. + +``` +Input: coins = [1, 2, 5], amount = 11 +Output: 3 +``` + +In this example, the minimum combination is 11 = 5 + 5 + 1. + +### Solution Explanation + +Since each coin can be used an unlimited number of times, this problem is essentially an unbounded knapsack problem. Below is the implementation using one-dimensional space compression. + +Note: The `dp` array is initialized to `amount + 1` instead of `-1` because the dynamic programming process involves taking the minimum. If initialized to `-1`, the result would always be `-1`. The choice of `amount + 1` is because the maximum possible number of coins is `amount` (using only 1-value coins), so this value is guaranteed to be greater than any valid combination. If the result remains `amount + 1` after the DP process, it means no valid combination exists, and we return `-1`. + + + + +```cpp +int coinChange(vector& coins, int amount) { + vector dp(amount + 1, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; ++i) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] != amount + 1 ? dp[amount] : -1; +} +``` + + + + +```py +def coinChange(coins: List[int], amount: int) -> int: + dp = [0] + [amount + 1] * amount + for i in range(1, amount + 1): + for coin in coins: + if i >= coin: + dp[i] = min(dp[i], dp[i - coin] + 1) + return dp[amount] if dp[amount] != amount + 1 else -1 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx new file mode 100644 index 00000000..f5331c5d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx @@ -0,0 +1,139 @@ +--- +sidebar_position: 32 +--- + +# 6.7 String Editing + +## [72. Edit Distance](https://leetcode.com/problems/edit-distance/) + +### Problem Description + +Given two strings, you can delete, replace, or insert any character from either string. Find the minimum number of steps required to make the two strings identical. + +### Input and Output Example + +Input consists of two strings, and the output is an integer representing the minimum number of steps. + +``` +Input: word1 = "horse", word2 = "ros" +Output: 3 +``` + +In this example, one optimal sequence of edits is horse -> rorse -> rose -> ros. + +### Solution Explanation + +Similar to problem 1143, we use a two-dimensional array `dp[i][j]`, where `dp[i][j]` represents the minimum number of edits required to transform the first string up to position `i` and the second string up to position `j`. + +- If the characters at position `i` and `j` are the same, then `dp[i][j] = dp[i-1][j-1]`. +- If the characters differ: + - The cost of modification is `dp[i-1][j-1] + 1`. + - The cost of inserting at position `i`/deleting at position `j` is `dp[i][j-1] + 1`. + - The cost of inserting at position `j`/deleting at position `i` is `dp[i-1][j] + 1`. + + + + +```cpp +int minDistance(string word1, string word2) { + int m = word1.length(), n = word2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 0; i <= m; ++i) { + for (int j = 0; j <= n; ++j) { + if (i == 0 || j == 0) { + dp[i][j] = i + j; + } else { + dp[i][j] = dp[i - 1][j - 1] + (word1[i - 1] != word2[j - 1]); + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def minDistance(word1: str, word2: str) -> int: + m, n = len(word1), len(word2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(m + 1): + for j in range(n + 1): + if i == 0 or j == 0: + dp[i][j] = i + j + else: + dp[i][j] = min( + dp[i - 1][j - 1] + int(word1[i - 1] != word2[j - 1]), + dp[i][j - 1] + 1, + dp[i - 1][j] + 1, + ) + return dp[m][n] +``` + + + + + +## [650. 2 Keys Keyboard](https://leetcode.com/problems/2-keys-keyboard/) + +### Problem Description + +Given the letter `A`, you can either copy all characters or paste the previously copied characters. Find the minimum number of operations needed to extend the string to the specified length. + +### Input and Output Example + +The input is a positive integer representing the target length, and the output is an integer representing the minimum number of operations required. + +``` +Input: 3 +Output: 3 +``` + +In this example, one optimal sequence of operations is to copy once and paste twice. + +### Solution Explanation + +Unlike typical dynamic programming problems that use addition or subtraction, this problem requires multiplication and division for state transitions because the paste operation doubles the length. We use a one-dimensional array `dp`, where `dp[i]` represents the minimum number of operations needed to extend the string to length `i`. For each position `j`, if `j` divides `i`, then length `i` can be achieved by operating on length `j`. The number of operations needed is equivalent to extending length `j` to length `i / j`. Thus, the recursive formula is `dp[i] = dp[j] + dp[i / j]`. + + + + + +```cpp +int minSteps(int n) { + vector dp(n + 1, 0); + for (int i = 2; i <= n; ++i) { + dp[i] = i; + for (int j = 2; j * j <= i; ++j) { + if (i % j == 0) { + dp[i] = dp[j] + dp[i / j]; + // Early pruning since smaller j guarantees the minimal operations. + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def minSteps(n: int) -> int: + dp = [0] * 2 + list(range(2, n + 1)) + for i in range(2, n + 1): + for j in range(2, floor(sqrt(i)) + 1): + if i % j == 0: + dp[i] = dp[j] + dp[i // j] + # Early pruning since smaller j guarantees the minimal operations. + break + return dp[n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx new file mode 100644 index 00000000..d4d8baca --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx @@ -0,0 +1,183 @@ +--- +sidebar_position: 33 +--- + +# 6.8 Stock Trading + +`Stock trading` problems can often be solved using dynamic programming. For more complex stock trading scenarios, such as requiring cooldown periods or transaction fees, a `state machine` implemented with dynamic programming is a common approach. + +## [121. Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) + +### Problem Description + +Given the fixed prices of a stock over a period of days, where you can only buy and sell once, find the maximum profit. + +### Input and Output Example + +The input is a one-dimensional array of integers representing daily stock prices, and the output is an integer representing the maximum profit. + +``` +Input: [7,1,5,3,6,4] +Output: 5 +``` + +In this example, the maximum profit is achieved by buying on day 2 (price = 1) and selling on day 5 (price = 6). + +### Solution Explanation + +We can traverse the array once, maintaining a record of the lowest price encountered before each day `i`. For each price, calculate the profit as the difference between the current price and the minimum price seen so far. Update the maximum profit accordingly. Note that in this problem, as well as others, `buy` and `sell` represent account operations: buying decreases account value (negative), and selling increases it (positive). + + + + + +```cpp +int maxProfit(vector& prices) { + int buy = numeric_limits::lowest(), sell = 0; + for (int price : prices) { + buy = max(buy, -price); + sell = max(sell, buy + price); + } + return sell; +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + buy, sell = -sys.maxsize, 0 + for price in prices: + buy = max(buy, -price) + sell = max(sell, buy + price) + return sell +``` + + + + + +## [188. Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) + +### Problem Description + +Given the fixed prices of a stock over a period of days, you can buy and sell at most $k$ times, holding at most one stock at a time. Find the maximum profit. + +### Input and Output Example + +The input is a one-dimensional array of integers representing daily stock prices, and an integer $k$ representing the number of allowed transactions. The output is an integer representing the maximum profit. + +``` +Input: [3,2,6,5,0,3], k = 2 +Output: 7 +``` + +In this example, the maximum profit is achieved by buying on day 2 (price = 2) and selling on day 3 (price = 6); then buying again on day 5 (price = 0) and selling on day 6 (price = 3). + +### Solution Explanation + +Similarly, we can define two dynamic programming arrays, `buy` and `sell`. For each day, `buy[j]` represents the maximum profit after the $j$-th buy, and `sell[j]` represents the maximum profit after the $j$-th sell. + + + + +```cpp +int maxProfit(int k, vector& prices) { + int days = prices.size(); + vector buy(k + 1, numeric_limits::lowest()), sell(k + 1, 0); + for (int i = 0; i < days; ++i) { + for (int j = 1; j <= k; ++j) { + buy[j] = max(buy[j], sell[j - 1] - prices[i]); + sell[j] = max(sell[j], buy[j] + prices[i]); + } + } + return sell[k]; +} +``` + + + + +```py +def maxProfit(k: int, prices: List[int]) -> int: + days = len(prices) + buy, sell = [-sys.maxsize] * (k + 1), [0] * (k + 1) + for i in range(days): + for j in range(1, k + 1): + buy[j] = max(buy[j], sell[j - 1] - prices[i]) + sell[j] = max(sell[j], buy[j] + prices[i]) + return sell[k] +``` + + + + + +## [309. Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) + +### Problem Description + +Given the fixed prices of a stock over a period of days, you can only own one stock at a time, and after selling a stock, you must wait one day (cooldown) before buying again. Find the maximum profit. + +### Input and Output Example + +The input is a one-dimensional array of integers representing daily stock prices. The output is an integer representing the maximum profit. + +``` +Input: [1,2,3,0,2] +Output: 3 +``` + +In this example, the optimal sequence of operations is buy, sell, cooldown, buy, sell. + +### Solution Explanation + +We can solve such complex state transition problems using a **state machine**. By defining multiple states and their transitions, we can derive the transition equations for each state. As illustrated, we can define four states to represent stock transactions with cooldowns, along with their transitions. + +
+ + ![](6.5.png) + +
Figure 6.5: Problem 309 - State Machine Transitions
+
+ + + + +```cpp +int maxProfit(vector& prices) { + int n = prices.size(); + vector buy(n), sell(n), s1(n), s2(n); + s1[0] = buy[0] = -prices[0]; + sell[0] = s2[0] = 0; + for (int i = 1; i < n; ++i) { + buy[i] = s2[i - 1] - prices[i]; + s1[i] = max(buy[i - 1], s1[i - 1]); + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i]; + s2[i] = max(s2[i - 1], sell[i - 1]); + } + return max(sell[n - 1], s2[n - 1]); +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + n = len(prices) + buy, sell, s1, s2 = [0] * n, [0] * n, [0] * n, [0] * n + s1[0] = buy[0] = -prices[0] + sell[0] = s2[0] = 0 + for i in range(1, n): + buy[i] = s2[i - 1] - prices[i] + s1[i] = max(buy[i - 1], s1[i - 1]) + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i] + s2[i] = max(s2[i - 1], sell[i - 1]) + return max(sell[n - 1], s2[n - 1]) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md new file mode 100644 index 00000000..79eb3e3b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md @@ -0,0 +1,61 @@ +--- +sidebar_position: 34 +--- + +# 6.9 Exercises + +## Basic Difficulty + +### [213. House Robber II](https://leetcode.com/problems/house-robber-ii/) + +Follow-up of the robber problem: how to handle circular arrays? + +--- + +### [53. Maximum Subarray](https://leetcode.com/problems/maximum-subarray/) + +A classic one-dimensional dynamic programming problem. Try optimizing the space complexity to a constant. + +--- + +### [343. Integer Break](https://leetcode.com/problems/integer-break/) + +A partition problem. First, solve it using dynamic programming, then think about whether there's a simpler approach. + +--- + +### [583. Delete Operation for Two Strings](https://leetcode.com/problems/delete-operation-for-two-strings/) + +A variation of the longest common subsequence problem. + +--- + +## Advanced Difficulty + +### [646. Maximum Length of Pair Chain](https://leetcode.com/problems/maximum-length-of-pair-chain/) + +A variation of the longest increasing subsequence problem. Similarly, try speeding it up using binary search. + +--- + +### [10. Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching/) + +Regex matching is a test of patience. You need to handle different cases, such as characters, asterisks, dots, etc., with careful condition discussions. + +--- + +### [376. Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/) + +The longest wiggle subsequence has a special formula. Think it through carefully. + +--- + +### [494. Target Sum](https://leetcode.com/problems/target-sum/) + +If told this is a 0-1 knapsack problem, does that give you any ideas? + +--- + +### [714. Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) + +Build a state machine, and stock trading problems will become much easier to solve. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png new file mode 100644 index 00000000..6b075633 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png new file mode 100644 index 00000000..4ff0572c Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png new file mode 100644 index 00000000..4acc447e Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png new file mode 100644 index 00000000..97774d35 Binary files /dev/null and b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png differ diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json new file mode 100644 index 00000000..4c1135db --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "6. Dynamic Programming Made Simple", + "position": 6, + "link": { + "type": "generated-index", + "description": "Chapter 6: Dynamic Programming Made Simple" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md new file mode 100644 index 00000000..392dceaf --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 35 +--- + +# 7.1 Algorithm Explanation + +As the name suggests, `divide and conquer` problems consist of two parts: "divide" and "conquer." By breaking the original problem into subproblems and then solving and merging these subproblems, we can solve the original problem. Merge sort, introduced in the sorting chapter, is a classic example of divide and conquer. In merge sort, the "divide" step splits the array into two smaller arrays using recursion until we get multiple arrays of length 1. The "conquer" step merges two sorted arrays into a single sorted array, starting from arrays of length 1 and eventually forming the final array. + +We can also use a mathematical expression to describe this process. Let $T(n)$ represent the time complexity of processing an array of length $n$. The recurrence relation for merge sort is $T(n) = 2T(n/2) + O(n)$. Here, $2T(n/2)$ represents splitting the array into two halves, and $O(n)$ represents the time complexity of merging two arrays of length $n/2$. + +:::info Theorem 7.1. Master Theorem + +For $T(n) = aT(n/b) + f(n)$, define $k = \log_{b} a$: +1. If $f(n) = O(n^p)$ and $p < k$, then $T(n) = O(n^k)$ +2. If there exists $c \geq 0$ such that $f(n) = O(n^k \log^c n)$, then $T(n) = O(n^k \log^{c+1} n)$ +3. If $f(n) = O(n^p)$ and $p > k$, then $T(n) = O(f(n))$ + +::: + +Using the master theorem, we can deduce that merge sort falls into the second category with a time complexity of $O(n \log n)$. Other divide-and-conquer problems can also use the master theorem to determine their time complexities. + +Additionally, top-down divide-and-conquer can be combined with memoization to avoid redundant traversal of identical subproblems. Alternatively, if it's convenient for derivation, a bottom-up dynamic programming approach can be used instead. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx new file mode 100644 index 00000000..8a5eeb02 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx @@ -0,0 +1,155 @@ +--- +sidebar_position: 36 +--- + +# 7.2 Expression Problems + +## [241. Different Ways to Add Parentheses](https://leetcode.com/problems/different-ways-to-add-parentheses/) + +### Problem Description + +Given a mathematical expression containing addition, subtraction, and multiplication, find all possible results by adding parentheses in different ways. + +### Input and Output Example + +The input is a string representing a mathematical expression, and the output is an array containing all unique results. + +``` +Input: "2-1-1" +Output: [0, 2] +``` + +In this example, there are two ways to add parentheses: ((2-1)-1) = 0 and (2-(1-1)) = 2. + +### Solution Explanation + +Using the divide-and-conquer approach, we can break down the problem by considering each operator, first solving the sub-expressions on both sides of the operator, and then combining the results using the operator. Special attention is needed for the base case where the input string contains no operators, only a single number. + + + + +```cpp +vector diffWaysToCompute(string expression) { + vector ways; + unordered_map> op_funcs; + op_funcs[’+’] = [](int x, int y) { return x + y; }; + op_funcs[’-’] = [](int x, int y) { return x - y; }; + op_funcs[’*’] = [](int x, int y) { return x * y; }; + for (int i = 0; i < expression.length(); ++i) { + char c = expression[i]; + if (!op_funcs.contains(c)) { + continue; + } + auto left = diffWaysToCompute(expression.substr(0, i)); + auto right = diffWaysToCompute(expression.substr(i + 1)); + for (int l : left) { + for (int r : right) { + ways.push_back(op_funcs[c](l, r)); + } + } + } + return ways.empty() ? vector{stoi(expression)} : ways; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + ways = [] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i, c in enumerate(expression): + if c not in op_funcs: + continue + left = diffWaysToCompute(expression[:i]) + right = diffWaysToCompute(expression[i + 1 :]) + ways += [op_funcs[c](l, r) for l in left for r in right] + return [int(expression)] if len(ways) == 0 else ways +``` + + + + + +We observe that some substrings produced by the `divide` step may appear multiple times. To avoid redundant calculations, we can use `memoization`. For instance, we can create a hash table where the `key` is `(l, r)` and the `value` is `ways`. Whenever the same `(l, r)` appears again, we can directly return the previously computed `ways`. Alternatively, instead of using a top-down divide-and-conquer approach with `memoization`, we could adopt a bottom-up dynamic programming approach. + + + + + +```cpp +vector diffWaysToCompute(string expression) { + // Use istringstream to split numbers and operators. + vector nums; + vector ops; + int num = 0; + char op = ’ ’; + istringstream ss(expression); + while (ss >> num) { + nums.push_back(num); + if (ss >> op) { + ops.push_back(op); + } + } + int n = nums.size(); + vector>> dp(n, vector>(n, vector())); + unordered_map> op_funcs; + op_funcs[’+’] = [](int a, int b) { return a + b; }; + op_funcs[’-’] = [](int a, int b) { return a - b; }; + op_funcs[’*’] = [](int a, int b) { return a * b; }; + for (int i = 0; i < n; ++i) { + for (int j = i; j >= 0; --j) { + if (i == j) { + dp[j][i].push_back(nums[i]); + continue; + } + for (int k = j; k < i; ++k) { + for (auto l : dp[j][k]) { + for (auto r : dp[k + 1][i]) { + dp[j][i].push_back(op_funcs[ops[k]](l, r)); + } + } + } + } + } + return dp[0][n - 1]; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + # re.split can directly separate operators (\D) and numbers. + sections = re.split(r"(\D)", expression) + nums = [int(num) for num in sections if num.isdigit()] + ops = [op for op in sections if not op.isdigit()] + n = len(nums) + dp = [[[] for _ in range(n)] for _ in range(n)] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i in range(n): + for j in range(i, -1, -1): + if i == j: + dp[j][i].append(nums[i]) + continue + for k in range(j, i): + dp[j][i] += [op_funcs[ops[k]](l, r) + for l in dp[j][k] for r in dp[k + 1][i]] + + return dp[0][n - 1] + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md new file mode 100644 index 00000000..18032a1e --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 37 +--- + +# 7.3 Exercises + +## Basic Difficulty + +### [932. Beautiful Array](https://leetcode.com/problems/beautiful-array/) + +Try solving this using a top-down divide-and-conquer (recursive) approach with `memoization` for optimization; then attempt a bottom-up dynamic programming approach. + +--- + +## Advanced Difficulty + +### [312. Burst Balloons](https://leetcode.com/problems/burst-balloons/) + +Try solving this using a top-down divide-and-conquer (recursive) approach with `memoization` for optimization; then attempt a bottom-up dynamic programming approach. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json new file mode 100644 index 00000000..4c5832a8 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "7. Simplifying with Divide and Conquer", + "position": 7, + "link": { + "type": "generated-index", + "description": "Chapter 7: Simplifying with Divide and Conquer" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md new file mode 100644 index 00000000..4603f312 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 38 +--- + +# 8.1 Introduction + +For the numerous math problems on LeetCode, we strive to categorize and explain them by type. However, many math problems have solutions that are not universally applicable, making it challenging to summarize all problem-solving techniques in one go. Therefore, we have selected a few classic or representative problems for your reference. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx new file mode 100644 index 00000000..a4aac979 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 39 +--- + +# 8.2 Least Common Multiple and Greatest Common Divisor + +Using the `Euclidean algorithm`, we can efficiently calculate the greatest common divisor (GCD) of two numbers. Multiplying the two numbers and dividing the product by their GCD gives the least common multiple (LCM). + + + + + +```cpp +int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); +} + +int lcm(int a, int b) { + return a * b / gcd(a, b); +} +``` + + + + +```py +def gcd(a: int, b: int) -> int: + return a if b == 0 else gcd(b, a % b) + +def lcm(a: int, b: int) -> int: + return (a * b) // gcd(a, b) +``` + + + + + +Furthermore, using the extended Euclidean algorithm (extended GCD), we can calculate not only the GCD of a and b but also their coefficients x and y such that ax + by = gcd(a, b). In Python, since int is passed by value, we can use a fixed-length list() to achieve reference passing. + + + + +```cpp +int xGCD(int a, int b, int &x, int &y) { + if (b == 0) { + x = 1, y = 0; + return a; + } + int x_inner, y_inner; + int gcd = xGCD(b, a % b, x_inner, y_inner); + x = y_inner, y = x_inner - (a / b) * y_inner; + return gcd; +} +``` + + + + +```py +def xGCD(a: int, b: int, x: List[int], y: List[int]) -> int: + if b == 0: + x[0], y[0] = 1, 0 + return a + x_inner, y_inner = [0], [0] + gcd = xGCD(b, a % b, x_inner, y_inner) + x[0], y[0] = y_inner, x_inner - (a / b) * y_inner + return gcd +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx new file mode 100644 index 00000000..b0c8134f --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx @@ -0,0 +1,138 @@ +--- +sidebar_position: 40 +--- + +# 8.3 Prime Numbers + +Prime numbers are integers greater than 1 that have no divisors other than 1 and themselves. It is important to note that every number can be expressed as a product of prime numbers. + + +## [204. Count Primes](https://leetcode.com/problems/count-primes/) + +### Problem Description + +Given a number \( n \), find the count of prime numbers less than \( n \). + +### Input and Output Example + +Input an integer and output another integer representing the count of prime numbers less than the input number. + +``` +Input: 10 +Output: 4 +``` + +In this example, the prime numbers less than 10 are [2, 3, 5, 7]. + +### Solution Explanation + +The `Sieve of Eratosthenes` is a widely used algorithm for determining whether an integer is a prime number. It is particularly efficient for determining all prime numbers less than a given integer $n$. The principle is simple: iterate through numbers from $1$ to $n$, and for the current number $m$, mark all multiples of $m$ (less than $n$) as composite numbers. After processing, the numbers not marked as composite are prime. + + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int count = n - 2; // Remove the non-prime number 1 + for (int i = 2; i < n; ++i) { + if (primes[i]) { + for (int j = 2 * i; j < n; j += i) { + if (primes[j]) { + primes[j] = false; + --count; + } + } + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + count = n - 2 # Remove the non-prime number 1 + for i in range(2, n): + if primes[i]: + for j in range(2 * i, n, i): + if primes[j]: + primes[j] = False + count -= 1 + return count +``` + + + + + +By leveraging certain properties of prime numbers, we can further optimize this algorithm. + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int sqrtn = sqrt(n); + int count = n / 2; // Even numbers are not prime + int i = 3; + // The smallest prime factor is always less than or equal to the square root. + while (i <= sqrtn) { + // Find multiples to the right, avoiding even numbers and redundant checks. + for (int j = i * i; j < n; j += 2 * i) { + if (primes[j]) { + --count; + primes[j] = false; + } + } + i += 2; + // Move to the next position to the right, avoiding even numbers and redundant checks. + while (i <= sqrtn && !primes[i]) { + i += 2; + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + sqrtn = sqrt(n) + count = n // 2 # Even numbers are not prime + i = 3 + # The smallest prime factor is always less than or equal to the square root. + while i <= sqrtn: + # Find multiples to the right, avoiding even numbers and redundant checks. + for j in range(i * i, n, 2 * i): + if primes[j]: + count -= 1 + primes[j] = False + i += 2 + # Move to the next position to the right, avoiding even numbers and redundant checks. + while i <= sqrtn and not primes[i]: + i += 2 + return count +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx new file mode 100644 index 00000000..db72a64a --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx @@ -0,0 +1,316 @@ +--- +sidebar_position: 41 +--- + +# 8.4 Numerical Processing + +## [504. Base 7](https://leetcode.com/problems/base-7/) + +### Problem Description + +Given a decimal integer, convert it to its base-7 representation. + +### Input and Output Example + +Input a decimal integer and output a string representing its base-7 format. + +``` +Input: 100 +Output: "202" +``` + +In this example, 100 in base-7 comes from 100 = 2 * 49 + 0 * 7 + 2 * 1. + +### Solution Explanation + +For `base conversion` problems, division and modulus (mod) are typically used for calculations. Special attention is needed for edge cases such as negative numbers and zero. If the output is expected as a numeric type rather than a string, consider whether it might exceed integer bounds. + + + + +```cpp +string convertToBase7(int num) { + if (num == 0) { + return "0"; + } + string base7; + bool is_negative = num < 0; + num = abs(num); + while (num) { + int quotient = num / 7, remainder = num % 7; + base7 = to_string(remainder) + base7; + num = quotient; + } + return is_negative ? "-" + base7 : base7; +} +``` + + + + +```py +def convertToBase7(num: int) -> str: + if num == 0: + return "0" + base7 = "" + is_negative = num < 0 + num = abs(num) + while num: + quotient, remainder = num // 7, num % 7 + base7 = str(remainder) + base7 + num = quotient + return "-" + base7 if is_negative else base7 +``` + + + + + +## [172. Factorial Trailing Zeroes](https://leetcode.com/problems/factorial-trailing-zeroes/) + +### Problem Description + +Given a non-negative integer, determine how many trailing zeroes are in its factorial result. + +### Input and Output Example + +Input a non-negative integer and output a non-negative integer representing the number of trailing zeroes in the factorial result. + +``` +Input: 12 +Output: 2 +``` + +In this example, 12! = 479001600 has two trailing zeroes. + +### Solution Explanation + +Each trailing 0 is produced by a factor of 2 × 5 = 10. Therefore, we can decompose each element in the factorial into its prime factors and count how many 2s and 5s there are. It is evident that the number of factor 2s is far greater than the number of factor 5s, so we only need to count the number of factor 5s in the factorial result. + + + + +```cpp +int trailingZeroes(int n) { + return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); +} +``` + + + + +```py +def trailingZeroes(n: int) -> int: + return 0 if n == 0 else n // 5 + trailingZeroes(n // 5) +``` + + + + + +## [415. Add Strings](https://leetcode.com/problems/add-strings/) + +### Problem Description + +Given two strings composed of digits, find their sum as a result. + +### Input and Output Example + +Input consists of two strings, and output is an integer representing the sum of the input numbers. + +``` +Input: num1 = "99", num2 = "1" +Output: 100 +``` + +Since addition proceeds from right to left, the strings can be reversed first, then calculated digit by digit. This type of problem tests attention to details, such as carrying and handling different string lengths. + +### Solution Explanation + + + + +```cpp +string addStrings(string num1, string num2) { + string added_str; + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + int len1 = num1.length(), len2 = num2.length(); + if (len1 <= len2) { + swap(num1, num2); + swap(len1, len2); + } + int add_bit = 0; + for (int i = 0; i < len1; ++i) { + int cur_sum = + (num1[i] - ’0’) + (i < len2 ? num2[i] - ’0’ : 0) + add_bit; + added_str += to_string(cur_sum % 10); + add_bit = cur_sum >= 10; + } + if (add_bit) { + added_str += "1"; + } + reverse(added_str.begin(), added_str.end()); + return added_str; +} +``` + + + + +```py +def addStrings(num1: str, num2: str) -> str: + added_str = "" + num1 = num1[::-1] + num2 = num2[::-1] + len1, len2 = len(num1), len(num2) + if len1 <= len2: + num1, num2 = num2, num1 + len1, len2 = len2, len1 + add_bit = 0 + for i in range(len1): + cur_sum = int(num1[i]) + (int(num2[i]) if i < len2 else 0) + add_bit + added_str += str(cur_sum % 10) + add_bit = int(cur_sum >= 10) + if add_bit: + added_str += "1" + return added_str[::-1] +``` + + + + + + +## [326. Power of Three](https://leetcode.com/problems/power-of-three/) + +### Problem Description + +Determine whether a number is a power of 3. + +### Input and Output Example + +Input an integer, output a boolean value. + +``` +Input: n = 27 +Output: true +``` + +### Solution Explanation + +There are two methods. One is using logarithms. Let log3 n = m, if n is an integer power of 3, then m must be an integer. + + + + +```cpp +bool isPowerOfThree(int n) { + return fmod(log10(n) / log10(3), 1) == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + return n > 0 and math.fmod(math.log10(n) / math.log10(3), 1) == 0 +``` + + + + + +Another method is that, within the range of a C++ `int`, the maximum power of 3 is $3^{19} = 1162261467$. If `n` is an integer power of 3, then `1162261467 % n` must equal zero; otherwise, it is not. However, in Python, since `int` can theoretically represent arbitrarily large numbers, we can only use a loop to verify. + + + + +```cpp +bool isPowerOfThree(int n) { + return n > 0 && 1162261467 % n == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + if n <= 0: + return False + while n % 3 == 0: + n //= 3 + return n == 1 +``` + + + + + +## [50. Pow(x, n)](https://leetcode.com/problems/powx-n/) + +### Problem Description + +Compute `x` raised to the power `n`. + +### Input and Output Example + +Input a floating-point number `x` and an integer `n`, output a floating-point number representing the result of the power computation. + +``` +Input: x = 2.00000, n = 10 +Output: 1024.00000 +``` + +### Solution Explanation + + +Using recursion, we can solve this problem relatively easily. Pay attention to handling edge cases. + + + + +```cpp +double myPow(double x, int n) { + if (n == 0) { + return 1; + } + if (x == 0) { + return 0; + } + if (n == numeric_limits::min()) { + return 1 / (x * myPow(x, numeric_limits::max())); + } + if (n < 0) { + return 1 / myPow(x, -n); + } + if (n % 2 != 0) { + return x * myPow(x, n - 1); + } + double myPowSqrt = myPow(x, n >> 1); + return myPowSqrt * myPowSqrt; +} +``` + + + + +```py +def myPow(x: float, n: int) -> float: + if n == 0: + return 1 + if x == 0: + return 0 + if n < 0: + return 1 / myPow(x, -n) + if n % 2 != 0: + return x * myPow(x, n - 1) + myPowSqrt = myPow(x, n >> 1) + return myPowSqrt * myPowSqrt +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx new file mode 100644 index 00000000..8b494b7d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx @@ -0,0 +1,232 @@ +--- +sidebar_position: 42 +--- + +# 8.5 Random and Sampling + +## [384. Shuffle an Array](https://leetcode.com/problems/shuffle-an-array/) + +### Problem Description + +Given an array, implement two functions. The first function `shuffle` randomly shuffles the array, and the second function `reset` restores the array to its original order. + +### Input and Output Example + +Input is an array of integers and a list of function names. Output is a two-dimensional array representing the result of each function call. + +``` +Input: nums = [1,2,3], actions: ["shuffle","shuffle","reset"] +Output: [[2,1,3],[3,2,1],[1,2,3]] +``` + +In this example, the first two shuffle results can be any random permutations. + +### Solution Explanation + +We use the classical `Fisher-Yates Shuffle Algorithm`, which works by swapping elements randomly to shuffle the array. Both forward and backward implementations are equally valid. Pay attention to the implementation details of the `reset` function and the constructor of the `Solution` class. + + + + +```cpp +class Solution { + public: + Solution(vector nums) : nums_(nums) {} + + vector reset() { return nums_; } + + vector shuffle() { + vector shuffled(nums_); + int n = nums_.size(); + // Reverse shuffle: effective and equivalent. + for (int i = n - 1; i >= 0; --i) { + swap(shuffled[i], shuffled[rand() % (i + 1)]); + } + // Forward shuffle: another valid approach. + // for (int i = 0; i < n; ++i) { + // int pos = rand() % (n - i); + // swap(shuffled[i], shuffled[i+pos]); + // } + return shuffled; + } + + private: + vector nums_; +}; +``` + + + + +```py +class Solution: + def __init__(self, nums: List[int]): + self.base = nums[:] + + def reset(self) -> List[int]: + return self.base[:] + + def shuffle(self) -> List[int]: + shuffled = self.base[:] + n = len(self.base) + # Reverse shuffle: effective and equivalent. + for i in range(n - 1, -1, -1): + j = random.randint(0, i) + shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + # Forward shuffle: another valid approach. + # for i in range(n): + # j = i + random.randint(0, n - i - 1) + # shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + return shuffled +``` + + + + + +## [528. Random Pick with Weight](https://leetcode.com/problems/random-pick-with-weight/) + +### Problem Description + +Given an array where each position's value represents its weight, implement a method to randomly sample indices based on these weights. + +### Input and Output Example + +Input consists of a one-dimensional positive integer array representing weights, and another one-dimensional string array of commands specifying the number of random samples. Output is a one-dimensional integer array indicating the sampled indices. + +``` +Input: weights = [1,3], actions: ["pickIndex","pickIndex","pickIndex"] +Output: [0,1,1] +``` + +In this example, the chosen index is uncertain each time, but the expected probability for index 0 is 1/4, and for index 1 is 3/4. + +### Solution Explanation + +We can first calculate the prefix sum using `partial_sum`, which gives the cumulative sum of weights up to each position. The resulting array for positive integers is monotonically increasing. When sampling, we generate a random number and use binary search to locate its position within the prefix sum, simulating the weighted sampling process. This binary search can be implemented using `lower_bound`. + +For the example, the prefix sum of weights [1,3] is [1,4]. If the random number is 1, `lower_bound` returns 0; if the random number is 2, 3, or 4, `lower_bound` returns 1. + +We'll delve deeper into prefix sum techniques in the following sections. + + + + +```cpp +class Solution { + public: + Solution(vector weights) : cumsum_(weights) { + partial_sum(cumsum_.begin(), cumsum_.end(), cumsum_.begin()); + } + + int pickIndex() { + int val = (rand() % cumsum_.back()) + 1; + return lower_bound(cumsum_.begin(), cumsum_.end(), val) - + cumsum_.begin(); + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class Solution: + def __init__(self, weights: List[int]): + self.cumsum = weights[:] + for i in range(1, len(weights)): + self.cumsum[i] += self.cumsum[i - 1] + + def pickIndex(self) -> int: + val = random.randint(1, self.cumsum[-1]) + return bisect.bisect_left(self.cumsum, val, 0, len(self.cumsum)) +``` + + + + + +## [382. Linked List Random Node](https://leetcode.com/problems/linked-list-random-node/) + +### Problem Description + +Given a singly linked list, design an algorithm to randomly return one of its values. + +### Input and Output Example + +Input is a singly linked list, output is a number representing the value of one of its nodes. + +``` +Input: 1->2->3->4->5 +Output: 3 +``` + +In this example, each node has an equal chance of being selected, such as node 3. + +### Solution Explanation + +Unlike arrays, where the total size is known, we cannot determine the total length of a linked list before traversal. In this scenario, we can use **reservoir sampling**: traverse the linked list, and at the $m$-th node, choose it with a probability of $\frac{1}{m}$ to replace the previously chosen node. + +A simple proof of the randomness of reservoir sampling is as follows: for the $m$-th node in a linked list of length $n$, the sufficient and necessary condition for it to be sampled is that it is chosen, and none of the subsequent nodes are chosen. The probability is calculated as: + +$$ +\frac{1}{m} × \frac{m}{m+1} × \frac{m+1}{m+2} × · · · × \frac{n−1}{n} = \frac{1}{n} +$$ + +Thus, each node has an equal probability of being selected. + +Alternatively, we can preprocess the linked list by traversing it once and converting it into an array for easier random access. + + + + +```cpp +class Solution { + public: + Solution(ListNode* node) : head_(node) {} + + int getRandom() { + int pick = head_->val; + ListNode* node = head_->next; + int i = 2; + while (node) { + if (rand() % i == 0) { + pick = node->val; + } + ++i; + node = node->next; + } + return pick; + } + + private: + ListNode* head_; +}; +``` + + + + +```py +class Solution: + def __init__(self, head: Optional[ListNode]): + self.head = head + + def getRandom(self) -> int: + pick = self.head.val + node = self.head.next + i = 2 + while node is not None: + if random.randint(0, i - 1) == 0: + pick = node.val + i += 1 + node = node.next + return pick +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md new file mode 100644 index 00000000..53d7a6e9 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 43 +--- + +# 8.6 Exercises + +## Basic Difficulty + +### [168. Excel Sheet Column Title](https://leetcode.com/problems/excel-sheet-column-title/) + +A variation of base-7 conversion, where the sequence starts from 1 instead of 0. + +--- + +### [67. Add Binary](https://leetcode.com/problems/add-binary/) + +A variation of string addition. + +--- + +### [238. Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) + +Can you solve this problem without using division? A previously discussed problem like 135 might give you some ideas. + +--- + +## Advanced Difficulty + +### [462. Minimum Moves to Equal Array Elements II](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/) + +One of my favorite LeetCode problems. It requires reasoning about the optimal way to make moves and then considering how to implement the moves. You might need some algorithms we discussed earlier. + +--- + +### [169. Majority Element](https://leetcode.com/problems/majority-element/) + +If you can't come up with a simple solution, search for the Boyer-Moore Majority Vote algorithm. + +--- + +### [470. Implement Rand10() Using Rand7()](https://leetcode.com/problems/implement-rand10-using-rand7/) + +How can you generate one random number generator using another? You may need to utilize the original generator multiple times. + +--- + +### [202. Happy Number](https://leetcode.com/problems/happy-number/) + +You can solve this problem using a simple `while` loop, but is there a better way? If we think of each number as a node, can we transform this into a cycle detection problem? \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json new file mode 100644 index 00000000..8ded4db1 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "8. Clever Math Problem Solving", + "position": 8, + "link": { + "type": "generated-index", + "description": "Chapter 8: Clever Math Problem Solving" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md new file mode 100644 index 00000000..5d955fa6 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 44 +--- + +# 9.1 Common Techniques + +`Bit manipulation` is a unique category in algorithm problems. By leveraging the characteristics of binary bit operations, we can achieve fascinating optimizations and calculations. Here are some common bitwise operators and their functions: + + +- `∧`: Bitwise XOR +- `&`: Bitwise AND +- `|`: Bitwise OR +- `~`: Bitwise NOT +- `<<`: Arithmetic left shift +- `>>`: Arithmetic right shift + +Below are some commonly used bitwise properties, where `0s` and `1s` represent binary numbers composed entirely of `0` or `1`, respectively: + +``` +x ^ 0s = x x & 0s = 0 x | 0s = x +x ^ 1s = ~x x & 1s = x x | 1s = 1s +x ^ x = 0 x & x = x x | x = x +``` + + +Additionally, here are some frequently used techniques: + +1. **Remove the lowest set bit**: `n & (n - 1)` + - This operation removes the lowest `1` in the binary representation of `n`. For example: + ``` + n = 11110100 + n - 1 = 11110011 + n & (n - 1) = 11110000 + ``` + +2. **Retrieve the lowest set bit**: `n & (-n)` + - This operation isolates the lowest `1` in the binary representation of `n`. For example: + ``` + n = 11110100 + -n = 00001100 + n & (-n) = 00000100 + ``` + +These are the commonly used bit manipulation tricks. For those interested, there are more advanced techniques worth exploring, but they will not be covered here. diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx new file mode 100644 index 00000000..909507af --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx @@ -0,0 +1,179 @@ +--- +sidebar_position: 45 +--- + +# 9.2 Basic Problems in Bit Manipulation + +## [461. Hamming Distance](https://leetcode.com/problems/hamming-distance/) + +### Problem Description + +Given two decimal numbers, calculate the Hamming distance between their binary representations (i.e., the number of differing bits). + +### Input and Output Example + +The input consists of two decimal integers, and the output is a decimal integer representing their Hamming distance. + +``` +Input: x = 1, y = 4 +Output: 2 +``` + +In this example, the binary representation of 1 is `0001`, and that of 4 is `0100`, with two differing bits. + +### Solution Explanation + +Perform a bitwise XOR operation on the two numbers and count the number of `1`s in the result. + + + + +```cpp +int hammingDistance(int x, int y) { + int diff = x ^ y, dist = 0; + while (diff != 0) { + dist += diff & 1; + diff >>= 1; + } + return dist; +} +``` + + + + +```py +def hammingDistance(x: int, y: int) -> int: + diff = x ^ y + dist = 0 + while diff != 0: + dist += diff & 1 + diff = diff >> 1 + return dist +``` + + + + + +## [190. Reverse Bits](https://leetcode.com/problems/reverse-bits/) + +### Problem Description + +Given a decimal positive integer, output its reversed binary representation. + +### Input and Output Example + +Both input and output are decimal positive integers. + +``` +Input: 43261596 (00000010100101000001111010011100) +Output: 964176192 (00111001011110000010100101000000) +``` + +Using arithmetic left shift and right shift, binary reversal can be easily implemented. + +### Solution Explanation + + + + +```cpp +uint32_t reverseBits(uint32_t n) { + uint32_t m = 0; + for (int i = 0; i < 32; ++i) { + m <<= 1; + m += n & 1; + n >>= 1; + } + return m; +} +``` + + + + +```py +def reverseBits(n: int) -> int: + m = 0 + for _ in range(32): + m = m << 1 + m += n & 1 + n = n >> 1 + return m +``` + + + + + +## [136. Single Number](https://leetcode.com/problems/single-number/) + +### Problem Description + +Given an integer array, only one number in this array appears exactly once, while all other numbers appear twice. Find the number that appears only once. + +### Input and Output Example + +The input is a one-dimensional integer array, and the output is an integer from the array. + +``` +Input: [4,1,2,1,2] +Output: 4 +``` + +### Solution Explanation + +We can use the properties of x ∧ x = 0 and x ∧ 0 = x to solve this. By performing a bitwise XOR on all numbers in the array, the result of XORing all numbers that appear twice is 0. XORing 0 with the number that appears once gives the number itself. + + + + +```cpp +int singleNumber(vector& nums) { + int single = 0; + for (int num : nums) { + single ^= num; + } + return single; +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + single = 0 + for num in nums: + single = single ^ num + return single +``` + + + + + +Here, we can also directly use the `reduce` function: + + + + +```cpp +int singleNumber(vector& nums) { + return reduce(nums.begin(), nums.end(), 0, + [](int x, int y) { return x ^ y; }); +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + return functools.reduce(lambda x, y: x ^ y, nums) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx new file mode 100644 index 00000000..08465c3d --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx @@ -0,0 +1,125 @@ +--- +sidebar_position: 46 +--- + +# 9.3 Binary Features + +By leveraging some binary features, we can apply bitwise operations to solve a wider range of problems. + +For example, we can use binary and bitwise operations to generate all subsets of an array. Suppose we have an array of length $n$, we can generate all binary numbers of length $n$, where 1 indicates selecting the number, and 0 indicates not selecting it. This way, we obtain $2^n$ subsets. + +## [318. Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/) + +### Problem Description + +Given multiple strings, find the maximum product of lengths of any two strings such that the two strings do not share any common letters. + +### Input and Output Example + +Input is a one-dimensional array containing multiple strings, and output is an integer representing the maximum product of lengths. + +``` +Input: ["a","ab","abc","d","cd","bcd","abcd"] +Output: 4 +``` + +In this example, one optimal pair is "ab" and "cd." + +### Solution Explanation + +How can we quickly determine if two strings share common letters? We can represent each string with a binary number of length 26, where each position indicates the presence of a specific letter. If two strings share common letters, their binary representations' bitwise AND will not be 0. Additionally, we can use a hash map to store the mapping from binary numbers to the longest string lengths. For example, "ab" and "aab" may have the same binary representation, but "aab" is longer. + + + + +```cpp +int maxProduct(vector& words) { + unordered_map cache; + int max_prod = 0; + for (const string& word : words) { + int mask = 0, w_len = word.length(); + for (char c : word) { + mask |= 1 << (c - ’a’); + } + cache[mask] = max(cache[mask], w_len); + for (auto [h_mask, h_len] : cache) { + if ((mask & h_mask) == 0) { + max_prod = max(max_prod, w_len * h_len); + } + } + } + return max_prod; +} +``` + + + + +```py +def maxProduct(words: List[str]) -> int: + cache = dict() + max_prod = 0 + for word in words: + mask, w_len = 0, len(word) + for c in word: + mask = mask | (1 << (ord(c) - ord("a"))) + cache[mask] = max(cache.get(mask, 0), w_len) + for h_mask, h_len in cache.items(): + if (mask & h_mask) == 0: + max_prod = max(max_prod, w_len * h_len) + return max_prod +``` + + + + + +## [338. Counting Bits](https://leetcode.com/problems/counting-bits/) + +### Problem Description + +Given a non-negative integer `n`, find the number of `1`s in the binary representation of every number from `0` to `n`. + +### Input and Output Example + +The input is a non-negative integer `n`, and the output is a list of non-negative integers of length `n + 1`, where each position `m` represents the number of `1`s in the binary representation of `m`. + +``` +Input: 5 +Output: [0,1,1,2,1,2] +``` + +### Solution Explanation + +This problem can be solved efficiently using dynamic programming and bitwise operations. Define an array `dp`, where `dp[i]` represents the number of `1`s in the binary representation of the number `i`. For the number `i`: +- If the last bit of its binary representation is `1`, the count of `1`s is `dp[i-1] + 1`. +- If the last bit of its binary representation is `0`, the count of `1`s is the same as that of its arithmetic right-shift result, i.e., `dp[i>>1]`. + + + + +```cpp +vector countBits(int n) { + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) + // Equivalent to: dp[i] = dp[i & (i - 1)] + 1; + dp[i] = i & 1 ? dp[i - 1] + 1 : dp[i >> 1]; + return dp; +} +``` + + + + +```py +def countBits(n: int) -> List[int]: + dp = [0] * (n + 1) + for i in range(1, n + 1): + # Equivalent to: dp[i] = dp[i & (i - 1)] + 1 + dp[i] = dp[i - 1] + 1 if i & 1 else dp[i >> 1] + return dp +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md new file mode 100644 index 00000000..b975477b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 47 +--- + +# 9.4 Exercises + +## Basic Difficulty + +### [268. Missing Number](https://leetcode.com/problems/missing-number/) + +A variation of the Single Number problem. Besides using bitwise operations, the problem can also be solved using the Gaussian summation formula. + +--- + +### [693. Binary Number with Alternating Bits](https://leetcode.com/problems/binary-number-with-alternating-bits/) + +Use bitwise operations to determine whether a number's binary representation alternates between `0` and `1`. + +--- + +### [476. Number Complement](https://leetcode.com/problems/number-complement/) + +A variation of binary flipping problems. + +--- + +## Advanced Difficulty + +### [260. Single Number III](https://leetcode.com/problems/single-number-iii/) + +A follow-up to the Single Number problem. Requires careful thought on how to leverage bitwise operations to solve. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json new file mode 100644 index 00000000..cb4d422b --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "9. Magical Bit Manipulation", + "position": 9, + "link": { + "type": "generated-index", + "description": "Chapter 9: Magical Bit Manipulation" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/acknowledgments.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/acknowledgments.md new file mode 100644 index 00000000..6c1f5320 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/acknowledgments.md @@ -0,0 +1,16 @@ +--- +sidebar_position: 79 +--- + +# Acknowledgments + +## Officially Recognized Supreme Supporter +Yudi Zhang + +## Friendly Sponsors +In no particular order: Yujia Chen、Chaoyu Wang、Chunyan Bai、Haoshuo Huang、Wenting Ye、Yuting Wang、Bill Liu、Zhiyu Min、Xuyang Cheng、Keyi Xian、Yihan Zhang、Rui Yan、Mao Cheng、Michael +Wang, and others. + +## GitHub Contributors + +In no particular order: quweikoala、szlghl1、mag1cianag、woodpenker、yangCoder96、cluckl、shaoshuai-luo、KivenGood、alicegong、hitYunhongXu、shengchen1998、jihchi、hapoyige、hitYunhongXu、h82258652、conan81412B、Mirrorigin、Light-young、XiangYG、xnervwang、sabaizzz、PhoenixChen98、zhang-wang997、corbg118、tracyqwerty、yorhaha、DeckardZ46、Ricardo-609、namu-guwal、hkulyc、jacklanda、View0、HelloYJohn、Corezcy、MoyuST、lutengda、fengshansi, and others. \ No newline at end of file diff --git a/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/index.md b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/index.md new file mode 100644 index 00000000..a6264fa7 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-plugin-content-docs/current/index.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 0 +--- + +# LeetCode 101: A Grinding Guide (2nd Edition) + +![](https://github.com/changgyhub/leetcode_101/blob/master/misc/cover.jpg?raw=true) + +Author: Chang Gao + +Languages: C++ & Python + +Version: Official Version 2.0c, latest version available on GitHub [changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +:::info +A textbook and reference guide for readers with basic programming knowledge but limited problem-solving experience. +::: + +## Preface + +At the end of 2019, the first edition of this book was officially released on GitHub and received an enthusiastic response. Over the past five years, the author has gained extensive work experience and recognized numerous flaws and shortcomings in the first edition. Thus, at the end of 2024, the author reorganized the content and released this second edition. + +This book is divided into three main parts: algorithms, mathematics, and data structures, spanning fifteen chapters. It provides a comprehensive explanation of techniques frequently used when solving LeetCode problems. In the first edition, the number of problems was restricted to 101 to align with the term "101" (symbolizing an introduction in English). However, the scope of interview questions has expanded over time. Hence, the second edition includes additional key problems to help readers fill any gaps in their knowledge. The author carefully selected problems based on their likelihood of appearing in interviews, ease of understanding, and general applicability. Each chapter concludes with practice problems that readers are strongly encouraged to attempt after completing the chapter. + +Every regular problem in this book comes with solutions in both C++ and Python3. Since the book’s purpose is not to teach C++ or Python, the author avoids delving too deeply into syntax details and uses some modern C++ standards and Pythonic code. As of late 2024, all code in the book runs correctly on LeetCode and, while maintaining readability, is often the fastest or most space-efficient solution. + +Remember, solving problems is only a small part of improving your interview and work capabilities. There is a vast ocean of computer science to explore, and it is not recommended to spend excessive time on problem-solving. To become a proficient computer scientist, treat problem-solving as an entry point while also strengthening your professional foundation, improving your skills, and staying informed about the latest advancements in the field. + +This book was completed during the author’s spare time and may contain errors or areas for improvement. Some problem explanations may lack detail or clarity. Readers are welcome to submit issues on GitHub to help refine the book, and the author will acknowledge your contributions in the acknowledgments section. For suggestions or inquiries, visit the author’s personal website or send a message via email or LinkedIn, and the author will respond promptly. + +Special thanks to GitHub user CyC2018 for their LeetCode problem explanations, which greatly assisted the author in the early stages of this book. Gratitude also goes to ElegantBook for its elegant LATEX template, which made it easy to transform notes into a professional-looking eBook. The cover photo of the second edition was taken by the author in July 2024 at the seaside town of Sausalito, north of the Golden Gate Bridge in San Francisco. Incidentally, the author bought a large three-scoop ice cream cone there, but it was too sweet to finish and had to be discarded. + +If you find this book helpful, consider supporting the author! + + + +## Important Notice + +GitHub repository for this book: [github.com/changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +This book is free of charge and prohibits any commercial use, as its purpose is solely for sharing and teaching. Academic sharing and circulation are welcome. All problem copyrights belong to LeetCode, and this book does not display content or code for LeetCode premium problems. + +## Introduction + +When visiting the LeetCode website, problems can often be categorized by type. The most common categories include arrays, dynamic programming, mathematics, strings, trees, hash maps, depth-first search, binary search, greedy algorithms, breadth-first search, and two pointers. This book covers the above categories and most other popular problem types, while categorizing them by type and difficulty level in a step-by-step manner. + +The first major category is algorithms. This book starts with the simplest greedy algorithms and gradually progresses to two pointers, binary search, sorting algorithms, search algorithms, and finally, more challenging topics such as dynamic programming and divide-and-conquer. + +The second category is mathematics, encompassing problems related to pure mathematics and computer-related topics like bit manipulation. These problems often test intellectual sharpness but are less commonly used in real-world work. The author recommends prioritizing other categories. + +The third category is data structures, including C++ STL, Python3 built-in data structures, string manipulation, linked lists, trees, and graphs. Linked lists are a subset of trees and graphs. The book concludes with an introduction to more advanced data structures like the classic Union-Find and LRU. diff --git a/leetcode_101/i18n/en/docusaurus-theme-classic/footer.json b/leetcode_101/i18n/en/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..a3c09ca8 --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Chang Gao. Built with Docusaurus.", + "description": "The footer copyright" + } +} diff --git a/leetcode_101/i18n/en/docusaurus-theme-classic/navbar.json b/leetcode_101/i18n/en/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..6e59d8ef --- /dev/null +++ b/leetcode_101/i18n/en/docusaurus-theme-classic/navbar.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "LeetCode 101 - A Grinding Guide", + "description": "The title in the navbar" + }, + "logo.alt": { + "message": "My Site Logo", + "description": "The alt text of navbar logo" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + } +} diff --git a/leetcode_101/i18n/zh-TW/code.json b/leetcode_101/i18n/zh-TW/code.json new file mode 100644 index 00000000..a1fe4ce6 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/code.json @@ -0,0 +1,313 @@ +{ + "theme.ErrorPageContent.title": { + "message": "此頁已當機。", + "description": "The title of the fallback page when the page crashed" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "回到頂部", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "歷史文章", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "歷史文章", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "部落格文章列表分頁導覽", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "較新的文章", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "較舊的文章", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "部落格文章分頁導覽", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "較新一篇", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "較舊一篇", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.tags.tagsPageLink": { + "message": "檢視所有標籤", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel": { + "message": "切換淺色/深色模式(當前為{mode})", + "description": "The ARIA label for the navbar color mode toggle" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "深色模式", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "淺色模式", + "description": "The name for the light color mode" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "頁面路徑", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription.plurals": { + "message": "{count} 個項目", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "文件選項卡", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "上一頁", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "下一頁", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "{count} 篇文件帶有標籤", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged}「{tagName}」", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "版本:{versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "此為 {siteTitle} {versionLabel} 版尚未發行的文件。", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "此為 {siteTitle} {versionLabel} 版的文件,現已不再積極維護。", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "最新的文件請參閱 {latestVersionLink} ({versionLabel})。", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "最新版本", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "編輯此頁", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "{heading}的直接連結", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": "於 {date} ", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": "由 {user} ", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "最後{byUser}{atDate}更新", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "選擇版本", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.NotFound.title": { + "message": "找不到頁面", + "description": "The title of the 404 page" + }, + "theme.tags.tagsListLabel": { + "message": "標籤:", + "description": "The label alongside a tag list" + }, + "theme.admonition.caution": { + "message": "警告", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "危險", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "資訊", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "備註", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "提示", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "注意", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "關閉", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "最近部落格文章導覽", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.CodeBlock.copied": { + "message": "複製成功", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "複製程式碼至剪貼簿", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.copy": { + "message": "複製", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "切換自動換行", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "展開側邊欄分類 '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "收起側邊欄分類 '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.NavBar.navAriaLabel": { + "message": "主導航", + "description": "The ARIA label for the main navigation" + }, + "theme.NotFound.p1": { + "message": "我們沒有您要找的頁面。", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "請聯絡原始連結來源網站的所有者,並通知他們連結已毀損。", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "選擇語言", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "本頁導覽", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "閱讀更多", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "閱讀 {title} 全文", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "閱讀時間約 {readingTime} 分鐘", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.breadcrumbs.home": { + "message": "主頁面", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "收起側邊欄", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "收起側邊欄", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "文件側邊欄", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Close navigation bar", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← 回到主選單", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "切換導覽列", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "展開側邊欄", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "展開側邊欄", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.blog.post.plurals": { + "message": "{count} 篇文章", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} 含有標籤「{tagName}」", + "description": "The title of the page for a blog tag" + }, + "theme.blog.author.pageTitle": { + "message": "{authorName} - {nPosts}", + "description": "The title of the page for a blog author" + }, + "theme.blog.authorsList.pageTitle": { + "message": "Authors", + "description": "The title of the authors page" + }, + "theme.blog.authorsList.viewAll": { + "message": "View All Authors", + "description": "The label of the link targeting the blog authors page" + }, + "theme.blog.author.noPosts": { + "message": "This author has not written any posts yet.", + "description": "The text for authors with 0 blog post" + }, + "theme.contentVisibility.unlistedBanner.title": { + "message": "未列出頁", + "description": "The unlisted content banner title" + }, + "theme.contentVisibility.unlistedBanner.message": { + "message": "此頁面未列出。搜索引擎不會對其索引,只有擁有直接連結的用戶才能訪問。", + "description": "The unlisted content banner message" + }, + "theme.contentVisibility.draftBanner.title": { + "message": "Draft page", + "description": "The draft content banner title" + }, + "theme.contentVisibility.draftBanner.message": { + "message": "This page is a draft. It will only be visible in dev and be excluded from the production build.", + "description": "The draft content banner message" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "重試", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "跳至主要内容", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "標籤", + "description": "The title of the tag list page" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current.json new file mode 100644 index 00000000..31dc7343 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,126 @@ +{ + "version.label": { + "message": "Next", + "description": "當前版本的標籤" + }, + "sidebar.tutorialSidebar.category.1. 最易懂的贪心算法": { + "message": "1. 最易懂的貪心演算法", + "description": "The label for category 1. 最易懂的貪心演算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.1. 最易懂的贪心算法.link.generated-index.description": { + "message": "第 1 章 最易懂的貪心演算法", + "description": "The generated-index page description for category 1. 最易懂的貪心演算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.2. 玩转双指针": { + "message": "2. 玩轉雙指針", + "description": "The label for category 2. 玩轉雙指針 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.2. 玩转双指针.link.generated-index.description": { + "message": "第 2 章 玩轉雙指針", + "description": "The generated-index page description for category 2. 玩轉雙指針 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.3. 居合斩!二分查找": { + "message": "3. 居合斬!二分搜尋", + "description": "The label for category 3. 居合斬!二分搜尋 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.3. 居合斩!二分查找.link.generated-index.description": { + "message": "第 3 章 居合斬!二分搜尋", + "description": "The generated-index page description for category 3. 居合斬!二分搜尋 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.4. 千奇百怪的排序算法": { + "message": "4. 千奇百怪的排序演算法", + "description": "The label for category 4. 千奇百怪的排序演算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.4. 千奇百怪的排序算法.link.generated-index.description": { + "message": "第 4 章 千奇百怪的排序演算法", + "description": "The generated-index page description for category 4. 千奇百怪的排序演算法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.5. 一切皆可搜索": { + "message": "5. 一切皆可搜尋", + "description": "The label for category 5. 一切皆可搜尋 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.5. 一切皆可搜索.link.generated-index.description": { + "message": "第 5 章 一切皆可搜尋", + "description": "The generated-index page description for category 5. 一切皆可搜尋 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.6. 深入浅出动态规划": { + "message": "6. 深入淺出的動態規劃", + "description": "The label for category 6. 深入淺出的動態規劃 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.6. 深入浅出动态规划.link.generated-index.description": { + "message": "第 6 章 深入淺出的動態規劃", + "description": "The generated-index page description for category 6. 深入淺出的動態規劃 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.7. 化繁为简的分治法": { + "message": "7. 化繁為簡的分治法", + "description": "The label for category 7. 化繁為簡的分治法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.7. 化繁为简的分治法.link.generated-index.description": { + "message": "第 7 章 化繁為簡的分治法", + "description": "The generated-index page description for category 7. 化繁為簡的分治法 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.8. 巧解数学问题": { + "message": "8. 巧解數學問題", + "description": "The label for category 8. 巧解數學問題 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.8. 巧解数学问题.link.generated-index.description": { + "message": "第 8 章 巧解數學問題", + "description": "The generated-index page description for category 8. 巧解數學問題 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.9. 神奇的位运算": { + "message": "9. 神奇的位元運算", + "description": "The label for category 9. 神奇的位元運算 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.9. 神奇的位运算.link.generated-index.description": { + "message": "第 9 章 神奇的位元運算", + "description": "The generated-index page description for category 9. 神奇的位元運算 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.10. 妙用数据结构": { + "message": "10. 巧用資料結構", + "description": "The label for category 10. 巧用資料結構 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.10. 妙用数据结构.link.generated-index.description": { + "message": "第 10 章 巧用資料結構", + "description": "The generated-index page description for category 10. 巧用資料結構 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.11. 令人头大的字符串": { + "message": "11. 頭痛的字串處理", + "description": "The label for category 11. 頭痛的字串處理 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.11. 令人头大的字符串.link.generated-index.description": { + "message": "第 11 章 頭痛的字串處理", + "description": "The generated-index page description for category 11. 頭痛的字串處理 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.12. 指针三剑客之一:链表": { + "message": "12. 指標三劍客之一:鏈結串列", + "description": "The label for category 12. 指標三劍客之一:鏈結串列 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.12. 指针三剑客之一:链表.link.generated-index.description": { + "message": "第 12 章 指標三劍客之一:鏈結串列", + "description": "The generated-index page description for category 12. 指標三劍客之一:鏈結串列 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.13. 指针三剑客之二:树": { + "message": "13. 指標三劍客之二:樹", + "description": "The label for category 13. 指標三劍客之二:樹 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.13. 指针三剑客之二:树.link.generated-index.description": { + "message": "第 13 章 指標三劍客之二:樹", + "description": "The generated-index page description for category 13. 指標三劍客之二:樹 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.14. 指针三剑客之三:图": { + "message": "14. 指標三劍客之三:圖", + "description": "The label for category 14. 指標三劍客之三:圖 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.14. 指针三剑客之三:图.link.generated-index.description": { + "message": "第 14 章 指標三劍客之三:圖", + "description": "The generated-index page description for category 14. 指標三劍客之三:圖 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.15. 更加复杂的数据结构": { + "message": "15. 更加複雜的資料結構", + "description": "The label for category 15. 更加複雜的資料結構 in sidebar tutorialSidebar" + }, + "sidebar.tutorialSidebar.category.15. 更加复杂的数据结构.link.generated-index.description": { + "message": "第 15 章 更加複雜的資料結構", + "description": "The generated-index page description for category 15. 更加複雜的資料結構in sidebar tutorialSidebar" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md new file mode 100644 index 00000000..fed844c7 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-1-algorithm-explanation.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 1 +--- + +# 1.1 算法解釋 + +顧名思義,`貪心算法或貪心思想`(greedy algorithm)採用貪心的策略,`保證每次操作都是局部最優的`,從而使最後得到的結果是`全局最優的`。 + +舉一個最簡單的例子:小明和小王喜歡吃蘋果,小明可以吃五個,小王可以吃三個。已知蘋果園裡有吃不完的蘋果,求小明和小王一共最多吃多少個蘋果。在這個例子中,我們可以選用的貪心策略為,每個人吃自己能吃的最多數量的蘋果,這在每個人身上都是局部最優的。又因為全局結果是局部結果的簡單求和,且局部結果互不相干,因此局部最優的策略同樣是全局最優的。 + +證明一道題能用貪心算法解決,有時遠比用貪心算法解決該題更複雜。一般情況下,在簡單操作後,具有明顯的從局部到整體的遞推關係,或者可以通過數學歸納法推測結果時,我們才會使用貪心算法。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx new file mode 100644 index 00000000..f38b39ac --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-2-assignment-problems.mdx @@ -0,0 +1,163 @@ +--- +sidebar_position: 2 +--- + +# 1.2 分配問題 + +## [455. Assign Cookies](https://leetcode.com/problems/assign-cookies/) + +### 題目描述 + +有一群孩子和一堆餅乾,每個孩子有一個飢餓度,每個餅乾都有一個飽腹度。每個孩子只能吃一個餅乾,且只有餅乾的飽腹度不小於孩子的飢餓度時,這個孩子才能吃飽。求解最多有多少孩子可以吃飽。 + +### 輸入輸出範例 + +輸入兩個陣列,分別代表孩子的飢餓度和餅乾的飽腹度。輸出可以吃飽的孩子的最大數量。 + +``` +Input: [1,2], [1,2,3] +Output: 2 +``` + +在這個範例中,我們可以給兩個孩子餵 [1,2]、[1,3]、[2,3] 這三種組合的任意一種。 + +### 題解 + +因為飢餓度最小的孩子最容易吃飽,所以我們先考慮這個孩子。為了盡量使得剩下的餅乾可以滿足飢餓度更大的孩子,我們應該把大於等於這個孩子飢餓度的、且大小最小的餅乾給這個孩子。滿足了這個孩子之後,我們採取同樣的策略,考慮剩下孩子裡飢餓度最小的孩子,直到沒有滿足條件的餅乾存在。 + +簡而言之,這裡的貪心策略是,給剩餘孩子裡最小飢餓度的孩子分配最小的能飽腹的餅乾。至於具體實現,因為我們需要獲得大小關係,一個便捷的方法就是把孩子和餅乾分別排序。這樣我們就可以從飢餓度最小的孩子和飽腹度最小的餅乾出發,計算有多少個配對可以滿足條件。 + +:::warning + +對陣列或字符串排序是常見的操作,方便之後的大小比較。排序順序默認是從小到大。 + +::: + +:::warning + +在之後的講解中,若我們談論的是對連續空間的變量進行操作,我們並不會明確區分陣列和字符串,因為它們本質上都是在連續空間上的有序變量集合。一個字符串 "abc" 可以被看作一個陣列 ['a', 'b', 'c']。 + +::: + + + + +```cpp +int findContentChildren(vector &children, vector &cookies) { + sort(children.begin(), children.end()); + sort(cookies.begin(), cookies.end()); + int child_i = 0, cookie_i = 0; + int n_children = children.size(), n_cookies = cookies.size(); + while (child_i < n_children && cookie_i < n_cookies) { + if (children[child_i] <= cookies[cookie_i]) { + ++child_i; + } + ++cookie_i; + } + return child_i; +} +``` + + + + +```py +def findContentChildren(children: List[int], cookies: List[int]) -> int: + children.sort() + cookies.sort() + child_i, cookie_i = 0, 0 + n_children, n_cookies = len(children), len(cookies) + while child_i < n_children and cookie_i < n_cookies: + if children[child_i] <= cookies[cookie_i]: + child_i += 1 + cookie_i += 1 + return child_i +``` + + + + + +### 複雜度分析 + +- **時間複雜度**:排序的時間為 $O(n \log n)$,雙指針遍歷的時間為 $O(n)$,因此總時間複雜度為: + $$ + O(n_{\text{children}} \log n_{\text{children}} + n_{\text{cookies}} \log n_{\text{cookies}}) + $$ +- **空間複雜度**:排序需要額外的 $O(n)$ 空間,總空間複雜度為: + $$ + O(n_{\text{children}} + n_{\text{cookies}}) + $$ + +## [135. Candy](https://leetcode.com/problems/candy/) + +### 題目描述 + +一群孩子站成一排,每一個孩子有自己的評分。現在需要給這些孩子發糖果,規則是如果一個孩子的評分比自己身旁的一個孩子要高,那麼這個孩子就必須得到比身旁孩子更多的糖果。所有孩子至少要有一個糖果。求解最少需要多少個糖果。 + +### 輸入輸出範例 + +輸入是一個陣列,表示孩子的評分。輸出是最少糖果的數量。 + +``` +Input: [1,0,2] +Output: 5 +``` +在這個範例中,最少的糖果分配方式是 [2,1,2]。 + + +### 題解 + +存在比較關係的貪心策略並不一定需要排序。雖然這一道題也是運用貪心策略,但我們只需要簡單的兩次遍歷即可:把所有孩子的糖果數初始化為 1;先從左往右遍歷一遍,如果右邊孩子的評分比左邊的高,則右邊孩子的糖果數更新為左邊孩子的糖果數加 1;再從右往左遍歷一遍,如果左邊孩子的評分比右邊的高,且左邊孩子當前的糖果數不大於右邊孩子的糖果數,則左邊孩子的糖果數更新為右邊孩子的糖果數加 1。通過這兩次遍歷,分配的糖果就可以滿足題目要求了。這裡的貪心策略即為,在每次遍歷中,只考慮並更新相鄰一側的大小關係。 + +在範例中,我們初始化糖果分配為 [1,1,1],第一次遍歷更新後的結果為 [1,1,2],第二次遍歷更新後的結果為 [2,1,2]。 + + + + +```cpp +int candy(vector& ratings) { + int n = ratings.size(); + vector candies(n, 1); + for (int i = 1; i < n; ++i) { + if (ratings[i] > ratings[i - 1]) { + candies[i] = candies[i - 1] + 1; + } + } + for (int i = n - 1; i > 0; --i) { + if (ratings[i] < ratings[i - 1]) { + candies[i - 1] = max(candies[i - 1], candies[i] + 1); + } + } + return accumulate(candies.begin(), candies.end(), 0); +} +``` + + + + +```py +def candy(ratings_list: List[int]) -> int: + n = len(ratings_list) + candies = [1] * n + for i in range(1, n): + if ratings_list[i] > ratings_list[i - 1]: + candies[i] = candies[i - 1] + 1 + for i in range(n - 1, 0, -1): + if ratings_list[i] < ratings_list[i - 1]: + candies[i - 1] = max(candies[i - 1], candies[i] + 1) + return sum(candies) +``` + + + + + +### 複雜度分析 + +- 時間複雜度 + - 從左到右遍歷和從右到左遍歷各需花費 $O(n)$ 的時間。 + - 總時間複雜度為 $O(n)$。 + +- 空間複雜度 + - 使用一個額外的陣列 `candies` 來儲存每個小孩的糖果數量,因此空間複雜度為 $O(n)$。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx new file mode 100644 index 00000000..afa70919 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-3-interval-problems.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 3 +--- + +# 1.3 區間問題 + +## [435. Non-overlapping Intervals](https://leetcode.com/problems/non-overlapping-intervals/) + +### 題目描述 + +給定多個區間,計算讓這些區間互不重疊所需要移除的最少區間數量。起止相連的區間不算重疊。 + +### 輸入輸出範例 + +輸入是一個陣列,包含多個長度固定為 2 的子陣列,表示每個區間的開始和結束。輸出是一個整數,表示需要移除的區間數量。 + + +``` +Input: [[1,2], [2,4], [1,3]] +Output: 1 +``` +在這個範例中,我們可以移除區間 [1,3],使得剩餘的區間 [[1,2], [2,4]] 互不重疊。 + + +### 題解 + +求最少移除的區間數量等同於盡量多保留不重疊的區間。在選擇要保留的區間時,區間的結尾非常重要:選擇的區間結尾越小,留給其他區間的空間就越大,這樣就能保留更多的區間。因此,我們的貪心策略是優先保留結尾小且不相交的區間。 + +具體實現方法為,先把區間按照結尾的大小進行增序排序(利用 lambda 函數),每次選擇結尾最小且與前一個選擇的區間不重疊的區間。 + +在範例中,排序後的陣列為 [[1,2], [1,3], [2,4]]。按照我們的貪心策略,首先初始化為區間 [1,2];由於 [1,3] 與 [1,2] 相交,我們跳過該區間;由於 [2,4] 與 [1,2] 不相交,我們將其保留。因此,最終保留的區間為 [[1,2], [2,4]]。 + +:::warning + +需要根據實際情況判斷按區間開頭排序還是按區間結尾排序。 + +::: + + + + +```cpp +int eraseOverlapIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end(), + [](vector& a, vector& b) { return a[1] < b[1]; }); + int removed = 0, prev_end = intervals[0][1]; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[i][0] < prev_end) { + ++removed; + } else { + prev_end = intervals[i][1]; + } + } + return removed; +} +``` + + + + +```py +def eraseOverlapIntervals(intervals: List[List[int]]) -> int: + intervals.sort(key=lambda x: x[1]) + removed, prev_end = 0, intervals[0][1] + for i in range(1, len(intervals)): + if prev_end > intervals[i][0]: + removed += 1 + else: + prev_end = intervals[i][1] + return removed +``` + + + + + +### 複雜度分析 + +- **時間複雜度** + - 將區間依照結束時間進行排序需花費 $O(n \log n)$ 的時間。 + - 遍歷排序後的區間需花費 $O(n)$ 的時間。 + - 總時間複雜度為 $O(n \log n)$。 + +- **空間複雜度** + - 排序操作可能需要 $O(n)$ 的額外空間(基於 Timsort 實現)。 + - 其他變數(如 `removed` 和 `prev_end`)僅需 $O(1)$ 空間。 + - 總空間複雜度為 $O(n)$。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md new file mode 100644 index 00000000..832a207a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/1-4-exercises.md @@ -0,0 +1,252 @@ +--- +sidebar_position: 4 +--- + +# 1.4 練習 + +## 基礎難度 + +### [605. Can Place Flowers](https://leetcode.com/problems/can-place-flowers/) + +採取什麼樣的貪心策略,可以種植最多的花朵呢? + +
+ 題解 + +#### 解題思路 + +1. **問題轉換**: + 為簡化邊界判斷,在花圃兩端添加虛擬位置 `0`。 + +2. **遍歷邏輯**: + - 對每個位置,檢查當前位置為 `0` 且左右兩側也為 `0` 時,可種植一朵花。 + - 種花後將位置設為 `1` 並將 `n` 減 1。 + +3. **最終判斷**: + 程式遍歷完後檢查 `n` 是否小於等於 `0`,返回結果。 + + + ```py + class Solution: + def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: + flowerbed = [0] + flowerbed + [0] + for i, f in enumerate(flowerbed[1:-1],start=1): + if f == 0 and flowerbed[i-1] == 0 and flowerbed[i+1] == 0: + n -= 1 + flowerbed[i] = 1 + return n <= 0 + ``` + +#### 複雜度分析 + +- **時間複雜度**: 主迴圈遍歷了 `flowerbed` 的所有元素一次,因此時間複雜度為 $O(m)$,其中 $m$ 是 `flowerbed` 的長度。 + +- **空間複雜度**: 程式在 `flowerbed` 兩端添加了額外的元素,佔用固定的額外空間,因此空間複雜度為 $O(1)$。 + +
+ +--- + +### [452. Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) + +這道題和題目 435 十分類似,但是稍有不同,具體是哪裡不同呢? + +
+ 題解 + +#### 解題思路 + +- 將所有氣球根據右邊界進行升序排序。 +- 初始化箭數 `arrows` 為 1,並記錄第一支箭射出的右邊界 `end`。 +- 遍歷所有氣球: + - 如果當前氣球的左邊界大於 `end`,表示需要新增一支箭,更新 `end` 為當前氣球的右邊界。 +- 返回箭數 `arrows`。 + +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + points.sort(key=lambda x: x[1]) # 根據右邊界排序 + arrows = 1 + end = points[0][1] + + for x_start, x_end in points[1:]: + if x_start > end: # 氣球不重疊,需要新箭 + arrows += 1 + end = x_end + + return arrows +``` + +#### 複雜度分析 +- **時間複雜度**: $O(n \log n)$,其中 $n$ 是氣球數量,排序操作為主要開銷。 + +- **空間複雜度**: $O(1)$,除了排序使用的額外空間外,程式只使用了常數額外空間。 + +
+ +--- + +### [763. Partition Labels](https://leetcode.com/problems/partition-labels/) + +為了滿足你的貪心策略,是否需要一些預處理? + +:::warning + +在處理陣列前,統計一遍訊息(如頻率、個數、第一次出現位置、最後一次出現位置等)可以使題目難度大幅降低。 + +::: + +
+ 題解 + +#### 解題思路 + +- 計算每個字符最後出現的位置,記錄為 `last` 字典。 +- 遍歷字符串,維護當前區間的右邊界 `end`,初始為 `0`,並記錄區間起點 `start`。 +- 當遍歷到的字符的最後出現位置超過當前的 `end` 時,更新 `end`。 +- 如果當前索引等於 `end`,表示找到了一個劃分區間,將區間長度加入結果列表,並將 `start` 更新為下一個字符的起點。 + +```python +class Solution: + def partitionLabels(self, s: str) -> List[int]: + last = {char: i for i, char in enumerate(s)} # 記錄每個字符的最後出現位置 + partitions = [] + start = end = 0 + + for i, char in enumerate(s): + end = max(end, last[char]) # 更新當前區間的右邊界,保證當前區間覆蓋所有字符的最後出現位置 + if i == end: # 當前索引等於區間右邊界,完成一個區間 + partitions.append(end - start + 1) + start = i + 1 # 更新下一區間的起點 + + return partitions +``` + +#### 複雜度分析 +- **時間複雜度**: $O(n)$,其中 $n$ 是字符串的長度,遍歷字符串兩次,一次建立字典,一次劃分區間。 + +- **空間複雜度**: $O(1)$,只使用了固定大小的字典和變數來儲存訊息。 + +
+ +--- + +### [122. Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) + +股票交易題型裡比較簡單的題目,在不限制交易次數的情況下,怎樣可以獲得最大利潤呢? + +
+ 題解 + +#### 解題思路 + +- 本題目允許多次交易(先買後賣),目標是最大化利潤。 +- **貪婪算法 (Greedy)**: + - 對於每一天,如果當天的價格高於前一天,就進行一次交易,將差值加入總利潤。 + - 本質上等價於抓住所有上升區間的收益。 +- 不需要記錄實際的交易,只需累加所有價格上升的差值。 + +```python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(1, len(prices)): + if prices[i] > prices[i - 1]: + profit += prices[i] - prices[i - 1] + return profit +``` + +#### 複雜度分析 +- **時間複雜度**: $O(n)$,其中 $n$ 是 prices 的長度,需遍歷整個價格列表一次。 + +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +
+ +--- + +## 進階難度 + +### [406. Queue Reconstruction by Height](https://leetcode.com/problems/queue-reconstruction-by-height/) + +溫馨提示,這道題可能同時需要排序和插入操作。 + +
+ 題解 + +#### 解題思路 + +- **問題描述**: + 給定一組 `(h, k)` 人物對,其中 `h` 是身高,`k` 是在這個人前面身高至少與他相同的人數。根據這些條件,重建排列隊列。 + +- **貪婪算法**: + - 將所有人按照 **身高降序** 和 **k 值升序** 排序。 + - 初始化一個空隊列,依次將排序後的人插入隊列的第 `k` 個位置。 + - 由於身高越高的人已經插入,他們對後續的插入順序不產生影響。 + +```python +class Solution: + def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: + # 按身高降序,k 值升序排序 + people.sort(key=lambda x: (-x[0], x[1])) + queue = [] + for person in people: + queue.insert(person[1], person) + return queue +``` + +#### 複雜度分析 +- **時間複雜度**: $O(n^2)$,其中 $n$ 是 people 的長度。 + - 排序需要 $O(n \log n)$。 + - 插入操作在最壞情況下需要 $O(n^2)$。 + +- **空間複雜度**: $O(n)$,用於儲存重建的隊列。 +
+ +--- + +### [665. Non-decreasing Array](https://leetcode.com/problems/non-decreasing-array/) + +需要仔細思考你的貪心策略在各種情況下,是否仍然是最優解。 + +
+ 題解 + +#### 解題思路 + +- **問題描述**: + 確認是否可以最多修改一個元素,讓整個陣列成為非遞減(每個元素小於或等於後一個元素)。 + +- **關鍵點**: + - 遍歷陣列時檢查是否有不符合非遞減的地方(即 `nums[i] > nums[i+1]`)。 + - 每次遇到不符合的情況: + - 嘗試修改 `nums[i]` 或 `nums[i+1]`,使整體保持非遞減。 + - 如果已經修改過一次,再次出現問題時直接返回 `False`。 + +- **修改策略**: + - 如果 `nums[i-1] <= nums[i+1]`,將 `nums[i]` 修改為 `nums[i+1]`。 + - 否則,將 `nums[i+1]` 修改為 `nums[i]`。 + +```python +class Solution: + def checkPossibility(self, nums: List[int]) -> bool: + modified = False # 是否已經修改過一次 + for i in range(len(nums) - 1): + if nums[i] > nums[i + 1]: # 發現不符合非遞減的情況 + if modified: # 已經修改過一次 + return False + # 嘗試修改 + if i == 0 or nums[i - 1] <= nums[i + 1]: + nums[i] = nums[i + 1] # 修改 nums[i] + else: + nums[i + 1] = nums[i] # 修改 nums[i+1] + modified = True # 標記已修改 + return True +``` + +#### 複雜度分析 +- **時間複雜度**: $O(n)$,其中 $n$ 是陣列的長度,只需遍歷陣列一次。 + +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +
\ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json new file mode 100644 index 00000000..ef63db0a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/1-greedy-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "1. 最易懂的貪心演算法", + "position": 1, + "link": { + "type": "generated-index", + "description": "第 1 章 最易懂的貪心演算法" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md new file mode 100644 index 00000000..93d6c374 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-1-cpp-stl.md @@ -0,0 +1,33 @@ +--- +sidebar_position: 48 +--- + +# 10.1 C++ STL + +在刷題時,我們幾乎一定會用到各種資料結構來輔助我們解決問題,因此我們必須熟悉各種資料結構的特點。C++ STL 提供的資料結構包括(實際底層細節可能因編譯器而異): + +1. **順序容器(Sequence Containers)**:維持順序的容器。 + 1. **vector**:`動態陣列`,是我們最常使用的資料結構之一,用於 $O(1)$ 的隨機讀取。因為大部分演算法的時間複雜度會大於 $O(n)$,因此我們經常新建 vector 來儲存各種資料或中間變數。由於在尾部增刪的複雜度是 $O(1)$,我們也可以把它當作 stack 來用。 + 2. **list**:`雙向鏈結串列`,也可以當作 stack 和 queue 來使用。由於 LeetCode 的題目多用 Node 來表示鏈結串列,且鏈結串列不支援快速隨機讀取,因此我們很少用到這個資料結構。一個例外是經典的 LRU 問題,我們需要利用鏈結串列的特性來解決,我們在後文會遇到這個問題。 + 3. **deque**:雙端佇列,這是一個非常強大的資料結構,既支援 $O(1)$ 隨機讀取,又支援 $O(1)$ 時間的頭部增刪和尾部增刪(因此可以當作 stack 和 queue 來使用),不過有一定的額外開銷。也可以用來近似一個雙向鏈結串列來使用。 + 4. **array**:固定大小的陣列,一般在刷題時我們不使用。 + 5. **forward_list**:單向鏈結串列,一般在刷題時我們不使用。 +2. **容器適配器(Container Adaptors)**:基於其他容器實現的容器。 + 1. **stack**:`後進先出(LIFO)的資料結構`,預設基於 deque 實現。stack 常用於深度優先搜尋、一些字串匹配問題以及單調堆疊問題。 + 2. **queue**:`先進先出(FIFO)的資料結構`,預設基於 deque 實現。queue 常用於廣度優先搜尋。 + 3. **priority_queue**:`優先佇列(最大值先出的資料結構)`,預設基於 vector 實現堆結構。它可以在 $O(n \log n)$ 的時間排序陣列,$O(\log n)$ 的時間插入任意值,$O(1)$ 的時間獲得最大值,$O(\log n)$ 的時間刪除最大值。priority_queue 常用於維護資料結構並快速獲取最大值,並且可以自定義比較函數;比如通過儲存負值或者更改比較函數,即可實現最小值先出。 + +3. **有序關聯容器(Ordered Associative Containers)**:有序的關聯容器。 + 1. **set**:有序集合,元素不可重複,底層實現預設為紅黑樹,即一種特殊的二元搜尋樹(BST)。它可以在 $O(n \log n)$ 的時間排序陣列,$O(\log n)$ 的時間插入、刪除、查找任意值,$O(\log n)$ 的時間獲得最小或最大值。需要注意的是,set 和 priority_queue 都可以用於維護資料結構並快速獲取最大最小值,但它們的時間複雜度和功能略有區別,如 priority_queue 預設不支援刪除任意值,而 set 獲得最大或最小值的時間複雜度略高,具體使用哪個取決於需求。 + 2. **multiset**:支援重複元素的 set。 + 3. **map**:`有序映射或有序表`,在 set 的基礎上增加映射關係,可以對每個元素 key 存一個值 value。 + 4. **multimap**:支援重複元素的 map。 + +4. **無序關聯容器(Unordered Associative Containers)**:無序的關聯容器。 + 1. **unordered_set**:`雜湊集合`,可以在 $O(1)$ 的時間快速插入、查找、刪除元素,常用於快速判斷某元素是否在容器內。 + 2. **unordered_multiset**:支援重複元素的 unordered_set。 + 3. **unordered_map**:`雜湊映射或雜湊表`,在 unordered_set 的基礎上增加映射關係,可以對每一個元素 key 存一個值 value。在某些情況下,如果 key 的範圍已知且較小,我們也可以用 vector 代替 unordered_map,用位置表示 key,用每個位置的值表示 value。 + 4. **unordered_multimap**:支援重複元素的 unordered_map。 + +由於這並不是一本講解 C++ 原理的書,更多的 STL 細節請讀者自行搜尋。只有理解了這些資料結構的原理和使用方法,才能更輕鬆地解決算法和資料結構問題。 + diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx new file mode 100644 index 00000000..3d06fcfa --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-10-prefix-sum-integral-image.mdx @@ -0,0 +1,226 @@ +--- +sidebar_position: 57 +--- + +# 10.10 前綴和與積分圖 + +一維的前綴和(cumulative sum, cumsum),二維的積分圖(summed-area table, image integral)是通過將每個位置之前的一維線段或二維矩形的數值預先計算並儲存,從而加速後續的查詢與計算。如果需要對前綴和或積分圖的值進行查找,可以將其存入雜湊表;如果需要對每個位置記錄前綴和或積分圖的值,則可以將其儲存到一維或二維數組中,通常還伴隨著動態規劃。 + +## [303. Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable/) + +### 題目描述 + +設計一個資料結構,使得其能夠快速查詢給定陣列中任意兩個位置間所有數字的總和。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。 + +``` +vector nums{-2,0,3,-5,2,-1}; +NumArray num_array = new NumArray(nums); +num_array.sumRange(0,2); // Result = -2+0+3 = 1. +num_array.sunRange(1,5); // Result = 0+3-5+2-1 = -1. +``` + +### 題解 + +對於一維的陣列,我們可以使用前綴和來解決此類問題。先建立一個與陣列 `nums` 長度相同的新陣列 `cumsum`,表示 `nums` 每個位置之前所有數字的總和。`cumsum` 陣列可以通過 C++ 自帶的 `partial_sum` 函數建立,也可以直接遍歷一遍 `nums` 陣列,並利用狀態轉移方程 `cumsum[i] = cumsum[i-1] + nums[i]` 完成統計。如果我們需要獲得位置 `i` 和 `j` 之間的數字和,只需計算 `cumsum[j+1] - cumsum[i]` 即可。 + + + + +```cpp +class NumArray { + public: + NumArray(vector nums) : cumsum_(nums.size() + 1, 0) { + partial_sum(nums.begin(), nums.end(), cumsum_.begin() + 1); + } + + int sumRange(int left, int right) { + return cumsum_[right + 1] - cumsum_[left]; + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class NumArray: + def __init__(self, nums: List[int]): + self.cumsum = [0] + nums[:] + for i in range(2, len(self.cumsum)): + self.cumsum[i] += self.cumsum[i - 1] + + def sumRange(self, left: int, right: int) -> int: + return self.cumsum[right + 1] - self.cumsum[left] +``` + + + + + +## [304. Range Sum Query 2D - Immutable](https://leetcode.com/problems/range-sum-query-2d-immutable/) + +### 題目描述 + +設計一個資料結構,使得其能夠快速查詢給定矩陣中,任意兩個位置包圍的長方形中所有數字的總和。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。其中 `sumRegion` 函數的四個輸入分別是第一個點的橫、縱坐標,和第二個點的橫、縱坐標。 + +``` +vector matrix{{3,0,1,4,2}, + {5,6,3,2,1}, + {1,2,0,1,5}, + {4,1,0,1,7}, + {1,0,3,0,5} +}; +NumMatrix num_matrix = new NumMatrix(matrix); +num_matrix.sumRegion(2,1,4,3); // Result = 8. +num_matrix.sumRegion(1,1,2,2); // Result = 11. +``` + +### 題解 + +類似於前綴和,我們可以把這種思想拓展到二維,即積分圖(summed-area table, image integral)。我們可以先建立一個 `sat` 矩陣,`sat[i][j]` 表示以位置 `(0, 0)` 為左上角、位置 `(i-1, j-1)` 為右下角的長方形中所有數字的總和。 + +
+ + ![](10.4.png) + +
圖 10.4: 題目 304 - 圖 1 - 左邊為給定矩陣,右邊為積分圖結果,右下角位置的積分圖值為 5+48+45−40 = 58
+
+ + +
+ + ![](10.5.png) + +
圖 10.5: 題目 304 - 圖 2 - 左邊為給定矩陣,右邊為積分圖結果,長方形 E 的數字總和等於 58 − 11 − 13 + 3 = 37
+
+ +如圖 1 所示,我們可以用動態規劃來計算 `sat` 矩陣:`sat[i][j] = matrix[i-1][j-1] + sat[i-1][j] + sat[i][j-1] - sat[i-1][j-1]`,即當前座標的數字 + 上面長方形的數字總和 + 左邊長方形的數字總和 - 上面長方形和左邊長方形重疊區域(即左上一格的長方形)中的數字總和。 + +如圖 2 所示,假設我們要查詢長方形 E 的數字總和,因為 `E = D − B − C + A`,我們發現 E 其實可以由四個位置的積分圖結果進行加減運算得到。因此這個演算法在預處理時的時間複雜度為 $O(mn)$,而在查詢時的時間複雜度僅為 $O(1)$。 + + + + +```cpp +class NumMatrix { + public: + NumMatrix(vector> matrix) { + int m = matrix.size(), n = matrix[0].size(); + sat_ = vector>(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + sat_[i][j] = matrix[i - 1][j - 1] + sat_[i - 1][j] + + sat_[i][j - 1] - sat_[i - 1][j - 1]; + } + } + } + + int sumRegion(int row1, int col1, int row2, int col2) { + return sat_[row2 + 1][col2 + 1] - sat_[row2 + 1][col1] - + sat_[row1][col2 + 1] + sat_[row1][col1]; + } + + private: + vector> sat_; +}; +``` + + + + +```py +class NumMatrix: + def __init__(self, matrix: List[List[int]]): + m, n = len(matrix), len(matrix[0]) + self.sat = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + self.sat[i][j] = ( + matrix[i - 1][j - 1] + + self.sat[i - 1][j] + + self.sat[i][j - 1] + - self.sat[i - 1][j - 1] + ) + + def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int: + return ( + self.sat[row2 + 1][col2 + 1] + - self.sat[row2 + 1][col1] + - self.sat[row1][col2 + 1] + + self.sat[row1][col1] + ) + +``` + + + + + +## [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) + +### 題目描述 + +給定一個陣列,尋找和為 $k$ 的連續子陣列個數。 + +### 輸入輸出範例 + +輸入是一維整數陣列和一個整數值 $k$;輸出是一個整數,表示滿足條件的連續子陣列個數。 + +``` +Input: nums = [1,1,1], k = 2 +Output: 2 +``` + +在這個範例中,我們可以找到兩個 [1,1] 連續子陣列滿足條件。 + +### 題解 + +本題同樣是利用前綴和,不同的是這裡我們使用一個雜湊表 `cache`,其鍵是前綴和,而值是該前綴和出現的次數。在我們遍歷到位置 $i$ 時,假設當前的前綴和是 `cumsum`,那麼 `cache[cumsum-k]` 即為以當前位置結尾、滿足條件的子陣列個數。 + + + + +```cpp +int subarraySum(vector& nums, int k) { + int count = 0, cumsum = 0; + unordered_map cache; // + cache[0] = 1; + for (int num : nums) { + cumsum += num; + count += cache[cumsum - k]; + ++cache[cumsum]; + } + return count; +} +``` + + + + +```py +def subarraySum(nums: List[int], k: int) -> int: + count, cur_sum = 0, 0 + cache = {0: 1} # + for num in nums: + cur_sum += num + count += cache.get(cur_sum - k, 0) + cache[cur_sum] = cache.get(cur_sum, 0) + 1 + return count +``` + + + + + diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md new file mode 100644 index 00000000..66bbb482 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-11-exercises.md @@ -0,0 +1,73 @@ +--- +sidebar_position: 58 +--- + +# 10.11 練習 + +## 基礎難度 + +### [566. Reshape the Matrix](https://leetcode.com/problems/reshape-the-matrix/) + +這題沒什麼難度,只是需要耐心操作。 + +--- + +### [225. Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues/) + +使用類似的方式,我們也可以用佇列(queue)實現堆疊(stack)。 + +--- + +### [503. Next Greater Element II](https://leetcode.com/problems/next-greater-element-ii/) + +`Daily Temperatures` 的變種題。 + +--- + +### [217. Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) + +使用什麼資料結構可以快速判斷是否有重複呢? + +--- + +### [697. Degree of an Array](https://leetcode.com/problems/degree-of-an-array/) + +如何對陣列進行預處理,才能正確且快速計算子陣列的長度? + +--- + +### [594. Longest Harmonious Subsequence](https://leetcode.com/problems/longest-harmonious-subsequence/) + +`最長連續序列` 的變種題。 + +--- + +### [15. 3Sum](https://leetcode.com/problems/3sum/) + +因為排序的複雜度是 $O(n \log n) < O(n^2)$,我們既可以先排序後再進行 $O(n^2)$ 的指針搜尋,也可以直接利用雜湊表進行 $O(n^2)$ 的搜尋。 + +--- + +## 進階難度 + +### [287. Find the Duplicate Number](https://leetcode.com/problems/find-the-duplicate-number/) + +`尋找丟失的數字` 的變種題。除了標記負值的方法,你是否有其它算法來解決這個問題? + +--- + +### [313. Super Ugly Number](https://leetcode.com/problems/super-ugly-number/) + +嘗試使用優先佇列來解決這個問題。 + +--- + +### [870. Advantage Shuffle](https://leetcode.com/problems/advantage-shuffle/) + +如果我們需要比較大小關係,而且同一數字可能出現多次,那麼應該使用什麼資料結構呢? + +--- + +### [307. Range Sum Query - Mutable](https://leetcode.com/problems/range-sum-query-mutable/) + +`前綴和` 的變種題。好吧我承認,這題可能稍微超出範圍,你或許需要搜索一下什麼是`線段樹`。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md new file mode 100644 index 00000000..d64c1bee --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-2-python-data-structures.md @@ -0,0 +1,24 @@ +--- +sidebar_position: 49 +--- + +# 10.2 Python 常用資料結構 + +類似於 C++ STL,Python 也提供了許多資料結構(實際底層實作細節可能因編譯器而異): + +1. **順序容器**:維持順序的容器。 + 1. **list**:`動態陣列`,是我們最常用的資料結構之一,適合用於 $O(1)$ 的隨機存取。由於大多數演算法的時間複雜度會大於 $O(n)$,我們經常建立 list 來儲存各種資料或中間結果。因為尾部的新增或移除操作有 $O(1)$ 的複雜度,我們也可以將其當作堆疊(stack)使用。 + 2. **tuple**:不可變的陣列,無法更改其中的元素或總長度。 + 3. **collections.deque**:`雙端佇列`,是一種功能強大的資料結構,支援 $O(1)$ 的隨機存取,也支援 $O(1)$ 時間的頭尾新增或移除操作(因此可作為堆疊或佇列使用)。但它有些額外開銷,也可用來模擬雙向鏈結串列。 + +2. **容器適配器**:基於其他容器實作的容器。 + 1. **heapq**:`最小堆`(最小值優先的資料結構),基於 list 實作的堆結構。它支援在 $O(n \log n)$ 時間內排序陣列,$O(\log n)$ 時間插入任意值,$O(1)$ 時間獲取最小值,$O(\log n)$ 時間移除最小值。`heapq` 常用於維持資料結構並快速獲取最小值,但不支援自定義比較函式。因此,通常需要預先計算自定義值,並將 (自定義值, 索引) 的 tuple 儲存於 heapq 中,進行比較時會優先比較自定義值,若相同則比較插入順序。 + +3. **有序關聯容器**: + 1. **collections.OrderedDict**:`順序映射或順序表`,注意這裡的 Ordered 與 C++ 中 map 的按大小排序不同,而是按照插入的先後順序排序。`OrderedDict` 非常適合用來實現 LRU(最近最少使用)。 +4. **無序關聯容器**: + 1. **set**:`雜湊集合`,可以在 $O(1)$ 的時間內快速插入、查詢和刪除元素,常用於快速查詢某個元素是否存在於容器中。 + 2. **dict**:`雜湊映射或雜湊表`,在 set 的基礎上增加了鍵值對的映射關係,可以對每個鍵(key)儲存對應的值(value)。在某些情況下,如果鍵的範圍已知且較小,我們也可以用 list 代替 dict,用索引位置表示鍵,用每個位置的值表示對應的值。 + 3. **collections.Counter**:`計數器`,是 dict 的一種特殊版本,可以直接傳入一個 list,並對其中的每個元素進行計數統計,鍵為元素值,值為該元素出現的頻次。可以用來作為多重集合。 + +同樣地,因為這並不是一本講解 Python 原理的書,更多的資料結構細節請讀者自行搜索。只有理解這些資料結構的原理和使用方法,才能夠更加游刃有餘地解決算法和資料結構問題。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx new file mode 100644 index 00000000..d7628808 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-3-arrays.mdx @@ -0,0 +1,248 @@ +--- +sidebar_position: 50 +--- + +# 10.3 陣列 + +## [448. Find All Numbers Disappeared in an Array](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/) + +### 題目描述 + +給定一個長度為 n 的陣列,其中包含範圍為 1 到 n 的整數,有些整數重複出現多次,有些整數沒有出現,求 1 到 n 中沒有出現過的整數。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,輸出也是一個一維整數陣列,表示輸入陣列中沒出現過的數字。 + +``` +Input: [4,3,2,7,8,2,3,1] +Output: [5,6] +``` + +利用陣列這種資料結構建立 n 個桶,把所有重複出現的位置進行標記,然後再遍歷一遍陣列,即可找到沒有出現過的數字。進一步地,我們可以直接對原陣列進行標記:把重複出現的數字在原陣列的位置設為負數(這裡負數的目的是把 1 到 n 的數字映射到 0 到 n-1 的位置),最後仍然為正數的位置即為沒有出現過的數。 + +### 題解 + + + + +```cpp +vector findDisappearedNumbers(vector& nums) { + vector disappeared; + for (int num : nums) { + int pos = abs(num) - 1; + if (nums[pos] > 0) { + nums[pos] = -nums[pos]; + } + } + for (int i = 0; i < nums.size(); ++i) { + if (nums[i] > 0) { + disappeared.push_back(i + 1); + } + } + return disappeared; +} +``` + + + + +```py +def findDisappearedNumbers(nums: List[int]) -> List[int]: + for num in nums: + pos = abs(num) - 1 + if nums[pos] > 0: + nums[pos] = -nums[pos] + return [i + 1 for i in range(len(nums)) if nums[i] > 0] +``` + + + + + +## [48. Rotate Image](https://leetcode.com/problems/rotate-image/) + +### 題目描述 + +給定一個 n × n 的矩陣,求它順時針旋轉 90 度的結果,且必須在原矩陣上修改(in-place)。怎樣能夠盡量不創建額外儲存空間呢? + +### 輸入輸出範例 + +輸入和輸出都是一個二維整數矩陣。 + +``` +Input: +[[1,2,3], + [4,5,6], + [7,8,9]] +Output: +[[7,4,1], + [8,5,2], + [9,6,3]] +``` + +### 題解 + +每次只考慮四個間隔 90 度的位置,可以進行 $O(1)$ 額外空間的旋轉。 + +
+ + ![](10.1.png) + +
圖 10.1: 題目 48 - $O(1)$ 空間旋轉範例,相同顏色代表四個互相交換的位置
+
+ + + + +```cpp +void rotate(vector>& matrix) { + int pivot = 0, n = matrix.size() - 1; + for (int i = 0; i <= n / 2; ++i) { + for (int j = i; j < n - i; ++j) { + pivot = matrix[j][n - i]; + matrix[j][n - i] = matrix[i][j]; + matrix[i][j] = matrix[n - j][i]; + matrix[n - j][i] = matrix[n - i][n - j]; + matrix[n - i][n - j] = pivot; + } + } +} +``` + + + + +```py +def rotate(matrix: List[List[int]]) -> None: + n = len(matrix) - 1 + for i in range(n // 2 + 1): + for j in range(i, n - i): + pivot = matrix[j][n - i] + matrix[j][n - i] = matrix[i][j] + matrix[i][j] = matrix[n - j][i] + matrix[n - j][i] = matrix[n - i][n - j] + matrix[n - i][n - j] = pivot +``` + + + + + +## [240. Search a 2D Matrix II](https://leetcode.com/problems/search-a-2d-matrix-ii/) + +### 題目描述 + +給定一個二維矩陣,已知每行和每列都是遞增排序,嘗試設計一個快速搜索某個數字是否存在於矩陣中的演算法。 + +### 輸入輸出範例 + +輸入是一個二維整數矩陣,和一個待搜索整數。輸出是一個布林值,表示該整數是否存在於矩陣中。 + +``` +Input: matrix = +[ [1, 4, 7, 11, 15], + [2, 5, 8, 12, 19], + [3, 6, 9, 16, 22], + [10, 13, 14, 17, 24], + [18, 21, 23, 26, 30]], target = 5 +Output: true +``` + +### 題解 + +這道題有一個簡單的技巧:我們可以從右上角開始查找,若當前值大於待搜索值,我們向左移動一位;若當前值小於待搜索值,我們向下移動一位。如果最終移動到左下角時仍不等於待搜索值,則說明該值不存在於矩陣中。 + + + + +```cpp +bool searchMatrix(vector>& matrix, int target) { + int m = matrix.size(), n = matrix[0].size(); + int i = 0, j = n - 1; + while (i < m && j >= 0) { + if (matrix[i][j] == target) { + return true; + } else if (matrix[i][j] < target) { + ++i; + } else { + --j; + } + } + return false; +} +``` + + + + +```py +def searchMatrix(matrix: List[List[int]], target: int) -> bool: + m, n = len(matrix), len(matrix[0]) + i, j = 0, n - 1 + while i < m and j >= 0: + if matrix[i][j] == target: + return True + if matrix[i][j] < target: + i += 1 + else: + j -= 1 + return False +``` + + + + + +## [769. Max Chunks To Make Sorted](https://leetcode.com/problems/max-chunks-to-make-sorted/) + +### 題目描述 + +給定一個包含 0 到 n 的整數陣列,每個整數只出現一次,求這個陣列最多可以分割成多少個子陣列,使得對每個子陣列進行遞增排序後,原陣列也是遞增的。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,輸出是一個整數,表示最多的分割數。 + +``` +Input: [1,0,2,3,4] +Output: 4 +``` + +在這個範例中,最多的分割是 [1, 0], [2], [3], [4]。 + +### 題解 + +從左到右遍歷,同時記錄目前的最大值,每當目前最大值等於目前陣列位置時,我們可以進行一次分割。 + +為什麼這個演算法可以解決問題呢?如果目前最大值大於目前陣列位置,則說明右邊一定有小於目前位置的數字,需要把它也加入待排序的子陣列;又因為陣列只包含不重複的 0 到 n,所以目前最大值一定不會小於目前陣列位置。因此,每當目前最大值等於目前陣列位置時,假設為 p,我們可以成功完成一次分割,並且其與上一次分割位置 q 之間的值一定是 q+1 到 p 的所有數字。 + + + + +```cpp +int maxChunksToSorted(vector& arr) { + int chunks = 0, cur_max = 0; + for (int i = 0; i < arr.size(); ++i) { + cur_max = max(cur_max, arr[i]); + chunks += cur_max == i; + } + return chunks; +} +``` + + + + +```py +def maxChunksToSorted(arr: List[int]) -> int: + chunks, cur_max = 0, 0 + for i, num in enumerate(arr): + cur_max = max(cur_max, num) + chunks += cur_max == i + return chunks +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx new file mode 100644 index 00000000..11212c84 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-4-stack-and-queue.mdx @@ -0,0 +1,257 @@ +--- +sidebar_position: 51 +--- + +# 10.4 堆疊與佇列 + +## [232. Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks/) + +### 題目描述 + +嘗試使用堆疊(stack)來實作佇列(queue)。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。 + +``` +MyQueue queue = new MyQueue(); +queue.push(1); +queue.push(2); +queue.peek(); // returns 1 +queue.pop(); // returns 1 +queue.empty(); // returns false +``` + +### 題解 + +我們可以用兩個堆疊來實作一個佇列:因為需要得到先入先出的結果,所以必須透過一個額外的堆疊翻轉一次陣列。這個翻轉過程可以在插入時完成,也可以在取值時完成。以下展示在取值時完成的寫法。 + + + + +```cpp +class MyQueue { + public: + MyQueue() {} + + void push(int x) { s_in_.push(x); } + + int pop() { + in2out(); + int x = s_out_.top(); + s_out_.pop(); + return x; + } + + int peek() { + in2out(); + return s_out_.top(); + } + + bool empty() { return s_in_.empty() && s_out_.empty(); } + + private: + void in2out() { + if (!s_out_.empty()) { + return; + } + while (!s_in_.empty()) { + int x = s_in_.top(); + s_in_.pop(); + s_out_.push(x); + } + } + + stack s_in_, s_out_; +}; +``` + + + + +```py +class MyQueue: + def __init__(self): + self.s_in = [] + self.s_out = [] + + def _in2out(self): + if len(self.s_out) > 0: + return + while len(self.s_in) > 0: + self.s_out.append(self.s_in.pop()) + + def push(self, x: int) -> None: + self.s_in.append(x) + + def pop(self) -> int: + self._in2out() + return self.s_out.pop() + + def peek(self) -> int: + self._in2out() + return self.s_out[-1] + + def empty(self) -> bool: + return len(self.s_in) == 0 and len(self.s_out) == 0 +``` + + + + + +## [155. Min Stack](https://leetcode.com/problems/min-stack/) + +### 題目描述 + +設計一個最小堆疊,除了需要支援一般堆疊的操作外,還需要支援在 $O(1)$ 時間內查詢堆疊中最小值的功能。 + +### 輸入輸出範例 + +以下是資料結構的使用範例: + +``` +MinStack minStack = new MinStack(); +minStack.push(-2); +minStack.push(0); +minStack.push(-3); +minStack.getMin(); // Returns -3. +minStack.pop(); +minStack.top(); // Returns 0. +minStack.getMin(); // Returns -2. +``` + +### 題解 + +我們可以額外建立一個輔助堆疊,該堆疊的頂部用來表示原堆疊中所有值的最小值。每當在原堆疊中插入一個數字時,若該數字小於或等於輔助堆疊的頂部,則表示該數字是原堆疊的最小值之一,我們同時將其插入輔助堆疊中。每當從原堆疊中取出一個數字時,若該數字等於輔助堆疊的頂部,則表示該數字是原堆疊中的最小值之一,我們同時取出輔助堆疊的頂部值。 + +另一種實現較簡單但時間複雜度略高的方法是,每次插入原堆疊時,都向輔助堆疊插入一次原堆疊中所有值的最小值(輔助堆疊頂部和待插入值中的較小值);每次從原堆疊中取出數字時,同樣從輔助堆疊中取出頂部值。這樣可以避免條件判斷,但需要每次都插入和取出。這裡只展示第一種方法。 + + + + +```cpp +class MinStack { + public: + MinStack() {} + + void push(int x) { + s_.push(x); + if (min_s_.empty() || min_s_.top() >= x) { + min_s_.push(x); + } + } + + void pop() { + if (!min_s_.empty() && min_s_.top() == s_.top()) { + min_s_.pop(); + } + s_.pop(); + } + + int top() { return s_.top(); } + + int getMin() { return min_s_.top(); } + + private: + stack s_, min_s_; +}; +``` + + + + +```py +class MinStack: + def __init__(self): + self.s = [] + self.min_s = [] + + def push(self, x: int) -> None: + self.s.append(x) + if len(self.min_s) == 0 or self.min_s[-1] >= x: + self.min_s.append(x) + + def pop(self) -> None: + if len(self.min_s) != 0 and self.s[-1] == self.min_s[-1]: + self.min_s.pop() + self.s.pop() + + def top(self) -> int: + return self.s[-1] + + def getMin(self) -> int: + return self.min_s[-1] +``` + + + + + + +## [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) + +### 題目描述 + +給定一個只由左右圓括號、花括號和方括號組成的字串,判斷這個字串是否合法。合法的定義是每一種類型的左括號都有一個右括號一一對應,且括號內的字串也滿足此要求。 + +### 輸入輸出範例 + +輸入是一個字串,輸出是一個布林值,表示字串是否合法。 + +``` +Input: "{[]}()" +Output: true +``` + +### 題解 + +括號匹配是典型使用堆疊來解決的問題。我們從左到右遍歷字串,每當遇到左括號時將其放入堆疊;當遇到右括號時,判斷其是否與堆疊頂部的括號類型相符,若相符則從堆疊中移除左括號,否則說明字串不合法。 + + + + +```cpp +bool isValid(string s) { + stack parsed; + unordered_map matches{{’(’, ’)’}, {’{’, ’}’}, {’[’, ’]’}}; + for (char c : s) { + if (matches.contains(c)) { + parsed.push(c); + continue; + } + if (parsed.empty()) { + return false; + } + if (c != matches[parsed.top()]) { + return false; + } + parsed.pop(); + } + return parsed.empty(); +} +``` + + + + +```py +def isValid(s: str) -> bool: + parsed = [] + matches = {"{": "}", "(": ")", "[": "]"} + for c in s: + if c in matches.keys(): + parsed.append(c) + continue + if len(parsed) == 0: + return False + if c != matches[parsed[-1]]: + return False + parsed.pop() + return len(parsed) == 0 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx new file mode 100644 index 00000000..e73105b4 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-5-monotonic-stack.mdx @@ -0,0 +1,72 @@ +--- +sidebar_position: 52 +--- + +# 10.5 單調堆疊 + +`單調堆疊`透過維持堆疊內值的單調遞增(遞減)性,可以在整體 $O(n)$ 的時間內解決需要大小比較的問題。 + +## [739. Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) + +### 題目描述 + +給定每天的溫度,求對於每一天需要等幾天才可以等到更暖和的一天。如果該天之後不存在更暖和的天氣,則記為 0。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,輸出是相同長度的整數陣列,表示對於每天需要等待多少天。 + +``` +Input: [73, 74, 75, 71, 69, 72, 76, 73] +Output: [1, 1, 4, 2, 1, 1, 0, 0] +``` + +### 題解 + +我們可以維持一個單調遞減的堆疊,表示每天的溫度;為了方便計算天數差,我們存放位置(即日期)而非溫度本身。我們從左到右遍歷溫度陣列,對於每個日期 $p$,如果 $p$ 的溫度比堆疊頂部儲存位置 $q$ 的溫度高,則我們取出 $q$,並記錄 $q$ 需要等待的天數為 $p - q$;我們重複這一過程,直到 $p$ 的溫度小於等於堆疊頂部儲存位置的溫度(或空堆疊)時,將 $p$ 插入堆疊頂部,然後考慮下一天。在此過程中,堆疊內陣列永遠保持單調遞減,避免了使用排序進行比較。最後若堆疊內剩餘一些日期,則說明它們之後都沒有出現更暖和的日期。 + + + + +```cpp +vector dailyTemperatures(vector& temperatures) { + int n = temperatures.size(); + vector days_to_wait(n, 0); + stack mono_stack; + for (int i = 0; i < n; ++i) { + while (!mono_stack.empty()) { + int j = mono_stack.top(); + if (temperatures[i] <= temperatures[j]) { + break; + } + mono_stack.pop(); + days_to_wait[j] = i - j; + } + mono_stack.push(i); + } + return days_to_wait; +} +``` + + + + +```py +def dailyTemperatures(temperatures: List[int]) -> List[int]: + n = len(temperatures) + days_to_wait = [0] * n + mono_stack = [] + for i in range(n): + while len(mono_stack) > 0: + j = mono_stack[-1] + if temperatures[i] <= temperatures[j]: + break + mono_stack.pop() + days_to_wait[j] = i - j + mono_stack.append(i) + return days_to_wait +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx new file mode 100644 index 00000000..8750681e --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-6-priority-queue.mdx @@ -0,0 +1,296 @@ +--- +sidebar_position: 53 +--- + +# 10.6 優先佇列 + +`優先佇列`(priority queue)可以在 $O(1)$ 時間內獲得最大值,並且可以在 $O(\log n)$ 時間內取出最大值或插入任意值。 + + +
+ + ![](10.2.png) + +
圖 10.2: (最大)堆,維護的是資料結構中的大於關係
+
+ +優先佇列常常用堆(heap)來實現。堆是一個完全二元樹,其每個節點的值總是大於等於子節點的值。實際實現堆時,我們通常用一個陣列而不是用指標建立一個樹。這是因為堆是完全二元樹,所以用陣列表示時,位置 $i$ 的節點的父節點位置一定為 $(i-1)/2$,而它的兩個子節點的位置又一定分別為 $2i+1$ 和 $2i+2$。 + +以下是堆的實現方法,其中最核心的兩個操作是上浮和下沉:如果一個節點比父節點大,那麼需要交換這兩個節點;交換後還可能比它新的父節點大,因此需要不斷地進行比較和交換操作,我們稱之為上浮;類似地,如果一個節點比父節點小,也需要不斷地向下進行比較和交換操作我們稱之為下沉。如果一個節點有兩個子節點,我們總是交換最大的子節點。 + + + + + +```cpp +class Heap { + public: + Heap() {} + // 上浮。 + void swim(int pos) { + int next_pos = (pos - 1) / 2; + while (pos > 0 && heap_[next_pos] < heap_[pos]) { + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = (pos - 1) / 2; + } + } + // 下沉。 + void sink(int pos) { + int n = heap_.size(); + int next_pos = 2 * pos + 1; + while (next_pos < n) { + if (next_pos < n - 1 && heap_[next_pos] < heap_[next_pos + 1]) { + ++next_pos; + } + if (heap_[pos] >= heap_[next_pos]) { + break; + } + swap(heap_[next_pos], heap_[pos]); + pos = next_pos; + next_pos = 2 * pos + 1; + } + } + // 插入任意值:把新的數字放在最後一位,然後上浮。 + void push(int k) { + heap_.push_back(k); + swim(heap_.size() - 1); + } + // 刪除最大值:把最後一個數字挪到開頭,然後下沉。 + void pop() { + heap_[0] = heap_.back(); + heap_.pop_back(); + sink(0); + } + // 獲得最大值。 + int top() { return heap_[0]; } + + private: + vector heap_; +}; +``` + + + + +```py +class Heap: + def __init__(self): + self.heap = [] + + # 上浮。 + def swim(self, pos: int): + next_pos = (pos - 1) // 2 + while pos > 0 and self.heap[next_pos] < self.heap[pos]: + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = (pos - 1) // 2 + + # 下沉。 + def sink(self, pos: int): + n = len(self.heap) + next_pos = 2 * pos + 1 + while next_pos < n: + if next_pos < n - 1 and self.heap[next_pos] < self.heap[next_pos + 1]: + next_pos += 1 + if self.heap[pos] >= self.heap[next_pos]: + break + self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] + pos = next_pos + next_pos = 2 * pos + 1 + + # 插入任意值:把新的數字放在最後一位,然後上浮。 + def push(self, k: int): + self.heap.append(k) + self.swim(len(self.heap) - 1) + + # 刪除最大值:把最後一個數字挪到開頭,然後下沉。 + def pop(self): + self.heap[0] = self.heap.pop() + self.sink(0) + + # 獲得最大值。 + def top(self) -> int: + return self.heap[0] + +``` + + + + + +通過將算法中的大於號和小於號互換,我們也可以得到一個快速獲得最小值的優先佇列。 + +## [23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) + +### 題目描述 + +給定 k 個遞增的鏈結串列,嘗試將它們合併成一條遞增鏈結串列。 + +### 輸入輸出範例 + +輸入是一維陣列,每個位置儲存鏈結串列的頭節點;輸出是一條鏈結串列。 + +``` +Input: +[1->4->5, + 1->3->4, + 2->6] +Output: 1->1->2->3->4->4->5->6 +``` + +### 題解 + +本題可以有多種解法,例如類似於合併排序進行兩兩合併。我們這裡展示一個速度較快的方法,即把所有的鏈結串列存入一個優先佇列中,每次提取所有鏈結串列頭部節點值中最小的那個節點,直到所有鏈結串列都被提取完為止。 + +由於 C++ priority_queue 的比較函數預設是對最大堆進行比較並維持遞增關係,如果我們想要獲取最小的節點值,我們則需要實現一個最小堆。因此,堆的比較函數應該維持遞減關係,即 lambda 函數中返回時用大於號而不是遞增關係時的小於號進行比較。 + + + + +```cpp +ListNode* mergeKLists(vector& lists) { + auto comp = [](ListNode* l1, ListNode* l2) { return l1->val > l2->val; }; + priority_queue, decltype(comp)> pq; + for (ListNode* l : lists) { + if (l) { + pq.push(l); + } + } + ListNode *dummy = new ListNode(0), *cur = dummy; + while (!pq.empty()) { + cur->next = pq.top(); + pq.pop(); + cur = cur->next; + if (cur->next) { + pq.push(cur->next); + } + } + return dummy->next; +} +``` + + + + +```py +def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]: + pq = [] + for idx, l in enumerate(lists): + if l is not None: + # ListNode 無法被雜湊,因此這裡我們直接記錄它在 lists 中的位置。 + pq.append((l.val, idx)) + heapq.heapify(pq) + + dummy = ListNode() + cur = dummy + + while len(pq) > 0: + _, l_idx = heapq.heappop(pq) + cur.next = lists[l_idx] + cur = cur.next + if cur.next is not None: + lists[l_idx] = lists[l_idx].next + heapq.heappush(pq, (cur.next.val, l_idx)) + + return dummy.next + +``` + + + + + +## [218. The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) + +### 題目描述 + +給定建築物的起始位置、結束位置和高度,返回建築物輪廓(天際線)的轉折點。 + +### 輸入輸出範例 + +輸入是一個二維整數陣列,每個建築物用 [左端, 右端, 高度] 表示;輸出是一個二維整數陣列,表示天際線轉折點的橫縱座標。 + +
+ + ![](10.3.png) + +
圖 10.3: 問題 218 - 建築物與其天際線範例
+
+ +``` +Input: [[2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8]] +Output: [[2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0]] +``` + +### 題解 + +我們可以使用優先隊列來儲存每棟建築的高度與右端(這裡使用 pair,其默認的比較函數是先比較第一個值,如果相等則再比較第二個值),從而找到目前會提高天際線的建築,並排除妨礙到前一棟建築(右端點)的建築。 + +因為 Python 的 `heapq` 是最小堆,所以我們在存值的時候可以存負值,這樣就模擬了最大堆。 + +這題較為複雜,若難以理解,建議暫時跳過,或者在紙上畫圖舉例分析。 + + + + +```cpp +vector> getSkyline(vector>& buildings) { + vector> skyline; + priority_queue> pq; // <高度, 右端> + int i = 0, n = buildings.size(); + int cur_x, cur_h; + while (i < n || !pq.empty()) { + if (pq.empty() || (i < n && buildings[i][0] <= pq.top().second)) { + cur_x = buildings[i][0]; + while (i < n && cur_x == buildings[i][0]) { + pq.emplace(buildings[i][2], buildings[i][1]); + ++i; + } + } else { + cur_x = pq.top().second; + while (!pq.empty() && cur_x >= pq.top().second) { + pq.pop(); + } + } + cur_h = pq.empty() ? 0 : pq.top().first; + if (skyline.empty() || cur_h != skyline.back()[1]) { + skyline.push_back({cur_x, cur_h}); + } + } + return skyline; +} +``` + + + + +```py +def getSkyline(buildings: List[List[int]]) -> List[List[int]]: + skyline = [] + pq = [] # <負高度, 右端> + heapq.heapify(pq) + i, n = 0, len(buildings) + + while i < n or len(pq) > 0: + if len(pq) == 0 or (i < n and buildings[i][0] <= pq[0][1]): + cur_x = buildings[i][0] + while i < n and cur_x == buildings[i][0]: + heapq.heappush(pq, (-buildings[i][2], buildings[i][1])) + i += 1 + else: + cur_x = pq[0][1] + while len(pq) > 0 and cur_x >= pq[0][1]: + heapq.heappop(pq) + + cur_h = -pq[0][0] if len(pq) > 0 else 0 + if len(skyline) == 0 or cur_h != skyline[-1][1]: + skyline.append([cur_x, cur_h]) + + return skyline + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx new file mode 100644 index 00000000..943c8341 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-7-deque.mdx @@ -0,0 +1,84 @@ +--- +sidebar_position: 54 +--- + +# 10.7 雙端佇列 + +## [239. Sliding Window Maximum](https://leetcode.com/problems/sliding-window-maximum/) + +### 題目描述 + +給定一個整數陣列和一個滑動視窗大小,求在這個視窗滑動過程中的每個時刻,其包含的最大值。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,以及一個表示滑動視窗大小的整數;輸出是一個一維整數陣列,表示每個時刻視窗內的最大值。 + +``` +Input: nums = [1,3,-1,-3,5,3,6,7], k = 3 +Output: [3,3,5,5,6,7] +``` + +在此範例中,滑動視窗在每個位置的最大值如下: + +``` + Window position Max +------------------------- ----- +[1 3 -1] -3 5 3 6 7 3 + 1 [3 -1 -3] 5 3 6 7 3 + 1 3 [-1 -3 5] 3 6 7 5 + 1 3 -1 [-3 5 3] 6 7 5 + 1 3 -1 -3 [5 3 6] 7 6 + 1 3 -1 -3 5 [3 6 7] 7 +``` + +### 題解 + +我們可以利用雙端佇列來實現:每次滑動視窗向右移動時,將視窗左端的值從雙端佇列左端移除,並將雙端佇列右邊小於當前視窗右端值的元素剔除。這樣,雙端佇列的最左端永遠是當前視窗內的最大值。 + +此外,這道題也可以視為單調堆疊的一種延伸:此雙端佇列利用從左到右遞減的順序來維持大小關係。 + + + + +```cpp +vector maxSlidingWindow(vector& nums, int k) { + deque dq; + vector swm; + for (int i = 0; i < nums.size(); ++i) { + if (!dq.empty() && dq.front() == i - k) { + dq.pop_front(); + } + while (!dq.empty() && nums[dq.back()] < nums[i]) { + dq.pop_back(); + } + dq.push_back(i); + if (i >= k - 1) { + swm.push_back(nums[dq.front()]); + } + } + return swm; +} +``` + + + + +```py +def maxSlidingWindow(nums: List[int], k: int) -> List[int]: + dq = collections.deque() + swm = [] + for i, num in enumerate(nums): + if len(dq) > 0 and dq[0] == i - k: + dq.popleft() + while len(dq) > 0 and nums[dq[-1]] < num: + dq.pop() + dq.append(i) + if i >= k - 1: + swm.append(nums[dq[0]]) + return swm +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx new file mode 100644 index 00000000..a7be373a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-8-hash-table.mdx @@ -0,0 +1,232 @@ +--- +sidebar_position: 55 +--- + +# 10.8 雜湊表 + +`雜湊表(hash table, hash map)`,又稱散列表,使用 $O(n)$ 空間複雜度儲存資料,通過雜湊函數(hash function)映射位置,從而實現近似 $O(1)$ 時間複雜度的插入、查詢、刪除等操作。雜湊表可以用來統計頻率、記錄內容等等。 + +如果元素是有限的,且範圍不大,那麼可以用一個固定大小的陣列來儲存或統計元素。例如,我們需要統計一個字串中所有字母的出現次數,則可以用一個長度為 26 的陣列來進行統計,其雜湊函數即為字母在字母表中的位置,這樣空間複雜度就可以降低為常數。 + +## [1. Two Sum](https://leetcode.com/problems/two-sum/) + +### 題目描述 + +給定一個(未排序的)整數陣列,已知有且只有兩個數的和等於給定值,求這兩個數的位置。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列和一個目標值,輸出是一個大小為 2 的一維陣列,表示滿足條件的兩個數字的位置。 + +``` +Input: nums = [2, 7, 15, 11], target = 9 +Output: [0, 1] +``` + +在這個範例中,第 0 個位置的值 2 和第 1 個位置的值 7 的和為 9。 + +### 題解 + +我們可以利用雜湊表儲存遍歷過的值以及它們的位置,每次遍歷到位置 i 的時候,查找雜湊表裡是否存在 `target - nums[i]`,若存在,則說明這兩個值的和為 `target`。 + + + + +```cpp +vector twoSum(vector& nums, int target) { + unordered_map cache; // <值,位置> + for (int i = 0; i < nums.size(); ++i) { + int num1 = nums[i], num2 = target - num1; + if (cache.contains(num2)) { + return vector{cache[num2], i}; + } + cache[num1] = i; + } + return {}; +} +``` + + + + +```py +def twoSum(nums: List[int], target: int) -> List[int]: + cache = dict() # <值,位置> + for i, num1 in enumerate(nums): + num2 = target - num1 + if num2 in cache: + return [cache[num2], i] + cache[num1] = i + return [] +``` + + + + + +## [128. Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) + +### 題目描述 + +給定一個整數陣列,求這個陣列中的數字可以組成的最長連續序列有多長。 + +### 輸入輸出範例 + +輸入是一個整數陣列,輸出是一個整數,表示連續序列的長度。 + +``` +Input: [100, 4, 200, 1, 3, 2] +Output: 4 +``` + +在這個範例中,最長連續序列是 [1,2,3,4]。 + +### 題解 + +我們可以把所有數字放到一個雜湊表,然後不斷地從雜湊表中任意取一個值,並刪除掉其之前之後的所有連續數字,然後更新目前的最長連續序列長度。重複這一過程,我們就可以找到所有的連續數字序列。 + + + + +```cpp +int longestConsecutive(vector& nums) { + unordered_set cache(nums.begin(), nums.end()); + int max_len = 0; + while (!cache.empty()) { + int cur = *(cache.begin()); + cache.erase(cur); + int l = cur - 1, r = cur + 1; + while (cache.contains(l)) { + cache.erase(l--); + } + while (cache.contains(r)) { + cache.erase(r++); + } + max_len = max(max_len, r - l - 1); + } + return max_len; +} +``` + + + + +```py +def longestConsecutive(nums: List[int]) -> int: + cache = set(nums) + max_len = 0 + + while len(cache) > 0: + cur = next(iter(cache)) + cache.remove(cur) + + l, r = cur - 1, cur + 1 + while l in cache: + cache.remove(l) + l -= 1 + while r in cache: + cache.remove(r) + r += 1 + + max_len = max(max_len, r - l - 1) + + return max_len + +``` + + + + + +## [149. Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) + +### 題目描述 + +給定一些二維座標中的點,求同一條線上最多有多少點。 + +### 輸入輸出範例 + +輸入是一個二維整數陣列,表示每個點的橫縱座標;輸出是一個整數,表示滿足條件的最多點數。 + +``` +Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] +^ +| +| o +| o o +| o +| o o ++-------------------> +0 1 2 3 4 5 6 +Output: 4 +``` + +在這個範例中,$y = 5 - x$ 上有四個點。 + +### 題解 + +對於每個點,我們對其他點建立雜湊表,統計同一斜率的點一共有多少個。這裡利用的原理是,一條線可以由一個點和斜率唯一確定。此外,也需要考慮斜率不存在和重複座標的情況。 + +本題還利用了一個小技巧:在遍歷每個點時,對於陣列中位置 i 的點,我們只需要考慮 i 之後的點即可,因為 i 之前的點已經考慮過 i 了。 + + + + +```cpp +int maxPoints(vector>& points) { + int max_count = 0, n = points.size(); + for (int i = 0; i < n; ++i) { + unordered_map cache; // <斜率, 點的數量> + int same_xy = 1, same_y = 1; + for (int j = i + 1; j < n; ++j) { + if (points[i][1] == points[j][1]) { + ++same_y; + if (points[i][0] == points[j][0]) { + ++same_xy; + } + } else { + double dx = points[i][0] - points[j][0], + dy = points[i][1] - points[j][1]; + ++cache[dx / dy]; + } + } + max_count = max(max_count, same_y); + for (auto item : cache) { + max_count = max(max_count, same_xy + item.second); + } + } + return max_count; +} +``` + + + + +```py +def maxPoints(points: List[List[int]]) -> int: + max_count, n = 0, len(points) + + for i, point1 in enumerate(points): + cache = dict() # <斜率, 點的數量> + same_xy, same_y = 1, 1 + + for point2 in points[i + 1:]: + if point1[1] == point2[1]: + same_y += 1 + if point1[0] == point2[0]: + same_xy += 1 + else: + dx, dy = point1[0] - point2[0], point1[1] - point2[1] + cache[dx / dy] = cache.get(dx / dy, 0) + 1 + + max_count = max(max_count, same_y) + for count in cache.values(): + max_count = max(max_count, same_xy + count) + + return max_count + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx new file mode 100644 index 00000000..8bfe5fd1 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10-9-multisets-and-maps.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 56 +--- + +# 10.9 多重集合和映射 + +## [332. Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) + +### 題目描述 + +給定一個人搭乘過的一些飛機的起止機場,已知這個人從 JFK 起飛,那麼這個人是按什麼順序飛的;如果存在多種可能性,返回字母序最小的那種。 + +### 輸入輸出範例 + +輸入是一個二維字串陣列,表示多個起止機場的組合;輸出是一個一維字串陣列,表示飛行順序。 + +``` +Input: [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]] +Output: ["JFK", "MUC", "LHR", "SFO", "SJC"] +``` + +### 題解 + +本題可以先用雜湊表記錄起止機場,其中鍵是起始機場,值是一個多重(有序)集合,表示對應的終止機場。因為一個人可能搭過重複的航線,所以我們需要使用多重集合來儲存重複值。儲存完成之後,我們可以利用堆疊/DFS 來還原從終點到起點的飛行順序,再將結果逆序得到從起點到終點的順序。 + +由於 Python 沒有內建的多重(有序)集合實作,我們可以直接儲存一個陣列,然後進行排序。也可以使用 Counter 結構,每次查找下一個機場時,返回鍵值最小的那個。 + + + + +```cpp +vector findItinerary(vector>& tickets) { + vector itinerary; + unordered_map> cache; + for (const auto& ticket : tickets) { + cache[ticket[0]].insert(ticket[1]); + } + stack s; + s.push("JFK"); + while (!s.empty()) { + string t = s.top(); + if (cache[t].empty()) { + itinerary.push_back(t); + s.pop(); + } else { + s.push(*cache[t].begin()); + cache[t].erase(cache[t].begin()); + } + } + reverse(itinerary.begin(), itinerary.end()); + return itinerary; +} +``` + + + + +```py +def findItinerary(tickets: List[List[str]]) -> List[str]: + itinerary = [] + cache = dict() + + for ticket in tickets: + if ticket[0] not in cache: + cache[ticket[0]] = [] + cache[ticket[0]].append(ticket[1]) + + for ticket in cache.keys(): + cache[ticket].sort(reverse=True) + + s = ["JFK"] + while len(s) > 0: + t = s[-1] + if t not in cache or len(cache[t]) == 0: + itinerary.append(t) + s.pop() + else: + t_next = cache[t].pop() + s.append(t_next) + + return list(reversed(itinerary)) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png new file mode 100644 index 00000000..a0f0fc51 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.1.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png new file mode 100644 index 00000000..9a10d41c Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.2.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png new file mode 100644 index 00000000..bc65f388 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.3.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png new file mode 100644 index 00000000..84c2f60e Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.4.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png new file mode 100644 index 00000000..310069c9 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/10.5.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json new file mode 100644 index 00000000..bc804e26 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/10-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "10. 妙用資料結構", + "position": 10, + "link": { + "type": "generated-index", + "description": "第 10 章 妙用資料結構" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md new file mode 100644 index 00000000..6f273266 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 59 +--- + +# 11.1 引言 + +字串可以視為由字元組成的陣列。由於字串是程式中經常需要處理的資料型別,因此有許多針對字串處理的題目,以下是一些常見的類型。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx new file mode 100644 index 00000000..f243663a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-2-string-comparison.mdx @@ -0,0 +1,350 @@ +--- +sidebar_position: 60 +--- + +# 11.2 字串比較 + +## [242. Valid Anagram](https://leetcode.com/problems/valid-anagram/) + +### 題目描述 + +判斷兩個字串包含的字元是否完全相同。 + +### 輸入輸出範例 + +輸入兩個字串,輸出一個布林值,表示兩個字串是否滿足條件。 + +``` +Input: s = "anagram", t = "nagaram" +Output: true +``` + +### 題解 + +我們可以利用雜湊表或陣列來統計兩個字串中每個字元出現的頻率。如果頻率相同,則說明它們包含的字元完全相同。 + + + + +```cpp +bool isAnagram(string s, string t) { + if (s.length() != t.length()) { + return false; + } + vector counts(26, 0); + for (int i = 0; i < s.length(); ++i) { + ++counts[s[i] - ’a’]; + --counts[t[i] - ’a’]; + } + return all_of(counts.begin(), counts.end(), [](int c) { return c == 0; }); +} +``` + + + + +```py +def isAnagram(s: str, t: str) -> bool: + if len(s) != len(t): + return False + counter = Counter(s) + counter.subtract(t) + return all(v == 0 for v in counter.values()) +``` + + + + + +## [205. Isomorphic Strings](https://leetcode.com/problems/isomorphic-strings/) + +### 題目描述 + +判斷兩個字串是否同構。兩個字串同構的定義為,透過將一個字串中的某些相同字元轉換為另一組相同字元,能使得兩個字串相同,且不同的字元不能被轉換為相同的字元。 + +### 輸入輸出範例 + +輸入兩個字串,輸出一個布林值,表示兩個字串是否滿足條件。 + +``` +Input: s = "paper", t = "title" +Output: true +``` + +在這個例子中,將 `s` 中的 `p`、`a`、`e`、`r` 轉換為 `t`、`i`、`l`、`e`,兩個字串就可以變得相同。 + +### 題解 + +我們可以將問題重新表述:記錄兩個字串中每個位置的字元首次出現的位置。如果兩個字串中相同位置的字元與它們的首次出現位置相同,則這兩個字串同構。 + +舉例來說,對於 "paper" 和 "title",假設我們現在處理第三個字元 `p` 和 `t`,發現它們首次出現的位置都在第一個字元,這表示目前位置滿足同構條件。我們可以使用雜湊表進行儲存,或者用一個長度為 128 的陣列(ASCII 定義下的字元總數)。 + + + + +```cpp +bool isIsomorphic(string s, string t) { + vector s_init(128, 0), t_init(128, 0); + for (int i = 0; i < s.length(); ++i) { + if (s_init[s[i]] != t_init[t[i]]) { + return false; + } + s_init[s[i]] = t_init[t[i]] = i + 1; + } + return true; +} +``` + + + + +```py +def isIsomorphic(s: str, t: str) -> bool: + s_init, t_init = [0] * 128, [0] * 128 + + for i in range(len(s)): + if s_init[ord(s[i])] != t_init[ord(t[i])]: + return False + s_init[ord(s[i])] = t_init[ord(t[i])] = i + 1 + + return True + +``` + + + + + +## [647. Palindromic Substrings](https://leetcode.com/problems/palindromic-substrings/) + +### 題目描述 + +給定一個字串,求其有多少個回文子字串。回文的定義是左右對稱。 + +### 輸入輸出範例 + +輸入是一個字串,輸出是一個整數,表示回文子字串的數量。 + +``` +Input: "aaa" +Output: 6 +``` + +六個回文子字串分別是 ["a", "a", "a", "aa", "aa", "aaa"]。 + +### 題解 + +我們可以從字串的每個位置開始,向左向右延長,判斷存在多少以當前位置為中心的回文子字串。 + + + + +```cpp +// 輔助函式。 +int extendSubstrings(string s, int l, int r) { + int count = 0, n = s.length(); + while (l >= 0 && r < n && s[l] == s[r]) { + --l; + ++r; + ++count; + } + return count; +} +// 主函式。 +int countSubstrings(string s) { + int count = 0; + for (int i = 0; i < s.length(); ++i) { + count += extendSubstrings(s, i, i); // 奇數長度 + count += extendSubstrings(s, i, i + 1); // 偶數長度 + } + return count; +} +``` + + + + +```py +# 輔助函式。 +def extendSubstrings(s: str, l: int, r: int) -> int: + count, n = 0, len(s) + while l >= 0 and r < n and s[l] == s[r]: + count += 1 + l -= 1 + r += 1 + return count + +# 主函式。 +def countSubstrings(s: str) -> int: + return sum( + # 奇數長度 + 偶數長度 + extendSubstrings(s, i, i) + extendSubstrings(s, i, i + 1) + for i in range(len(s)) + ) + +``` + + + + + +## [696. Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/) + +### 題目描述 + +給定一個 0 和 1 組成的字串,求有多少非空子字串,其 '0' 和 '1' 的數量相同,且 '0' 和 '1' 必須連續出現(例如 "0011", "1100";但 "0101" 不算有效)。 + +### 輸入輸出範例 + +輸入是一個字串,輸出是一個整數,表示符合條件的子字串的數量。 + +``` +Input: "00110011" +Output: 6 +``` + +在這個範例中,六個 '0' 和 '1' 數量相同的子字串為 ["0011", "01", "1100", "10", "0011", "01"]。 + +### 題解 + +從左往右遍歷字串,記錄當前字元連續出現的長度,以及其前一段不同字元的連續長度。例如對於字串 "00110" 的最後一位 '0',我們記錄的值為: +- 相同字元長度為 1,因為最後只有一個連續的 '0'; +- 不同字元長度為 2,因為在最後的 '0' 之前,有兩個連續的 '1'。 + +若不同字元的連續長度大於等於當前字元的連續長度,則說明存在一個且僅一個以當前字元結尾、符合條件的子字串。 + + + + +```cpp +int countBinarySubstrings(string s) { + int prev = 0, cur = 1, count = 0; + for (int i = 1; i < s.length(); ++i) { + if (s[i] == s[i - 1]) { + ++cur; + } else { + prev = cur; + cur = 1; + } + if (prev >= cur) { + ++count; + } + } + return count; +} +``` + + + + +```py +def countBinarySubstrings(s: str) -> int: + prev, cur, count = 0, 1, 0 + + for i in range(1, len(s)): + if s[i] == s[i - 1]: + cur += 1 + else: + prev = cur + cur = 1 + if prev >= cur: + count += 1 + + return count + +``` + + + + + +## [1249. Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/) + +### 題目描述 + +給定一個包含字母與括號的字串,求最少移除多少括號才能使其合法。 + +### 輸入輸出範例 + +輸入是一個字串,輸出是一個合法且長度最長的結果字串。 + +``` +Input: s = "lee(t(c)o)de)" +Output: "lee(t(c)o)de" +``` + +返回 "lee(t(co)de)" 或 "lee(t(c)ode)" 也算正確。 + +### 題解 + +因為只有一種括號類型,因此我們不一定需要用堆疊來統計括號對應情況。相反,我們可以使用一個臨時變數來記錄當前位置時左括號比右括號多出多少個: + +- 如果在遍歷過程中,這個數值變為負數,說明有多餘的右括號需要移除。 +- 若遍歷結束時這個值為正數,則說明有多餘的左括號需要移除,這可以透過從右到左的遍歷完成。 + +一個小技巧是先標記待刪除的位置,最後一次性移除這些位置的括號。 + + + + +```cpp +string minRemoveToMakeValid(string s) { + int count = 0, n = s.length(); + char to_delete = '#'; + for (char& c : s) { + if (c == '(') { + ++count; + } else if (c == ')') { + if (count > 0) { + --count; + } else { + c = to_delete; + } + } + } + for (int i = n - 1; i >= 0; --i) { + if (count == 0) break; + if (s[i] == '(') { + s[i] = to_delete; + --count; + } + } + s.erase(remove_if(s.begin(), s.end(), + [to_delete](char c) { return c == to_delete; }), + s.end()); + return s; +} + +``` + + + + +```py +def minRemoveToMakeValid(s: str) -> str: + count, n = 0, len(s) + to_delete = set() + + for i in range(n): + if s[i] == "(": + count += 1 + elif s[i] == ")": + if count > 0: + count -= 1 + else: + to_delete.add(i) + + for i in range(n - 1, -1, -1): + if count == 0: + break + if s[i] == "(": + to_delete.add(i) + count -= 1 + + return "".join(s[i] for i in range(n) if i not in to_delete) + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx new file mode 100644 index 00000000..b266d4bf --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-3-string-interpretation.mdx @@ -0,0 +1,129 @@ +--- +sidebar_position: 61 +--- + +# 11.3 字串解析 + +## [227. Basic Calculator II](https://leetcode.com/problems/basic-calculator-ii/) + +### 題目描述 + +給定一個包含加減乘除整數運算的字串,計算其運算結果。如果除不盡則向 0 取整。 + +### 輸入輸出範例 + +輸入是一個合法的運算字串,輸出是一個整數,表示其運算結果。 + +``` +Input: " 3+5 / 2 " +Output: 5 +``` + +在這個例子中,因為除法的優先級高於加法,所以結果是 5 而不是 4。 + +### 題解 + +如果我們在字串左邊加上一個 `+` 號,可以證明其並不改變運算結果,且字串可以分割成多個 `<運算符, 數字>` 的配對形式;這樣一來我們就可以從左到右處理。由於乘除的優先級高於加減,因此我們需要使用一個中間變數來儲存高優先度的運算結果。 + +此類型題目也考驗很多細節處理,例如沒有運算符的情況,以及多個空格的情況等等。 + + + + +```cpp +// 輔助函數 - parse 從位置 i 開始的一個數字。 +int parseNum(const string& s, int& i) { + int num = 0, n = s.length(); + while (i < n && isdigit(s[i])) { + num = 10 * num + (s[i++] - '0'); + } + return num; +} + +// 主函式。 +int calculate(string s) { + char op = '+'; + long global_num = 0, local_num = 0; + int i = -1, n = s.length(); + while (++i < n) { + if (s[i] == ' ') { + continue; + } + long num = parseNum(s, i); + switch (op) { + case '+': + global_num += local_num; + local_num = num; + break; + case '-': + global_num += local_num; + local_num = -num; + break; + case '*': + local_num *= num; + break; + case '/': + local_num /= num; + break; + } + if (i < n) { + op = s[i]; + } + } + return global_num + local_num; +} + +``` + + + + +```py +from typing import Tuple + +# 輔助函數 - parse 從位置 i 開始的一個數字。 +# 返回 (數字, 下一個 i 位置) +def parseNum(s: str, i: int) -> Tuple[int, int]: + num, n = 0, len(s) + while i < n and s[i].isdigit(): + num = 10 * num + int(s[i]) + i += 1 + return (num, i) + +# 主函式。 +def calculate(s: str) -> int: + op = "+" + global_num, local_num = 0, 0 + i, n = 0, len(s) + + while i < n: + if s[i] == " ": + i += 1 + continue + + num, i = parseNum(s, i) + + match op: + case "+": + global_num += local_num + local_num = num + case "-": + global_num += local_num + local_num = -num + case "*": + local_num *= num + case "/": + # int() 會實現向 0 取整,而 // 對負數會遠離 0 取整。 + local_num = int(local_num / num) + + if i < n: + op = s[i] + i += 1 + + return global_num + local_num + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx new file mode 100644 index 00000000..d85c8b22 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-4-string-matching.mdx @@ -0,0 +1,106 @@ +--- +sidebar_position: 62 +--- + +# 11.4 字串匹配 + +## [28. Implement strStr()](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/) + +### 題目描述 + +判斷一個字串是否為另一個字串的子字串,並返回其位置。 + +### 輸入輸出範例 + +輸入一個母字串和一個子字串,輸出一個整數,表示子字串在母字串中的位置,若不存在則返回 -1。 + +``` +Input: haystack = "hello", needle = "ll" +Output: 2 +``` + +### 題解 + +使用著名的 Knuth-Morris-Pratt(KMP)演算法,可以在 $O(m + n)$ 時間內利用動態規劃完成匹配。這裡我們定義 `dp` 陣列為,`dp[i]` 表示 `needle` 中以位置 `i` 結尾的片段(即後綴),最長可以匹配到 `needle` 的起始位置(即前綴)。例如,對於 `needle = "ababaca"`,`dp` 陣列為 `[-1, -1, 0, 1, 2, -1, 0]`,表示每個位置的最大匹配 [無, 無, a, ab, aba, 無, a]。 + +這道題比較複雜,初學者可以暫時跳過。 + + + + +```cpp +// 輔助函式。 +vector computeDp(const string &needle) { + int n = needle.length(); + vector dp(n, -1); + for (int j = 1, k = -1; j < n; ++j) { + while (k > -1 && needle[k + 1] != needle[j]) { + k = dp[k]; // 如果下一位不同,回溯到前一個前綴片段 + } + if (needle[k + 1] == needle[j]) { + ++k; // 前綴和後綴片段相同,匹配長度加 1 + } + dp[j] = k; // 更新前綴匹配位置 + } + return dp; +} +// 主函式。 +int strStr(const string &haystack, const string &needle) { + int m = haystack.length(), n = needle.length(); + vector dp = computeDp(needle); + for (int i = 0, k = -1; i < m; ++i) { + while (k > -1 && needle[k + 1] != haystack[i]) { + k = dp[k]; // 如果下一位不同,回溯到前一個相同片段 + } + if (needle[k + 1] == haystack[i]) { + ++k; // 片段相同,匹配長度加 1 + } + if (k == n - 1) { + return i - n + 1; // 匹配完成 + } + } + return -1; +} +``` + + + + +```py +from typing import List + +# 輔助函式。 +def computeDp(needle: str) -> List[int]: + n = len(needle) + dp = [-1] * n + k = -1 + for j in range(1, n): + while k > -1 and needle[k + 1] != needle[j]: + k = dp[k] # 如果下一位不同,回溯到前一個前綴片段 + if needle[k + 1] == needle[j]: + k += 1 # 前綴和後綴片段相同,匹配長度加 1 + dp[j] = k # 更新前綴匹配位置 + return dp + +# 主函式。 +def strStr(haystack: str, needle: str) -> int: + m, n = len(haystack), len(needle) + if n == 0: + return 0 # Edge case for an empty needle + + dp = computeDp(needle) + k = -1 + for i in range(m): + while k > -1 and needle[k + 1] != haystack[i]: + k = dp[k] # 如果下一位不同,回溯到前一個相同片段 + if needle[k + 1] == haystack[i]: + k += 1 # 片段相同,匹配長度加 1 + if k == n - 1: + return i - n + 1 # 匹配完成 + return -1 + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md new file mode 100644 index 00000000..6576e517 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/11-5-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 63 +--- + +# 11.5 練習 + +## 基礎難度 + +### [409. Longest Palindrome](https://leetcode.com/problems/longest-palindrome/) + +計算一組字符可以構成的回文字符串的最大長度,可以使用其他資料結構進行輔助統計。 + +--- + +### [3. Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) + +計算最長無重複子字符串的長度,同樣可以使用其他資料結構進行輔助統計。 + +--- + +## 進階難度 + +### [772. Basic Calculator III](https://leetcode.com/problems/basic-calculator-iii/) + +題目 227 的 follow-up,非常推薦練習。 + +--- + +### [5. Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/) + +類似於我們之前講過的子序列問題,子陣列或子字符串問題常常也可以用動態規劃來解決。先用動態規劃寫出一個 $O(n^2)$ 時間複雜度的解法,然後搜索一下 Manacher’s Algorithm,它可以在 $O(n)$ 時間內解決這個問題。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json new file mode 100644 index 00000000..bf71f88e --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/11-string-manipulation/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "11. 頭痛的字串處理", + "position": 11, + "link": { + "type": "generated-index", + "description": "第 11 章 頭痛的字串處理" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md new file mode 100644 index 00000000..d62d5040 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-1-data-structure-introduction.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 64 +--- + +# 12.1 資料結構介紹 + +(單向)`鏈結串列`是由節點與指標構成的資料結構,每個節點存有一個值,以及一個指向下一個節點的指標。因此,許多鏈結串列問題可以使用遞迴來處理。不同於陣列,鏈結串列無法直接獲取任意節點的值,必須透過指標找到該節點後才能取得其值。同樣地,在未遍歷至鏈結串列結尾前,我們無法得知其長度,除非依賴其他資料結構來儲存長度。LeetCode 預設的鏈結串列表示方法如下。 + + + + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + + + + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + + + + + +由於在進行鏈結串列操作時,特別是刪除節點時,經常因為直接操作當前節點而導致記憶體或指標出現問題。有兩個小技巧可以解決這個問題: + +1. 儘量操作當前節點的下一個節點,而非當前節點本身。 +2. 建立一個虛擬節點 (dummy node),使其指向當前鏈結串列的頭節點。這樣即使原鏈結串列中的所有節點全被刪除,虛擬節點依然存在,最終返回 `dummy->next` 即可。 + +:::warning + +一般來說,演算法題不需要釋放記憶體。在刷 LeetCode 的時候,若需要刪除一個節點,可以直接進行指標操作而無需回收記憶體。但在實際軟體工程中,對於無用的記憶體,建議盡量顯式釋放,或者使用智能指標進行管理。 + +::: \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx new file mode 100644 index 00000000..0ac10156 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-2-basic-linked-list-operations.mdx @@ -0,0 +1,272 @@ +--- +sidebar_position: 65 +--- + +# 12.2 链表的基本操作 + +## [206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) + +### 題目描述 + +翻轉一個鏈結串列。 + +### 輸入輸出範例 + +輸入一個鏈結串列,輸出該鏈結串列翻轉後的結果。 + +``` +Input: 1->2->3->4->5->nullptr +Output: 5->4->3->2->1->nullptr +``` + +### 題解 + +鏈結串列翻轉是非常基礎也必須掌握的技能。我們提供了兩種寫法——遞迴和非遞迴。建議同時掌握這兩種寫法。 + +遞迴的寫法為: + + + + +```cpp +ListNode* reverseList(ListNode* head, ListNode* head_prev = nullptr) { + if (head == nullptr) { + return head_prev; + } + ListNode* head_next = head->next; + head->next = head_prev; + return reverseList(head_next, head); +} +``` + + + + +```py +def reverseList( + head: Optional[ListNode], head_prev: Optional[ListNode] = None +) -> Optional[ListNode]: + if head is None: + return head_prev + head_next = head.next + head.next = head_prev + return reverseList(head_next, head) +``` + + + + + +非遞迴的寫法為: + + + + +```cpp +ListNode* reverseList(ListNode* head) { + ListNode *head_prev = nullptr, *head_next; + while (head) { + head_next = head->next; + head->next = head_prev; + head_prev = head; + head = head_next; + } + return head_prev; +} +``` + + + + +```py +def reverseList(head: Optional[ListNode]) -> Optional[ListNode]: + head_prev = None + while head is not None: + head_next = head.next + head.next = head_prev + head_prev = head + head = head_next + return head_prev +``` + + + + + +## [21. Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) + +### 題目描述 + +給定兩個遞增排序的鏈結串列,將它們合併成一個遞增排序的鏈結串列。 + +### 輸入輸出範例 + +輸入:兩個鏈結串列。 +輸出:一個鏈結串列,表示合併的結果。 + +``` +Input: 1->2->4, 1->3->4 +Output: 1->1->2->3->4->4 +``` + +### 題解 + +我們提供遞迴與非遞迴兩種寫法。 +遞迴的寫法如下: + + + + +```cpp +ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (l2 == nullptr) { + return l1; + } + if (l1 == nullptr) { + return l2; + } + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } + l2->next = mergeTwoLists(l1, l2->next); + return l2; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + if l1 is None or l2 is None: + return l1 or l2 + if l1.val < l2.val: + l1.next = mergeTwoLists(l1.next, l2) + return l1 + l2.next = mergeTwoLists(l1, l2.next) + return l2 +``` + + + + + +非遞迴的寫法為: + + + + +```cpp +ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { + ListNode *dummy = new ListNode(0), *node = dummy; + while (l1 && l2) { + if (l1->val < l2->val) { + node->next = l1; + l1 = l1->next; + } else { + node->next = l2; + l2 = l2->next; + } + node = node->next; + } + node->next = l1 == nullptr ? l2 : l1; + return dummy->next; +} +``` + + + + +```py +def mergeTwoLists( + l1: Optional[ListNode], l2: Optional[ListNode] +) -> Optional[ListNode]: + dummy = ListNode() + head = dummy + + while l1 and l2: + if l1.val < l2.val: + dummy.next = l1 + l1 = l1.next + else: + dummy.next = l2 + l2 = l2.next + dummy = dummy.next + + dummy.next = l1 or l2 + return head.next + +``` + + + + + +## [24. Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) + +### 題目描述 + +給定一個鏈結串列,交換每一對相鄰的節點。 + +### 輸入輸出範例 + +輸入一個鏈結串列,輸出交換後的鏈結串列。 + +``` +Input: 1->2->3->4 +Output: 2->1->4->3 +``` + +### 題解 + +使用指標進行交換操作,題目難度不高,但需要細心。 + + + + +```cpp +ListNode* swapPairs(ListNode* head) { + ListNode *node1 = head, *node2; + if (node1 && node1->next) { + node2 = node1->next; + node1->next = node2->next; + node2->next = node1; + head = node2; + while (node1->next && node1->next->next) { + node2 = node1->next->next; + node1->next->next = node2->next; + node2->next = node1->next; + node1->next = node2; + node1 = node2->next; + } + } + return head; +} +``` + + + + +```py +def swapPairs(head: Optional[ListNode]) -> Optional[ListNode]: + node1 = head + if node1 is not None and node1.next is not None: + node2 = node1.next + node1.next = node2.next + node2.next = node1 + head = node2 + while node1.next is not None and node1.next.next is not None: + node2 = node1.next.next + node1.next.next = node2.next + node2.next = node1.next + node1.next = node2 + node1 = node2.next + return head +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx new file mode 100644 index 00000000..9a253ec6 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-3-other-linked-list-techniques.mdx @@ -0,0 +1,143 @@ +--- +sidebar_position: 66 +--- + +# 12.3 其他鏈結串列技巧 + +## [160. Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists/) + +### 題目描述 + +給定兩個鏈結串列,判斷它們是否在某一個節點相交,並找出相交的節點。 + +### 輸入輸出範例 + +輸入為兩條鏈結串列,輸出為相交的節點。如果沒有相交節點,則回傳 `nullptr`。 + +``` +Input: +A: a1 -> a2 + | + v + c1 -> c2 -> c3 + ^ + | +B: b1 -> b2 -> b3 +Output: c1 +``` + +### 題解 + +假設鏈結串列 A 的起點到相交點的距離是 `a`,鏈結串列 B 的起點到相交點的距離是 `b`,而相交點到串列尾端的距離為 `c`。 + +我們可以用兩個指標,分別從兩個鏈結串列的起點開始,並以相同的速度向前移動。如果指標到達串列的尾端,就切換到另一個鏈結串列的起點繼續移動。透過這種方式,兩個指標在經過 `a + b + c` 次移動後,會同時抵達相交的節點。 + + + + +```cpp +ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + ListNode *l1 = headA, *l2 = headB; + while (l1 != l2) { + l1 = l1 != nullptr ? l1->next : headB; + l2 = l2 != nullptr ? l2->next : headA; + } + return l1; +} +``` + + + + +```py +def getIntersectionNode( + headA: ListNode, headB: ListNode +) -> Optional[ListNode]: + l1 = headA + l2 = headB + while l1 != l2: + l1 = l1.next if l1 is not None else headB + l2 = l2.next if l2 is not None else headA + return l1 +``` + + + + + +## [234. Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list/) + +### 題目描述 + +以 $O(1)$ 的空間複雜度,判斷鏈結串列是否為回文。 + +### 輸入輸出範例 + +輸入是一個鏈結串列,輸出是一個布林值,表示鏈結串列是否為回文。 + +``` +Input: 1->2->3->2->1 +Output: true +``` + +### 題解 + +先使用快慢指標找到鏈結串列的中點,再把鏈結串列切成兩半;然後把後半段翻轉;最後比較兩半是否相等。 + + + + + +```cpp +bool isPalindrome(ListNode* head) { + if (head == nullptr || head->next == nullptr) { + return true; + } + ListNode *slow = head, *fast = head; + while (fast->next && fast->next->next) { + slow = slow->next; + fast = fast->next->next; + } + slow->next = reverseList(slow->next); // 見題目206 + slow = slow->next; + while (slow != nullptr) { + if (head->val != slow->val) { + return false; + } + head = head->next; + slow = slow->next; + } + return true; +} +``` + + + + +```py +def isPalindrome(head: Optional[ListNode]) -> bool: + if head is None or head.next is None: + return True + + slow, fast = head, head + + while fast.next is not None and fast.next.next is not None: + slow = slow.next + fast = fast.next.next + + slow.next = reverseList(slow.next) # 見題目206 + slow = slow.next + + while slow is not None: + if head.val != slow.val: + return False + head = head.next + slow = slow.next + + return True + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md new file mode 100644 index 00000000..3310590f --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/12-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 67 +--- + +# 12.4 練習 + +## 基礎難度 + +### [83. Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) + +雖然 LeetCode 並未強制要求,但我們仍然建議回收記憶體,特別是在題目要求刪除節點時。 + +--- + +### [328. Odd Even Linked List](https://leetcode.com/problems/odd-even-linked-list/) + +這道題其實很簡單,千萬不要把題目複雜化。 + +--- + +### [19. Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/) + +既然可以使用快慢指針找到鏈結串列的中點,也可以利用類似的方法找到倒數第 N 個節點,無需再次遍歷。 + +--- + +## 進階難度 + +### [148. Sort List](https://leetcode.com/problems/sort-list/) + +利用快慢指針找到鏈結串列的中點後,可以對鏈結串列進行合併排序。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json new file mode 100644 index 00000000..cec51af2 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/12-linked-lists/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "12. 指標三劍客之一:鏈結串列", + "position": 12, + "link": { + "type": "generated-index", + "description": "第 12 章 指標三劍客之一:鏈結串列" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx new file mode 100644 index 00000000..b1d3f9b6 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-1-data-structure-introduction.mdx @@ -0,0 +1,36 @@ +--- +sidebar_position: 68 +--- + +# 13.1 資料結構介紹 + +作為(單)鏈結串列的升級版,我們通常接觸的樹都是`二元樹`(binary tree),即每個節點最多有兩個子節點;且除非題目說明,預設樹中不存在循環結構。LeetCode 預設的樹表示方法如下。 + + + + +```cpp +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode(int x) : val(x), left(NULL), right(NULL) {} +}; +``` + + + + +```py +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right +``` + + + + + +可以看出,其與鏈結串列的主要差別就是多了一個子節點的指標。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx new file mode 100644 index 00000000..3c0ad993 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-2-tree-recursion.mdx @@ -0,0 +1,481 @@ +--- +sidebar_position: 69 +--- + +# 13.2 樹的遞迴 + +對於一些簡單的遞迴題,某些 LeetCode 達人喜歡寫 one-line code,即用一行程式碼解決問題。我們也會展示一些這樣的程式碼,但對於新手,筆者仍然建議您使用多行的 if-else 判斷語句。 + +在許多情況下,樹遞迴的寫法與深度優先搜索的遞迴寫法相同,因此本書不會區分兩者。 + +## [104. Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) + +### 題目描述 + +求一個二元樹的最大深度。 + +### 輸入輸出範例 + +輸入是一個二元樹,輸出是一個整數,表示該樹的最大深度。 + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: 3 +``` + +### 題解 + +利用遞迴,我們可以很方便地求得最大深度。 + + + + +```cpp +int maxDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + return max(maxDepth(root->left), maxDepth(root->right)) + 1; +} +``` + + + + +```py +def maxDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + return max(maxDepth(root.left), maxDepth(root.right)) + 1 +``` + + + + + +## [110. Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) + +### 題目描述 + +判斷一個二元樹是否平衡。平衡樹的定義是:對於樹上的任意節點,其左右子節點的最大深度差不得超過 1。 + +### 輸入輸出範例 + +輸入是一個二元樹,輸出是一個布林值,表示該樹是否平衡。 + +``` +Input: + 1 + / \ + 2 2 + / \ + 3 3 + / \ +4 4 +Output: false +``` + +### 題解 + +解法類似於計算樹的最大深度,但有兩個不同點: + +1. 必須先計算子樹的深度,再進行比較。 +2. 如果在處理子樹時發現該子樹已經不平衡,則立即返回 -1,讓其祖先節點能避免不必要的判斷。(本題的判斷相對簡單,只需計算深度差的絕對值即可;但如果比較過程較為複雜,避免重複判斷可以節省大量計算時間。) + + + + +```cpp +// 輔助函式。 +int balancedDepth(TreeNode* root) { + if (root == nullptr) { + return 0; + } + int left = balancedDepth(root->left); + int right = balancedDepth(root->right); + if (left == -1 || right == -1 || abs(left - right) > 1) { + return -1; + } + return max(left, right) + 1; +} +// 主函式。 +bool isBalanced(TreeNode* root) { return balancedDepth(root) != -1; } +``` + + + + +```py +# 輔助函式。 +def balancedDepth(root: Optional[TreeNode]) -> int: + if root is None: + return 0 + left = balancedDepth(root.left) + right = balancedDepth(root.right) + if left == -1 or right == -1 or abs(left - right) > 1: + return -1 + return max(left, right) + 1 + +# 主函式。 +def isBalanced(root: Optional[TreeNode]) -> bool: + return balancedDepth(root) != -1 + +``` + + + + + +## [543. Diameter of Binary Tree](https://leetcode.com/problems/diameter-of-binary-tree/) + +### 題目描述 + +求一個二元樹的最長直徑。直徑的定義是二元樹上任意兩節點之間的無向距離。 + +### 輸入輸出範例 + +輸入是一個二元樹,輸出是一個整數,表示最長直徑。 + +``` +Input: + 1 + / \ + 2 3 + / \ + 4 5 +Output: 3 +``` + +在這個範例中,最長直徑是 [4,2,1,3] 和 [5,2,1,3]。 + +### 題解 + +我們可以利用遞迴來處理二元樹。在解題時需要注意一點:當我們處理某個子樹時,我們更新的最長直徑值和遞迴返回的值是不相同的。 + +更新的最長直徑值是指經過該子樹根節點的最長直徑(也就是左右子樹的長度總和);而函數返回的值則是以該子樹根節點為端點的最長直徑(也就是單側子樹的長度)。這樣設計返回值,可以遞迴地更新父節點的最長直徑。 + + + + +```cpp +// 輔助函式。 +int updateDiameter(TreeNode* node, int& diameter) { + if (node == nullptr) { + return 0; + } + int left = updateDiameter(node->left, diameter); + int right = updateDiameter(node->right, diameter); + diameter = max(diameter, left + right); + return max(left, right) + 1; +} +// 主函式。 +int diameterOfBinaryTree(TreeNode* root) { + int diameter = 0; + updateDiameter(root, diameter); + return diameter; +} +``` + + + + +```py +# 輔助函式。 +def updateDiameter(node: Optional[TreeNode], diameter: List[int]) -> int: + if node is None: + return 0 + left = updateDiameter(node.left, diameter) + right = updateDiameter(node.right, diameter) + diameter[0] = max(diameter[0], left + right) + return max(left, right) + 1 + +# 主函式。 +def diameterOfBinaryTree(root: Optional[TreeNode]) -> int: + diameter = [0] + updateDiameter(root, diameter) + return diameter[0] + +``` + + + + + +## [437. Path Sum III](https://leetcode.com/problems/path-sum-iii/) + +### 題目描述 + +給定一個整數二元樹,求路徑節點值的總和等於給定目標值的路徑數量。 + +### 輸入輸出範例 + +輸入是一個二元樹和一個目標整數。輸出是一個整數,表示滿足條件的路徑數量。 + +``` +Input: sum = 8, tree = + 10 + / \ + 5 -3 + / \ \ + 3 2 11 + / \ \ + 3 -2 1 +Output: 3 +``` + +在這個例子中,總和為 8 的路徑共有三條:`[[5,3],[5,2,1],[-3,11]]`。 + +### 題解 + +在遞迴處理每個節點時,需要分為兩種情況考慮: +1. 若選取當前節點加入路徑,則之後的節點必須連續加入,或停止加入。 +2. 若不選取當前節點,則需對其左右子節點重新進行考慮。 + +為此,我們可以建立一個輔助函式,專門計算從當前節點開始的連續路徑數量。 + + + + +```cpp +// 輔助函式。 +// 使用 long long 防止 test case 中出現大數溢位,通常情況下 int 即可。 +long long pathSumStartWithRoot(TreeNode* root, long long targetSum) { + if (root == nullptr) { + return 0; + } + return (root->val == targetSum) + + pathSumStartWithRoot(root->left, targetSum - root->val) + + pathSumStartWithRoot(root->right, targetSum - root->val); +} +// 主函式。 +int pathSum(TreeNode* root, int targetSum) { + if (root == nullptr) { + return 0; + } + return pathSumStartWithRoot(root, targetSum) + + pathSum(root->left, targetSum) + pathSum(root->right, targetSum); +} +``` + + + + +```py +# 輔助函式。 +def pathSumStartWithRoot(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + int(root.val == targetSum) + + pathSumStartWithRoot(root.left, targetSum - root.val) + + pathSumStartWithRoot(root.right, targetSum - root.val) + ) + +# 主函式。 +def pathSum(root: Optional[TreeNode], targetSum: int) -> int: + if root is None: + return 0 + return ( + pathSumStartWithRoot(root, targetSum) + + pathSum(root.left, targetSum) + + pathSum(root.right, targetSum) + ) + +``` + + + + + +## [101. Symmetric Tree](https://leetcode.com/problems/symmetric-tree/) + +### 題目描述 + +判斷一個二元樹是否對稱。 + +### 輸入輸出範例 + +輸入一個二元樹,輸出一個布林值,表示該樹是否對稱。 + +``` +Input: + 1 + / \ + 2 2 + / \ / \ +3 4 4 3 +Output: true +``` + +### 題解 + +判斷一棵樹是否對稱等價於判斷左右子樹是否對稱。筆者一般習慣將判斷兩個子樹是否相等或對稱類型的題解法稱為「四步法」: +1. 如果兩個子樹都為空指標,則它們相等或對稱。 +2. 如果兩個子樹只有一個為空指標,則它們不相等或不對稱。 +3. 如果兩個子樹根節點的值不相等,則它們不相等或不對稱。 +4. 根據相等或對稱的要求,進行遞迴處理。 + + + + +```cpp +// 輔助函式。 +bool isLeftRightSymmetric(TreeNode* left, TreeNode* right) { + if (left == nullptr && right == nullptr) { + return true; + } + if (left == nullptr or right == nullptr) { + return false; + } + if (left->val != right->val) { + return false; + } + return isLeftRightSymmetric(left->left, right->right) && + isLeftRightSymmetric(left->right, right->left); +} +// 主函式。 +bool isSymmetric(TreeNode* root) { + if (root == nullptr) { + return true; + } + return isLeftRightSymmetric(root->left, root->right); +} +``` + + + + +```py +# 輔助函式。 +def isLeftRightSymmetric( + left: Optional[TreeNode], right: Optional[TreeNode] +) -> bool: + if left is None and right is None: + return True + if left is None or right is None: + return False + if left.val != right.val: + return False + return ( + isLeftRightSymmetric(left.left, right.right) and + isLeftRightSymmetric(left.right, right.left) + ) + +# 主函式。 +def isSymmetric(root: Optional[TreeNode]) -> bool: + if root is None: + return True + return isLeftRightSymmetric(root.left, root.right) + +``` + + + + + +## [1110. Delete Nodes And Return Forest](https://leetcode.com/problems/delete-nodes-and-return-forest/) + +### 題目描述 + +給定一個整數二元樹和一些整數,求刪掉這些整數對應的節點後,剩餘的子樹。 + +### 輸入輸出範例 + +輸入是一個整數二元樹和一維整數陣列,輸出是一個陣列,每個位置儲存一個子樹(的根節點)。 + +``` +Input: to_delete = [3,5], tree = + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 +Output: [ + 1 + / + 2 + / +4 ,6 ,7] +``` + +### 題解 + +本題主要需要注意的細節包括如何透過遞迴處理原樹,以及在何時斷開指標。同時,為了方便尋找待刪除的節點,可以建立一個雜湊表進行快速查找。筆者強烈建議讀者在看完題解後,自己實現一次本題,加深對於遞迴的理解與運用能力。 + + + + +```cpp +// 輔助函式。 +TreeNode* moveNodesToForest(TreeNode* root, unordered_set& undeleted, + vector& forest) { + if (root == nullptr) { + return nullptr; + } + root->left = moveNodesToForest(root->left, undeleted, forest); + root->right = moveNodesToForest(root->right, undeleted, forest); + if (undeleted.contains(root->val)) { + if (root->left != nullptr) { + forest.push_back(root->left); + } + if (root->right != nullptr) { + forest.push_back(root->right); + } + root = nullptr; + } + return root; +} +// 主函式。 +vector delNodes(TreeNode* root, vector& to_delete) { + vector forest; + unordered_set undeleted(to_delete.begin(), to_delete.end()); + root = moveNodesToForest(root, undeleted, forest); + if (root != nullptr) { + forest.push_back(root); + } + return forest; +} +``` + + + + +```py +# 輔助函式。 +def moveNodesToForest( + root: Optional[TreeNode], undeleted: Set[int], forest: List[TreeNode] +) -> Optional[TreeNode]: + if root is None: + return None + + root.left = moveNodesToForest(root.left, undeleted, forest) + root.right = moveNodesToForest(root.right, undeleted, forest) + + if root.val in undeleted: + if root.left is not None: + forest.append(root.left) + if root.right is not None: + forest.append(root.right) + root = None + + return root + +# 主函式。 +def delNodes(root: Optional[TreeNode], to_delete: List[int]) -> List[TreeNode]: + forest = [] + undeleted = set(to_delete) + root = moveNodesToForest(root, undeleted, forest) + if root is not None: + forest.append(root) + return forest + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx new file mode 100644 index 00000000..e5192862 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-3-level-order-traversal.mdx @@ -0,0 +1,92 @@ +--- +sidebar_position: 70 +--- + +# 13.3 層次遍歷 + +我們可以使用廣度優先搜尋進行層次遍歷。注意,不需要使用兩個佇列來分別儲存當前層的節點和下一層的節點,因為在開始遍歷一層節點時,當前佇列中的節點數就是當前層的節點數,只要控制遍歷這麼多節點數,就能保證這次遍歷的都是當前層的節點。 + +## [637. Average of Levels in Binary Tree](https://leetcode.com/problems/average-of-levels-in-binary-tree/) + +### 題目描述 + +給定一個二元樹,求每一層的節點值的平均數。 + +### 輸入輸出範例 + +輸入是一個二元樹,輸出是一個一維陣列,表示每層節點值的平均數。 + +``` +Input: + 3 + / \ + 9 20 + / \ + 15 7 +Output: [3, 14.5, 11] +``` + +### 題解 + +利用廣度優先搜尋,我們可以很方便地求取每層的平均值。 + + + + +```cpp +vector averageOfLevels(TreeNode* root) { + vector level_avg; + if (root == nullptr) { + return level_avg; + } + queue q; + q.push(root); + int count = q.size(); + while (count > 0) { + double level_sum = 0; + for (int i = 0; i < count; ++i) { + TreeNode* node = q.front(); + q.pop(); + level_sum += node->val; + if (node->left != nullptr) { + q.push(node->left); + } + if (node->right != nullptr) { + q.push(node->right); + } + } + level_avg.push_back(level_sum / count); + count = q.size(); + } + return level_avg; +} +``` + + + + +```py +def averageOfLevels(root: Optional[TreeNode]) -> List[float]: + level_avg = [] + if root is None: + return level_avg + q = collections.deque() + q.append(root) + count = len(q) + while count > 0: + level_sum = 0 + for _ in range(count): + node = q.popleft() + level_sum += node.val + if node.left is not None: + q.append(node.left) + if node.right is not None: + q.append(node.right) + level_avg.append(level_sum / count) + count = len(q) + return level_avg +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx new file mode 100644 index 00000000..b4099c87 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-4-preorder-inorder-postorder-traversal.mdx @@ -0,0 +1,256 @@ +--- +sidebar_position: 71 +--- + +# 13.4 前中後序遍歷 + +前序遍歷、中序遍歷和後序遍歷是三種利用深度優先搜尋(DFS)遍歷二元樹的方式。它們在節點訪問的順序上有所不同,其餘部分完全相同。考慮如下二元樹: + +``` + 1 + / \ + 2 3 + / \ \ +4 5 6 +``` + +前序遍歷先訪問父節點,再訪問左節點,最後訪問右節點,得到的遍歷順序是 [1 2 4 5 3 6]。 + + + + +```cpp +void preorder(TreeNode* root) { + visit(root); + preorder(root->left); + preorder(root->right); +} +``` + + + + +```py +def preorder(root: TreeNode): + visit(root) + preorder(root.left) + preorder(root.right) +``` + + + + + +中序遍歷先訪問左節點,再訪問父節點,最後訪問右節點,得到的遍歷順序是 [4 2 5 1 3 6]。 + + + + +```cpp +void inorder(TreeNode* root) { + inorder(root->left); + visit(root); + inorder(root->right); +} +``` + + + + +```py +def inorder(root: TreeNode): + inorder(root.left) + visit(root) + inorder(root.right) +``` + + + + + +後序遍歷先訪問左節點,再訪問右節點,最後訪問父節點,得到的遍歷順序是 [4 5 2 6 3 1]。 + + + + +```cpp +void postorder(TreeNode* root) { + postorder(root->left); + postorder(root->right); + visit(root); +} +``` + + + + +```py +def postorder(root: TreeNode): + postorder(root.left) + postorder(root.right) + visit(root) +``` + + + + + +## [105. Construct Binary Tree from Preorder and Inorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) + +### 題目描述 + +給定一棵二元樹的前序遍歷和中序遍歷結果,嘗試復原這棵樹。已知樹裡不存在重複值的節點。 + +### 輸入輸出範例 + +輸入是兩個一維陣列,分別表示樹的前序遍歷和中序遍歷結果;輸出是一棵二元樹。 + +``` +Input: preorder = [4,9,20,15,7], inorder = [9,4,15,20,7] +Output: + 4 + / \ + 9 20 + / \ + 15 7 +``` + +### 題解 + +我們通過本題的範例講解一下本題的思路。前序遍歷的第一個節點是 `4`,意味著 `4` 是根節點。我們在中序遍歷結果中找到 `4` 這個節點,根據中序遍歷的性質可以得出: + +- `4` 在中序遍歷陣列中的位置左側子陣列為左子樹,節點數為 `1`,對應的是前序遍歷陣列中 `4` 之後的 `1` 個數字(`9`)。 +- `4` 在中序遍歷陣列中的位置右側子陣列為右子樹,節點數為 `3`,對應的是前序遍歷陣列最後的 `3` 個數字。 + +有了這些訊息,我們可以對左子樹和右子樹進行遞迴復原。為了方便查找數字的位置,我們可以用雜湊表預處理中序遍歷的結果。 + + + + +```cpp +// 輔助函式。 +TreeNode* reconstruct(unordered_map& io_map, vector& po, int l, + int r, int mid_po) { + if (l > r) { + return nullptr; + } + int mid_val = po[mid_po]; + int mid_io = io_map[mid_val]; + int left_len = mid_io - l + 1; + TreeNode* node = new TreeNode(mid_val); + node->left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1); + node->right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len); + return node; +} +// 主函式。 +TreeNode* buildTree(vector& preorder, vector& inorder) { + unordered_map io_map; + for (int i = 0; i < inorder.size(); ++i) { + io_map[inorder[i]] = i; + } + return reconstruct(io_map, preorder, 0, preorder.size() - 1, 0); +} +``` + + + + +```py +# 輔助函式。 +def reconstruct( + io_map: Dict[int, int], po: List[int], l: int, r: int, mid_po: int +) -> Optional[TreeNode]: + if l > r: + return None + mid_val = po[mid_po] + mid_io = io_map[mid_val] + left_len = mid_io - l + 1 + node = TreeNode(mid_val) + node.left = reconstruct(io_map, po, l, mid_io - 1, mid_po + 1) + node.right = reconstruct(io_map, po, mid_io + 1, r, mid_po + left_len) + return node + +# 主函式。 +def buildTree(preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + io_map = {val: i for i, val in enumerate(inorder)} + return reconstruct(io_map, preorder, 0, len(preorder) - 1, 0) + +``` + + + + + +## [144. Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/) + +### 題目描述 + +不使用遞迴,實現二元樹的前序遍歷。 + +### 輸入輸出範例 + +輸入是一棵二元樹,輸出是一個陣列,表示二元樹前序遍歷的結果。 + +``` +Input: + 1 + \ + 2 + / + 3 +Output: [1,2,3] +``` + +### 題解 + +由於遞迴的本質是透過堆疊進行函數調用,因此我們可以使用堆疊來實現前序遍歷。注意進堆疊的順序。 + + + + + +```cpp +vector preorderTraversal(TreeNode* root) { + vector po; + if (root == nullptr) { + return po; + } + stack s; + s.push(root); + while (!s.empty()) { + TreeNode* node = s.top(); + s.pop(); + po.push_back(node->val); + if (node->right) { + s.push(node->right); // 先右後左,保證左子樹先遍歷 + } + if (node->left) { + s.push(node->left); + } + } + return po; +} +``` + + + + +```py +def preorderTraversal(root: Optional[TreeNode]) -> List[int]: + po = [] + if root is None: + return po + s = [root] + while len(s) > 0: + node = s.pop() + po.append(node.val) + if node.right is not None: + s.append(node.right) # 先右後左,保證左子樹先遍歷 + if node.left is not None: + s.append(node.left) + return po +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx new file mode 100644 index 00000000..b0641f4c --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-5-binary-search-tree.mdx @@ -0,0 +1,189 @@ +--- +sidebar_position: 72 +--- + +# 13.5 二元搜尋樹 + +`二元搜尋樹`(Binary Search Tree, BST)是一種特殊的二元樹:對於每個父節點,其左子樹中所有節點的值小於等於父節點的值,其右子樹中所有節點的值大於等於父節點的值。因此對於一個二元搜尋樹,我們可以在 $O(\log n)$ 的時間內查找某值是否存在:從根節點開始,若當前節點的值大於查找值則向左下走,若當前節點的值小於查找值則向右下走。同時因為二元搜尋樹是有序的,對其中序遍歷的結果即為排好序的陣列。 + +例如下面這棵樹即為二元搜尋樹,其中序遍歷結果為 [1, 2, 3, 4, 5, 6]。 + +``` + 4 + / \ + 2 5 + / \ \ +1 3 6 +``` + +## [99. Recover Binary Search Tree](https://leetcode.com/problems/recover-binary-search-tree/) + +### 題目描述 + +給定一個二元搜尋樹,已知有兩個節點被不小心交換了,試復原此樹。 + +### 輸入輸出範例 + +輸入是一個被誤交換兩個節點的二元搜尋樹,輸出是改正後的二元搜尋樹。 + +``` +Input: + 3 + / \ +1 4 + / + 2 +Output: + 2 + / \ +1 4 + / + 3 +``` + +在這個範例中,2 和 3 被不小心交換了。 + +### 題解 + +我們可以使用中序遍歷這個二元搜尋樹,同時設置一個 `prev` 指標,記錄當前節點中序遍歷時的前一節點。如果當前節點的值小於 `prev` 節點的值,說明次序需要調整。有一個技巧是: + +- 如果遍歷整個序列的過程中只出現一次次序錯誤,說明這兩個相鄰節點需要被交換。 +- 如果出現了兩次次序錯誤,則需要交換這兩個節點。 + + + + + +```cpp +// 輔助函式。 +void inorder(TreeNode* root, TreeNode*& mistake1, TreeNode*& mistake2, + TreeNode*& prev) { + if (root == nullptr) { + return; + } + inorder(root->left, mistake1, mistake2, prev); + if (prev != nullptr && root->val < prev->val) { + if (mistake1 == nullptr) { + mistake1 = prev; + } + mistake2 = root; + } + prev = root; + inorder(root->right, mistake1, mistake2, prev); +} +// 主函式。 +void recoverTree(TreeNode* root) { + TreeNode *mistake1 = nullptr, *mistake2 = nullptr, *prev = nullptr; + inorder(root, mistake1, mistake2, prev); + if (mistake1 != nullptr && mistake2 != nullptr) { + swap(mistake1->val, mistake2->val); + } +} +``` + + + + +```py +# 輔助函式。 +# 注意,Python 中並不方便在輔函式中直接傳指標,因此我們建造長度為 1 的 list 進行傳引用。 +def inorder( + root: Optional[TreeNode], + mistake1=List[Optional[TreeNode]], + mistake2=List[Optional[TreeNode]], + prev=List[Optional[TreeNode]], +): + if root is None: + return + inorder(root.left, mistake1, mistake2, prev) + if prev[0] is not None and root.val < prev[0].val: + if mistake1[0] is None: + mistake1[0] = prev[0] + mistake2[0] = root + prev[0] = root + inorder(root.right, mistake1, mistake2, prev) + +# 主函式。 +def recoverTree(root: Optional[TreeNode]) -> None: + mistake1, mistake2, prev = [None], [None], [None] + inorder(root, mistake1, mistake2, prev) + if mistake1[0] is not None and mistake2[0] is not None: + mistake1[0].val, mistake2[0].val = mistake2[0].val, mistake1[0].val +``` + + + + + +## [669. Trim a Binary Search Tree](https://leetcode.com/problems/trim-a-binary-search-tree/) + +### 題目描述 + +給定一個二元搜尋樹和兩個整數 L 和 R,且 L < R,試修剪此二元搜尋樹,使得修剪後所有節點的值都在 [L, R] 的範圍內。 + +### 輸入輸出範例 + +輸入是一個二元搜尋樹和兩個整數 L 和 R,輸出一個被修剪好的二元搜尋樹。 + +``` +Input: L = 1, R = 3, tree = + 3 + / \ + 0 4 + \ + 2 + / + 1 +Output: + 3 + / + 2 + / +1 +``` + +### 題解 + +利用二元搜尋樹的大小關係,我們可以很容易地利用遞迴進行樹的處理。 + + + + +```cpp +TreeNode* trimBST(TreeNode* root, int low, int high) { + if (root == nullptr) { + return root; + } + if (root->val > high) { + return trimBST(root->left, low, high); + } + if (root->val < low) { + return trimBST(root->right, low, high); + } + root->left = trimBST(root->left, low, high); + root->right = trimBST(root->right, low, high); + return root; +} +``` + + + + +```py +def trimBST( + root: Optional[TreeNode], low: int, high: int +) -> Optional[TreeNode]: + if root is None: + return None + if root.val > high: + return trimBST(root.left, low, high) + if root.val < low: + return trimBST(root.right, low, high) + root.left = trimBST(root.left, low, high) + root.right = trimBST(root.right, low, high) + return root +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx new file mode 100644 index 00000000..412a4b6c --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-6-trie.mdx @@ -0,0 +1,137 @@ +--- +sidebar_position: 73 +--- + +# 13.6 字典樹 + +字典樹(Trie)用於判斷字串是否存在或者是否具有某種字串前綴。 + +
+ + ![](13.1.png) + +
圖 13.1: 字典樹,儲存了單字 A、to、tea、ted、ten、i、in 和 inn,以及它們的頻率
+
+ +為什麼需要用字典樹解決這類問題呢?假如我們有一個儲存了近萬個單字的字典,即使我們使用雜湊表,在其中搜尋一個單字的實際開銷也是非常大的,且無法輕易支援搜尋單字前綴。然而由於一個英文單字的長度 n 通常在 10 以內,如果我們使用字典樹,則可以在 $O(n)$——近似 $O(1)$ 的時間內完成搜尋,且額外開銷非常小。 + +## [208. Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) + +### 題目描述 + +嘗試建立一個字典樹,支援快速插入單字、查找單字、查找單字前綴的功能。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。 + +``` +Trie trie = new Trie(); +trie.insert("apple"); +trie.search("apple"); // true +trie.search("app"); // false +trie.startsWith("app"); // true +trie.insert("app"); +trie.search("app"); // true +``` + +### 題解 + +以下是字典樹的典型實現方法。 + + + + +```cpp +struct TrieNode { + bool word_ends; + vector children; + TrieNode() : word_ends(false), children(26, nullptr) {} +}; + +class Trie { + public: + Trie() : root_(new TrieNode()) {} + + void insert(string word) { + TrieNode* node = root_; + for (char c : word) { + int pos = c - ’a’; + if (node->children[pos] == nullptr) { + node->children[pos] = new TrieNode(); + } + node = node->children[pos]; + } + node->word_ends = true; + } + + bool search(string word) { + TrieNode* node = root_; + for (char c : word) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr && node->word_ends; + } + + bool startsWith(string prefix) { + TrieNode* node = root_; + for (char c : prefix) { + if (node == nullptr) { + break; + } + node = node->children[c - ’a’]; + } + return node != nullptr; + } + + private: + TrieNode* root_; +}; +``` + + + + +```py +class TrieNode: + def __init__(self): + self.word_ends = False + self.children = [None] * 26 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word: str) -> None: + node = self.root + for c in word: + pos = ord(c) - ord("a") + if node.children[pos] is None: + node.children[pos] = TrieNode() + node = node.children[pos] + node.word_ends = True + + def search(self, word: str) -> bool: + node = self.root + for c in word: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None and node.word_ends + + def startsWith(self, prefix: str) -> bool: + node = self.root + for c in prefix: + if node is None: + break + node = node.children[ord(c) - ord("a")] + return node is not None + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md new file mode 100644 index 00000000..ac9e968e --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13-7-exercises.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 74 +--- + +# 13.7 練習 + +## 基礎難度 + +### [226. Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) + +巧用遞迴,你可以在五行內完成這道題。 + +--- + +### [617. Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees/) + +同樣的,利用遞迴可以輕鬆搞定。 + +--- + +### [572. Subtree of Another Tree](https://leetcode.com/problems/subtree-of-another-tree/) + +子樹是對稱樹的姊妹題,寫法也十分類似。 + +--- + +### [404. Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves/) + +怎麼判斷一個節點是不是左節點呢?一種可行的方法是,在輔函式裡多傳一個參數,表示當前節點是不是父節點的左節點。 + +--- + +### [513. Find Bottom Left Tree Value](https://leetcode.com/problems/find-bottom-left-tree-value/) + +最左下角的節點滿足什麼條件?針對這種條件,我們該如何找到它? + +--- + +### [538. Convert BST to Greater Tree](https://leetcode.com/problems/convert-bst-to-greater-tree/) + +嘗試利用某種遍歷方式來解決此題,每個節點只需遍歷一次。 + +--- + +### [235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) + +利用 BST 的獨特性質,這道題可以很輕鬆完成。 + +--- + +### [530. Minimum Absolute Difference in BST](https://leetcode.com/problems/minimum-absolute-difference-in-bst/) + +還記得我們所說的,對於 BST 應該利用哪種遍歷嗎? + +--- + +## 進階難度 + +### [1530. Number of Good Leaf Nodes Pairs](https://leetcode.com/problems/number-of-good-leaf-nodes-pairs/) + +題目 543 的變種題,注意在輔函式中,每次更新的全域變數是左右兩邊距離之和滿足條件的數量,而返回的是左右兩邊所有(長度不溢出的)子節點的高度 +1。 + +--- + +### [889. Construct Binary Tree from Preorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) + +給定任意兩種遍歷結果,我們都可以重建樹的結構。 + +--- + +### [106. Construct Binary Tree from Inorder and Postorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) + +給定任意兩種遍歷結果,我們都可以重建樹的結構。 + +--- + +### [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) + +因為前中序後遍歷是用遞迴實現的,而遞迴的底層實現是堆疊操作,因此我們總能用堆疊實現。 + +--- + +### [145. Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/) + +因為前中序後遍歷是用遞迴實現的,而遞迴的底層實現是堆疊操作,因此我們總能用堆疊實現。 + +--- + +### [236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) + +現在不是 BST,而是普通的二元樹了,該怎麼辦? + +--- + +### [109. Convert Sorted List to Binary Search Tree](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) + +把排好序的鏈結串列變成 BST。為了使得 BST 盡量平衡,我們需要尋找鏈結串列的中點。 + +--- + +### [897. Increasing Order Search Tree](https://leetcode.com/problems/increasing-order-search-tree/) + +把 BST 壓成一個鏈結串列,務必考慮清楚指標操作的順序,否則可能會出現環路。 + +--- + +### [653. Two Sum IV - Input is a BST](https://leetcode.com/problems/two-sum-iv-input-is-a-bst/) + +啊哈,這道題可能會把你騙到。 + +--- + +### [450. Delete Node in a BST](https://leetcode.com/problems/delete-node-in-a-bst/) + +當尋找到待刪節點時,你可以分情況考慮——當前節點是葉節點、只有一個子節點和有兩個子節點。建議同時回收記憶體。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13.1.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13.1.png new file mode 100644 index 00000000..06c168c6 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/13.1.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/_category_.json new file mode 100644 index 00000000..4a692469 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/13-trees/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "13. 指標三劍客之二:樹", + "position": 13, + "link": { + "type": "generated-index", + "description": "第 13 章 指標三劍客之二:樹" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx new file mode 100644 index 00000000..b5c858b8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-1-data-structure-introduction.mdx @@ -0,0 +1,16 @@ +--- +sidebar_position: 75 +--- + +# 14.1 資料結構介紹 + +作為指標三劍客之一,圖是樹的升級版。`圖`通常可以分為有向(directed)或無向(undirected)、有循環(cyclic)或無循環(acyclic)、所有節點相連(connected)或不相連(disconnected)。樹其實就是一種相連的無向無環圖,而另一種很常見的圖則是`有向無環圖`(Directed Acyclic Graph,DAG)。 + +
+ + ![](14.1.png) + +
圖 14.1: 有向無環圖範例
+
+ +圖通常有兩種表示方法。假設圖中有 `n` 個節點和 `m` 條邊。第一種表示方法是`鄰接矩陣`(adjacency matrix):我們可以建立一個 `n × n` 的矩陣 `G`,如果第 `i` 個節點連向第 `j` 個節點,則 `G[i][j] = 1`,反之為 `0`;如果圖是無向的,則此矩陣必定是對稱矩陣,即 `G[i][j] = G[j][i]`。第二種表示方法是`鄰接鏈結串列`(adjacency list):我們可以建立一個大小為 `n` 的陣列,每個位置 `i` 儲存一個陣列或鏈結串列,表示第 `i` 個節點連向的其他節點。鄰接矩陣的空間開銷比鄰接鏈結串列大,但鄰接鏈結串列不支援快速查找節點 `i` 和節點 `j` 是否相連。因此,可以根據題目的需要選擇適合的表示方法。此外,我們也可以直接用一個 `m × 2` 的矩陣來儲存所有的邊。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx new file mode 100644 index 00000000..95cc7555 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-2-bipartite-graph.mdx @@ -0,0 +1,90 @@ +--- +sidebar_position: 76 +--- + +# 14.2 二分圖 + +`二分圖`演算法也稱為`染色法`,是一種廣度優先搜索。如果能用兩種顏色對圖中的節點進行著色,且保證相鄰的節點顏色不同,那麼這個圖就是二分圖。 + +## [785. Is Graph Bipartite?](https://leetcode.com/problems/is-graph-bipartite/) + +### 題目描述 + +給定一個圖,判斷它是否可以二分。 + +### 輸入輸出範例 + +輸入是一個鄰接鏈結串列表示的圖(例如位置 0 的鄰接鏈結串列為 `[1,3]`,表示節點 0 與節點 1 相連,節點 0 與節點 3 相連);輸出是一個布林值,表示圖是否二分。 + +``` +Input: [[1,3], [0,2], [1,3], [0,2]] +0----1 +| | +| | +3----2 +Output: true +``` + +在這個範例中,我們可以把 `{0,2}` 分為一組,把 `{1,3}` 分為另一組。 + +### 題解 + +利用佇列和廣度優先搜索,我們可以對未著色的節點進行著色,並檢查是否存在顏色相同的相鄰節點。注意在程式碼中,我們使用 `0` 表示未檢查的節點,使用 `1` 和 `2` 表示兩種不同的顏色。 + + + + +```cpp +bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n, 0); + queue q; + for (int i = 0; i < n; ++i) { + if (color[i] == 0) { + q.push(i); + color[i] = 1; + } + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int j : graph[node]) { + if (color[j] == 0) { + q.push(j); + color[j] = color[node] == 2 ? 1 : 2; + } else if (color[j] == color[node]) { + return false; + } + } + } + } + return true; +} +``` + + + + +```py +def isBipartite(graph: List[List[int]]) -> bool: + n = len(graph) + color = [0] * n + q = collections.deque() + + for i in range(n): + if color[i] == 0: + q.append(i) + color[i] = 1 + while len(q) > 0: + node = q.popleft() + for j in graph[node]: + if color[j] == 0: + q.append(j) + color[j] = 1 if color[node] == 2 else 2 + elif color[j] == color[node]: + return False + return True +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx new file mode 100644 index 00000000..0e48f56a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-3-topological-sorting.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 77 +--- + +# 14.3 拓撲排序 + +`拓撲排序`(topological sort)是一種常見的算法,用於對有向無環圖(DAG)進行排序。給定 DAG 中的 $N$ 個節點,我們需要將它們排序成一個線性序列;如果節點 $i$ 指向節點 $j$,則排序結果中 $i$ 必須在 $j$ 之前。拓撲排序的結果並不唯一,只要滿足以上條件即可。 + +## [210. Course Schedule II](https://leetcode.com/problems/course-schedule-ii/) + +### 題目描述 + +給定 $N$ 門課程以及它們的前置必修課,找出可以一次性完成所有課程的修課順序。 + +### 輸入輸出範例 + +輸入是一個正整數,表示課程數量,以及一個二維陣列,表示所有的有向邊(例如 `[1,0]` 表示課程 1 必須在課程 0 之後修完)。輸出是一個一維陣列,表示拓撲排序的結果。 + +``` +Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] +Output: [0,1,2,3] +``` + +在這個例子中,另一種可行的順序是 `[0,2,1,3]`。 + +### 題解 + +我們可以先建立一個鄰接矩陣來表示圖,方便進行直接查找。這裡注意,我們將所有的邊進行反向處理,使得如果課程 $i$ 指向課程 $j$,表示課程 $i$ 必須在課程 $j$ 之前完成。這樣處理更符合我們對前置課程的直觀理解。 + +拓撲排序可以看作是廣度優先搜索(BFS)的一種特殊情況: + +1. 遍歷所有節點,將入度為 $0$ 的節點(即無前置課程要求的節點)加入隊列。 +2. 處理隊列中的節點: + - 將當前節點加入排序結果中。 + - 將當前節點指向的所有節點的入度減少 $1$。 + - 如果某個節點的入度變為 $0$,將該節點加入隊列。 +3. 當隊列處理完畢後,若所有節點均已排序,則完成拓撲排序;否則,若圖中存在環,則無法完成所有課程。 + + + + +```cpp +vector findOrder(int numCourses, vector>& prerequisites) { + vector> graph(numCourses, vector()); + vector indegree(numCourses, 0), schedule; + for (const auto& pr : prerequisites) { + graph[pr[1]].push_back(pr[0]); + ++indegree[pr[0]]; + } + queue q; + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] == 0) { + q.push(i); + } + } + while (!q.empty()) { + int u = q.front(); + q.pop(); + schedule.push_back(u); + for (int v : graph[u]) { + --indegree[v]; + if (indegree[v] == 0) { + q.push(v); + } + } + } + for (int i = 0; i < indegree.size(); ++i) { + if (indegree[i] != 0) { + return vector(); + } + } + return schedule; +} +``` + + + + +```py +def findOrder(numCourses: int, prerequisites: List[List[int]]) -> List[int]: + graph = [[] for _ in range(numCourses)] + indegree = [0] * numCourses + schedule = [] + + for pr_from, pr_to in prerequisites: + graph[pr_to].append(pr_from) + indegree[pr_from] += 1 + + q = collections.deque([i for i, deg in enumerate(indegree) if deg == 0]) + + while len(q) > 0: + u = q.popleft() + schedule.append(u) + for v in graph[u]: + indegree[v] -= 1 + if indegree[v] == 0: + q.append(v) + + return schedule if all(deg == 0 for deg in indegree) else [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md new file mode 100644 index 00000000..9000cc1c --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14-4-exercises.md @@ -0,0 +1,33 @@ +--- +sidebar_position: 78 +--- + +# 14.4 練習 + +## 基礎難度 + +### [1059. All Paths from Source Lead to Destination](https://leetcode.com/problems/all-paths-from-source-lead-to-destination/) + +雖然使用深度優先搜尋(DFS)可以解決大部分圖的遍歷問題,但需要特別注意檢查是否陷入了環路。 + +--- + +## 進階難度 + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +筆者其實已經撰寫了這道題的詳細解答,但後來發現該題需要付費解鎖才能查看。為了避免版權糾紛,將此題移至練習題中。本題考察最小生成樹(minimum spanning tree, MST)的求法,通常可以用兩種演算法實現: + +- **Prim’s Algorithm**:利用優先佇列選擇最小的消耗。 +- **Kruskal’s Algorithm**:對邊排序後使用並查集(Union-Find)。 + +--- + +### [882. Reachable Nodes In Subdivided Graph](https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/) + +筆者考慮了很久,最終決定將這道題放在練習題中,而非詳細講解。本題屬於經典的節點最短距離問題,常用的解法包括: + +- **Bellman-Ford** 單源最短路演算法(允許負邊權重)。 +- **Dijkstra** 無負邊單源最短路演算法。 + +雖然這些都是經典演算法,但 LeetCode 中相關題型較少,因此這裡僅供讀者自行深入學習。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14.1.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14.1.png new file mode 100644 index 00000000..46ebed1b Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/14.1.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/_category_.json new file mode 100644 index 00000000..5ee5393f --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/14-graphs/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "14. 指標三劍客之三:圖", + "position": 14, + "link": { + "type": "generated-index", + "description": "第 14 章 指標三劍客之三:圖" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md new file mode 100644 index 00000000..1ecf728e --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 75 +--- + +# 15.1 引言 + +到目前為止,我們已經接觸了大量的資料結構,包括利用指標實現的三劍客(鏈結串列、樹和圖)以及 C++ 自帶的 STL 函式庫。對於某些題目,我們不僅需要使用多種資料結構來解決問題,還需要將這些資料結構進行嵌套與聯動,以實現更複雜且更快速的操作。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx new file mode 100644 index 00000000..21855e9b --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-2-union-find.mdx @@ -0,0 +1,140 @@ +--- +sidebar_position: 76 +--- + +# 15.2 並查集 + +`並查集`(union-find, disjoint set)是一種用於動態連通性問題的數據結構,可以高效地實現動態連接兩個點,並快速判斷兩個點是否連通。假設有 n 個節點,我們初始化時將所有節點的父節點設為自身;每次需要連接節點 i 和 j 時,可以將秩較小一方的父節點標記為另一方(按秩合併);每次需要查詢兩個節點是否相連時,可以查找 i 和 j 的祖先是否相同,並通過路徑壓縮減少祖先層級,從而加速後續的查詢操作。 + +
+ + ![](15.1.png) + +
圖 15.1: 並查集範例,其中 union 操作可以將兩個集合按秩合併,find 操作可以查找節點的祖先並壓縮路徑。
+
+ +## [684. Redundant Connection](https://leetcode.com/problems/redundant-connection/) + +### 題目描述 + +在無向圖中找出一條邊,移除後該圖可以成為一棵樹(即無向無環圖)。如果有多個解,返回原陣列中位置最靠後的那條邊。 + +### 輸入輸出範例 + +輸入是一個二維陣列,表示所有的邊(對應的兩個節點);輸出是一個一維陣列,表示需要移除的邊(對應的兩個節點)。 + +``` +Input: [[1,2], [1,3], [2,3]] + 1 + / \ +2 - 3 +Output: [2,3] +``` + +### 題解 + +由於需要判斷是否兩個節點被重複連通,我們可以使用並查集來解決此類問題。以下為實現細節: + + + + +```cpp +class Solution { + public: + vector findRedundantConnection(vector>& edges) { + n_ = edges.size(); + id_ = vector(n_); + depth_ = vector(n_, 1); + for (int i = 0; i < n_; ++i) { + id_[i] = i; + } + for (auto& edge : edges) { + int i = edge[0], j = edge[1]; + if (linked(i - 1, j - 1)) { + return vector{i, j}; + } + connect(i - 1, j - 1); + } + return vector(); + } + + private: + int find(int i) { + // 路徑壓縮。 + while (i != id_[i]) { + id_[i] = id_[id_[i]]; + i = id_[i]; + } + return i; + } + + void connect(int i, int j) { + i = find(i), j = find(j); + if (i == j) { + return; + } + // 按秩合併。 + if (depth_[i] <= depth_[j]) { + id_[i] = j; + depth_[j] = max(depth_[j], depth_[i] + 1); + } else { + id_[j] = i; + depth_[i] = max(depth_[i], depth_[j] + 1); + } + } + + bool linked(int i, int j) { return find(i) == find(j); } + + int n_; + vector id_; + vector depth_; +}; +``` + + + + +```py +class Solution: + def __init__(self): + self.n = 0 + self.id = None + self.depth = None + + def find(self, i: int) -> int: + # 路徑壓縮。 + while i != self.id[i]: + self.id[i] = self.id[self.id[i]] + i = self.id[i] + return i + + def connect(self, i: int, j: int): + i = self.find(i) + j = self.find(j) + if i == j: + return + # 按秩合併。 + if self.depth[i] <= self.depth[j]: + self.id[i] = j + self.depth[j] = max(self.depth[j], self.depth[i] + 1) + else: + self.id[j] = i + self.depth[i] = max(self.depth[i], self.depth[j] + 1) + + def linked(self, i: int, j: int) -> bool: + return self.find(i) == self.find(j) + + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + self.n = len(edges) + self.id = list(range(self.n)) + self.depth = [1] * self.n + for i, j in edges: + if self.linked(i - 1, j - 1): + return [i, j] + self.connect(i - 1, j - 1) + return [] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx new file mode 100644 index 00000000..d6d81c75 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-3-composite-data-structures.mdx @@ -0,0 +1,256 @@ +--- +sidebar_position: 77 +--- + +# 15.3 複合資料結構 + +這一類題目通常採用雜湊表或有序表輔助記錄,以加速尋址;再搭配陣列或鏈結串列進行連續的資料儲存,以加速連續選址或刪除值。 + +## [146. LRU Cache](https://leetcode.com/problems/lru-cache/) + +### 題目描述 + +設計一個固定大小的最近最少使用快取(Least Recently Used Cache, LRU)。當快取未滿時插入資料,或者查找或更新快取內已存在的資料時,將該資料標記為最近使用。在快取滿的情況下,插入新資料時需要移除最久未使用的資料,插入新資料,並將該新資料標記為最近使用。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。給定一個大小為 n 的快取,利用最近最少使用策略儲存資料。 + +``` +LRUCache cache = new LRUCache( 2 /* capacity */ ); +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // 輸出 value 1 +cache.put(3, 3); // 移除 key 2 +cache.get(2); // 輸出 value -1 (未找到) +cache.put(4, 4); // 移除 key 1 +cache.get(1); // 輸出 value -1 (未找到) +cache.get(3); // 輸出 value 3 +cache.get(4); // 輸出 value 4 +``` + +### 題解 + +我們採用一個鏈結串列來儲存資料的 key 和 value,鏈結串列的連結順序即為最近使用的新舊順序,最新的資料在鏈結串列的頭節點。同時我們需要一個雜湊表進行查找,其鍵是資料的 key,值是其在鏈結串列中的對應指標/迭代器。每次查找成功(cache hit)時,需要將指標/迭代器對應的節點移動到鏈結串列的頭節點。 + + + + +```cpp +class LRUCache { + public: + LRUCache(int capacity) : n_(capacity) {} + + int get(int key) { + auto it = key_to_cache_it_.find(key); + if (it == key_to_cache_it_.end()) { + return -1; + } + cache_.splice(cache_.begin(), cache_, it->second); + return it->second->second; + } + + void put(int key, int value) { + auto it = key_to_cache_it_.find(key); + if (it != key_to_cache_it_.end()) { + it->second->second = value; + return cache_.splice(cache_.begin(), cache_, it->second); + } + cache_.insert(cache_.begin(), make_pair(key, value)); + key_to_cache_it_[key] = cache_.begin(); + if (cache_.size() > n_) { + key_to_cache_it_.erase(cache_.back().first); + cache_.pop_back(); + } + } + + private: + list> cache_; + unordered_map>::iterator> key_to_cache_it_; + int n_; +}; +``` + + + + +```py +class Node: + def __init__(self, key=-1, val=-1): + self.key = key + self.val = val + self.prev = None + self.next = None + +class LinkedList: + def __init__(self): + self.dummy_start = Node() + self.dummy_end = Node() + self.dummy_start.next = self.dummy_end + self.dummy_end.prev = self.dummy_start + + def appendleft(self, node) -> Node: + left, right = self.dummy_start, self.dummy_start.next + node.next = right + right.prev = node + left.next = node + node.prev = left + return node + + def remove(self, node) -> Node: + left, right = node.prev, node.next + left.next = right + right.prev = left + return node + + def move_to_start(self, node): + return self.appendleft(self.remove(node)) + + def pop(self): + return self.remove(self.dummy_end.prev) + + def peek(self): + return self.dummy_end.prev.val + +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.key_to_node = dict() + self.cache_nodes = LinkedList() + + def get(self, key: int) -> int: + if key not in self.key_to_node: + return -1 + node = self.key_to_node[key] + self.cache_nodes.move_to_start(node) + return node.val + + def put(self, key: int, value: int) -> None: + if key in self.key_to_node: + node = self.cache_nodes.remove(self.key_to_node[key]) + node.val = value + else: + node = Node(key, value) + self.key_to_node[key] = node + self.cache_nodes.appendleft(node) + if len(self.key_to_node) > self.n: + self.key_to_node.pop(self.cache_nodes.pop().key) +``` + + + + + +對於 Python 而言,我們還可以直接利用 `OrderedDict` 函數實現 LRU,這將大大簡化題目的難度。不過,筆者希望讀者還是能仔細研讀以上的解題說明,深入了解 LRU 實現的核心原理。 + +```py +class LRUCache: + def __init__(self, capacity: int): + self.n = capacity + self.cache = {} + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + self.cache[key] = self.cache.pop(key) + return self.cache[key] + + def put(self, key: int, value: int) -> None: + if key in self.cache: + self.cache.pop(key) + self.cache[key] = value + if len(self.cache) > self.n: + self.cache.pop(next(iter(self.cache))) +``` + +## [380. Insert Delete GetRandom O(1)](https://leetcode.com/problems/insert-delete-getrandom-o1/) + +### 題目描述 + +設計一個插入、刪除和隨機取值均為 $O(1)$ 時間複雜度的資料結構。 + +### 輸入輸出範例 + +以下是資料結構的調用範例。 + +``` +RandomizedSet randomizedSet = new RandomizedSet(); +randomizedSet.insert(1); +randomizedSet.remove(2); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 50% 1, 50% 2 +randomizedSet.remove(1); +randomizedSet.insert(2); +randomizedSet.getRandom(); // 100% 2 +``` + +### 題解 + +我們採用一個陣列儲存插入的數字,同時利用一個雜湊表查找位置。每次插入數字時,直接加入陣列,且將位置記錄在雜湊表中。每次刪除數字時,將當前陣列最後一位與刪除位互換,並更新雜湊表。隨機取值時,則可以在陣列內任意選取位置。 + + + + +```cpp +class RandomizedSet { + public: + bool insert(int val) { + if (v_to_k_.contains(val)) { + return false; + } + v_to_k_[val] = nums_.size(); + nums_.push_back(val); + return true; + } + + bool remove(int val) { + if (!v_to_k_.contains(val)) { + return false; + } + v_to_k_[nums_.back()] = v_to_k_[val]; + nums_[v_to_k_[val]] = nums_.back(); + v_to_k_.erase(val); + nums_.pop_back(); + return true; + } + + int getRandom() { return nums_[rand() % nums_.size()]; } + + private: + unordered_map v_to_k_; + vector nums_; +}; +``` + + + + +```py +class RandomizedSet: + def __init__(self): + self.nums = [] + self.v_to_k = {} + + def insert(self, val: int) -> bool: + if val in self.v_to_k: + return False + self.v_to_k[val] = len(self.nums) + self.nums.append(val) + return True + + def remove(self, val: int) -> bool: + if val not in self.v_to_k: + return False + self.v_to_k[self.nums[-1]] = self.v_to_k[val] + self.nums[self.v_to_k[val]] = self.nums[-1] + del self.v_to_k[val] + self.nums.pop() + return True + + def getRandom(self) -> int: + return self.nums[random.randint(0, len(self.nums) - 1)] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md new file mode 100644 index 00000000..80a2f240 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15-4-exercises.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 78 +--- + +# 15.4 練習 + +## 基礎難度 + +### [1135. Connecting Cities With Minimum Cost](https://leetcode.com/problems/connecting-cities-with-minimum-cost/) + +使用並查集,按照 Kruskal’s Algorithm 再解一次這道題吧。 + +--- + +## 進階難度 + +### [432. All O`one Data Structure](https://leetcode.com/problems/all-oone-data-structure/) + +設計一個包含 increaseKey,decreaseKey,getMaxKey,getMinKey 均為 $O(1)$ 時間複雜度的資料結構。 + +--- + +### [716. Max Stack](https://leetcode.com/problems/max-stack/) + +設計一個支持 push,pop,top,getMax 和 popMax 的堆疊。可以用類似 LRU 的方法降低時間複雜度,但因為要獲取的是最大值,我們應該把 unordered_map 換成哪一種資料結構呢? diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png new file mode 100644 index 00000000..6a2df359 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/15.1.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json new file mode 100644 index 00000000..a38a7773 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/15-advanced-data-structures/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "15. 更加複雜的資料結構", + "position": 15, + "link": { + "type": "generated-index", + "description": "第 15 章 更加複雜的資料結構" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md new file mode 100644 index 00000000..bf3b6f8e --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-1-algorithm-explanation.md @@ -0,0 +1,21 @@ +--- +sidebar_position: 5 +--- + +# 2.1 算法解釋 + +雙指針主要用於遍歷陣列,兩個指針指向不同的元素,從而協同完成任務。也可以延伸到多個陣列的多個指針。 + +若兩個指針指向同一陣列,遍歷方向相同且不會相交,則也稱為滑動窗口(兩個指針包圍的區域即為當前的窗口),經常用於區間搜索。 + +若兩個指針指向同一陣列,但是遍歷方向相反,則可以用來進行搜索,待搜索的陣列往往是排好序的。 + +在 C++ 中,要注意 `const` 的位置對指針效果的影響: + +```cpp +int x; +int * p1 = &x; // 指針可以被修改,值也可以被修改 +const int * p2 = &x; // 指針可以被修改,值不可以被修改(const int) +int * const p3 = &x; // 指針不可以被修改(* const),值可以被修改 +const int * const p4 = &x; // 指針不可以被修改,值也不可以被修改 +``` diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx new file mode 100644 index 00000000..350f1226 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-2-two-sum.mdx @@ -0,0 +1,78 @@ +--- +sidebar_position: 6 +--- + +# 2.2 Two Sum + +## [167. Two Sum II - Input array is sorted](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/) + +### 題目描述 + +在一個增序的整數陣列裡找到兩個數,使它們的和為給定值。已知有且只有一對解。 + +### 輸入輸出範例 + +輸入是一個陣列(`numbers`)和一個給定值(`target`)。輸出是兩個數的位置,從 1 開始計數。 + +``` +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +``` + +在這個範例中,第一個數字(2)和第二個數字(7)的和等於給定值(9)。 + +### 題解 + +因為陣列已經排好序,我們可以採用方向相反的雙指針來尋找這兩個數字。一個指針初始指向最小的元素,即陣列最左邊,向右遍歷;另一個指針初始指向最大的元素,即陣列最右邊,向左遍歷。 + +如果兩個指針指向元素的和等於給定值,那麼它們就是我們要的結果。如果兩個指針指向元素的和小於給定值,我們把左邊的指針右移一位,使得當前的和增加一點。如果兩個指針指向元素的和大於給定值,我們把右邊的指針左移一位,使得當前的和減少一點。 + +可以證明,對於排好序且有解的陣列,雙指針一定能遍歷到最優解。證明方法如下:假設最優解的兩個數的位置分別是 `l` 和 `r`。我們假設在左指針在 `l` 左邊的時候,右指針已經移動到了 `r`;此時兩個指針指向值的和小於給定值,因此左指針會一直右移直到到達 `l`。同理,如果我們假設在右指針在 `r` 右邊的時候,左指針已經移動到了 `l`;此時兩個指針指向值的和大於給定值,因此右指針會一直左移直到到達 `r`。所以雙指針在任何時候都不可能處於 `(l,r)` 之間,又因為不滿足條件時指針必須移動一個,所以最終一定會收斂在 `l` 和 `r`。 + + + + +```cpp +vector twoSum(vector& numbers, int target) { + int l = 0, r = numbers.size() - 1, two_sum; + while (l < r) { + two_sum = numbers[l] + numbers[r]; + if (two_sum == target) { + break; + } + if (two_sum < target) { + ++l; + } else { + --r; + } + } + return vector{l + 1, r + 1}; +} +``` + + + + +```py +def twoSum(numbers: List[int], target: int) -> List[int]: + l, r = 0, len(numbers) - 1 + while l < r: + two_sum = numbers[l] + numbers[r] + if two_sum == target: + break + if two_sum < target: + l += 1 + else: + r -= 1 + return [l + 1, r + 1] +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是陣列的長度。每次迭代中,指針會移動一次,最多執行 $n$ 次迭代。 + +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx new file mode 100644 index 00000000..e2f8d83f --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-3-merge-sorted-arrays.mdx @@ -0,0 +1,73 @@ +--- +sidebar_position: 7 +--- + +# 2.3 合併兩個有序陣列 + +## [88. Merge Sorted Array](https://leetcode.com/problems/merge-sorted-array/) + +### 題目描述 + +給定兩個有序陣列,將它們合併為一個陣列。 + +### 輸入輸出範例 + +輸入是兩個陣列和它們分別的長度 `m` 和 `n`。其中第一個陣列的長度被延長至 `m + n`,多出的 `n` 位被 `0` 填補。題目要求把第二個陣列合併到第一個陣列上,不需要開闢額外空間。 + +``` +Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 +Output: nums1 = [1,2,2,3,5,6] +``` + + +### 題解 + +因為這兩個陣列已經排好序,我們可以將兩個指針分別放在兩個陣列的末尾,即 `nums1` 的 `(m - 1)` 位和 `nums2` 的 `(n - 1)` 位。每次將較大的那個數字複製到 `nums1` 的後邊,然後向前移動一位。 + +我們也需要第三個指針來定位 `nums1` 的末尾,以便進行複製。在以下的代碼裡,我們直接利用 `m` 和 `n` 當作兩個陣列的指針,再額外創建一個 `pos` 指針,起始位置為 `m + n - 1`。每次向左移動 `m` 或 `n` 的時候,也要向左移動 `pos`。注意,如果 `nums1` 的數字已經複製完,不要忘記繼續複製 `nums2` 的數字;如果 `nums2` 的數字已經複製完,剩下的 `nums1` 的數字不需要改變,因為它們已經排好序。 + +在 C++ 的題解中,我們使用了 `++` 和 `--` 的小技巧:`a++` 和 `++a` 都會將 `a` 加 1,但 `a++` 的返回值為 `a`,而 `++a` 的返回值為 `a + 1`。如果只希望增加 `a` 的值而不需要返回值,則兩種寫法都可以(`++a` 在未經編譯器優化的情況下運行速度會略快一些)。 + + + + + +```cpp +void merge(vector& nums1, int m, vector& nums2, int n) { + int pos = m-- + n-- - 1; + while (m >= 0 && n >= 0) { + nums1[pos--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; + } + while (n >= 0) { + nums1[pos--] = nums2[n--]; + } +} +``` + + + + +```py +def merge(nums1: List[int], m: int, nums2: List[int], n: int) -> None: + pos = m + n - 1 + m -= 1 + n -= 1 + while m >= 0 and n >= 0: + if nums1[m] > nums2[n]: + nums1[pos] = nums1[m] + m -= 1 + else: + nums1[pos] = nums2[n] + n -= 1 + pos -= 1 + nums1[: n + 1] = nums2[: n + 1] +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(m + n)$,遍歷 `nums1` 和 `nums2` 一次。 +- **空間複雜度**: $O(1)$,直接在 `nums1` 上進行操作,未使用額外空間。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx new file mode 100644 index 00000000..65cfddd8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-4-sliding-window.mdx @@ -0,0 +1,113 @@ +--- +sidebar_position: 8 +--- + +# 2.4 滑動窗口 + +## [76. Minimum Window Substring](https://leetcode.com/problems/minimum-window-substring/) + +### 題目描述 + +給定兩個字串 `s` 和 `t`,求 `s` 中包含 `t` 所有字符的最短連續子字串的長度,同時要求時間複雜度不得超過 $O(n)$。 + + +### 輸入輸出範例 + +輸入是兩個字串 `s` 和 `t`,輸出是 `s` 字串的一個子串。如果不存在解,則輸出一個空字串。 + +``` +Input: s = "ADOBECODEBANC", t = "ABC" +Output: "BANC" +``` + +在這個範例中,`s` 中同時包含一個 `A`、一個 `B`、一個 `C` 的最短子字串是 "BANC"。 + +### 題解 + +本題使用滑動窗口求解,即兩個指針 `l` 和 `r` 都是從最左端向最右端移動,且 `l` 的位置一定在 `r` 的左邊或重合。在 C++ 解法中,使用了兩個長度為 128 的陣列,`valid` 和 `freq`,用來映射字符(ASCII 僅包含 128 個字符)。其中 `valid` 表示每個字符在 `t` 中是否存在,而 `freq` 表示目前 `t` 中每個字符在 `s` 的滑動窗口中缺少的數量:如果為正,則說明還缺少;如果為負,則說明有盈餘。在 Python 解法中,直接使用了 `Counter` 數據結構,同時統計 `t` 中存在的字符和其缺少的數量(也可以用 `dict` 替代)。 + +需要注意,本題雖然在 `for` 循環裡出現了一個 `while` 循環,但由於 `while` 循環負責移動 `l` 指針,且 `l` 只會從左到右移動一次,因此總時間複雜度仍然是 $O(n)$。 + + + + +```cpp +string minWindow(string s, string t) { + vector valid(128, false); + vector freq(128, 0); + // 統計 t 中的字符情況。 + for (int i = 0; i < t.length(); ++i) { + valid[t[i]] = true; + ++freq[t[i]]; + } + // 移動滑動窗口,更新統計數據。 + int count = 0; + int min_l = -1, min_length = -1; + for (int l = 0, r = 0; r < s.length(); ++r) { + if (!valid[s[r]]) { + continue; + } + // 將 r 位置的字符加入頻率統計,並檢查是否補充了 t 中缺失的字符。 + if (--freq[s[r]] >= 0) { + ++count; + } + // 滑動窗口已包含 t 中全部字符,嘗試右移 l,在不影響結果的情況下尋找最短子串。 + while (count == t.length()) { + if (min_length == -1 || r - l + 1 < min_length) { + min_l = l; + min_length = r - l + 1; + } + // 將 l 位置的字符移出頻率統計,並檢查 t 中對應字符是否重新缺失。 + if (valid[s[l]] && ++freq[s[l]] > 0) { + --count; + } + ++l; + } + } + return min_length == -1 ? "" : s.substr(min_l, min_length); +} +``` + + + + +```py +def minWindow(s: str, t: str) -> str: + # 統計 t 中的字符情況,等價於: + # freq = dict() + # for c in t: + # freq[c] = freq.get(c, 0) + 1 + freq = Counter(t) + # 移動滑動窗口,更新統計數據。 + count = 0 + min_l, min_length = None, None + l = 0 + for r in range(len(s)): + if s[r] not in freq: + continue + # 將 r 位置的字符加入頻率統計,並檢查是否補充了 t 中缺失的字符。 + freq[s[r]] -= 1 + if freq[s[r]] >= 0: + count += 1 + # 滑動窗口已包含 t 中全部字符,嘗試右移 l,在不影響結果的情況下尋找最短子串。 + while count == len(t): + if min_length is None or r - l + 1 < min_length: + min_l = l + min_length = r - l + 1 + # 將 l 位置的字符移出頻率統計,並檢查 t 中對應字符是否重新缺失。 + if s[l] in freq: + freq[s[l]] += 1 + if freq[s[l]] > 0: + count -= 1 + l += 1 + return "" if min_length is None else s[min_l: min_l + min_length] +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(|s| + |t|)$,對字符串 `s` 遍歷一次(窗口擴展和收縮共計 $O(|s|)$),初始化 `t` 的統計需要 $O(|t|)$。 +- **空間複雜度**: $O(|t|)$,字典 `freq` 的大小與 `t` 中的不同字符數量成正比。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx new file mode 100644 index 00000000..c3039691 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-5-fast-slow-pointers.mdx @@ -0,0 +1,103 @@ +--- +sidebar_position: 9 +--- + +# 2.5 快慢指針 + +## [142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/) + +### 題目描述 + +給定一個鏈結串列,如果存在環路,找到環路的起始點。 + +### 輸入輸出範例 + +輸入是一個鏈結串列,輸出是鏈結串列中的一個節點。如果沒有環路,返回一個空指針。 +在這個範例中,值為 2 的節點即為環路的起始點。 +如果沒有特別說明,LeetCode 採用如下的數據結構表示鏈結串列。 + +![alt](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png) + +```cpp +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(nullptr) {} +}; +``` + +```py +class ListNode: + def __init__(self, x): + self.val = x + self.next = None # or a ListNode +``` + +### 題解 + +針對鏈結串列找環路的問題,有一個通用解法——快慢指針(Floyd 判圈法)。給定兩個指針,分別命名為 slow 和 fast,起始位置在鏈結串列的開頭。每次 fast 前進兩步,slow 前進一步。如果 fast 可以走到盡頭,則說明沒有環路;如果 fast 可以無限走下去,則說明一定有環路,且必然存在一個時刻 slow 和 fast 相遇。當 slow 和 fast 第一次相遇時,將 fast 重新移動到鏈結串列開頭,並 讓 slow 和 fast 每次都前進一步。當 slow 和 fast 第二次相遇時,相遇的節點即為環路的起始點。 + +:::warning + +針對某些只需要判斷是否存在環路的問題,也可以通過建立雜湊表來檢查重複。 + +::: + + + + + +```cpp +ListNode *detectCycle(ListNode *head) { + ListNode *slow = head, *fast = head; + bool is_first_cycle = true; + // 檢查環路。 + while (fast != slow || is_first_cycle) { + if (fast == nullptr || fast->next == nullptr) { + return nullptr; + } + fast = fast->next->next; + slow = slow->next; + is_first_cycle = false; + } + // 尋找節點。 + fast = head; + while (fast != slow) { + slow = slow->next; + fast = fast->next; + } + return fast; +} +``` + + + + +```py +def detectCycle(head: Optional[ListNode]) -> Optional[ListNode]: + slow = head + fast = head + is_first_cycle = True + # 檢查環路。 + while fast != slow or is_first_cycle: + if fast is None or fast.next is None: + return None + fast = fast.next.next + slow = slow.next + is_first_cycle = False + # 尋找節點。 + fast = head + while fast != slow: + fast = fast.next + slow = slow.next + return fast +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是鏈結串列的節點數量。`slow` 和 `fast` 分別最多遍歷一次鏈結串列。 +- **空間複雜度**: $O(1)$,只使用了兩個指針,不需要額外的空間。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md new file mode 100644 index 00000000..0587ea75 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/2-6-exercises.md @@ -0,0 +1,198 @@ +--- +sidebar_position: 10 +--- + +# 2.6 練習 + +## 基礎難度 + +### [633. Sum of Square Numbers](https://leetcode.com/problems/sum-of-square-numbers/) + +Two Sum 題目的變形題之一。 + +
+ 題解 + +#### 解題思路 + +- 本題需要判斷是否存在兩個非負整數 $a$ 和 $b$,使得 $a^2 + b^2 = c$,其中 $c$ 是輸入的整數。 +- **雙指針法**: + 1. 設置兩個指針:左指針 $a = 0$,右指針 $b = \lfloor \sqrt{c} \rfloor$。 + 2. 計算當前平方和 $a^2 + b^2$: + - 如果 $a^2 + b^2 = c$,返回 `True`。 + - 如果 $a^2 + b^2 < c$,增加 $a$。 + - 如果 $a^2 + b^2 > c$,減少 $b$。 + 3. 如果指針相交且沒有找到結果,返回 `False`。 + +```python +class Solution: + def judgeSquareSum(self, c: int) -> bool: + a, b = 0, int(c**0.5) # 初始化指針 + while a <= b: + square_sum = a * a + b * b + if square_sum == c: + return True + elif square_sum < c: + a += 1 # 增加左指針 + else: + b -= 1 # 減少右指針 + return False +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(\sqrt{c})$,指針從兩端向中間收攏,最多執行 $\sqrt{c}$ 次迭代。 +- **空間複雜度**: $O(1)$,僅使用了固定數量的變數。 + +
+ + +--- + +### [680. Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) + +Two Sum 題目的變形題之二。 + +
+ 題解 + +#### 解題思路 + +- 本題需要判斷一個字符串是否可以通過刪除最多一個字符後,成為回文字符串。 +- **雙指針法**: + 1. 設置左右指針 `l` 和 `r`,分別指向字符串的頭部和尾部。 + 2. 如果 `s[l] == s[r]`,則將指針向中間移動。 + 3. 如果 `s[l] != s[r]`: + - 刪除左邊字符(檢查子串 `s[l+1:r+1]`)或右邊字符(檢查子串 `s[l:r]`)。 + - 如果任意一個子串是回文,則返回 `True`。 + 4. 如果左右指針正常移動到中間,說明原字符串是回文,返回 `True`。 + +- **輔助函數**: + 使用一個函數檢查子串是否是回文。 + +```python +class Solution: + def validPalindrome(self, s: str) -> bool: + def is_palindrome(sub: str) -> bool: + return sub == sub[::-1] + + l, r = 0, len(s) - 1 + while l < r: + if s[l] == s[r]: + l += 1 + r -= 1 + else: + return is_palindrome(s[l+1:r+1]) or is_palindrome(s[l:r]) + return True +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是字符串的長度。主迴圈遍歷字符串一次,檢查回文子串的操作最多進行一次,總計為線性時間。 +- **空間複雜度**: $O(1)$,除了輔助函數外,未使用額外空間。 + +
+ +--- + +### [524. Longest Word in Dictionary through Deleting](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/) + +合併兩個有序陣列的變形題。 + +
+ 題解 + +#### 解題思路 + +- 本題要求找出可以通過刪除字符串中若干字符而得到的最長單詞。如果有多個單詞的長度相同,返回字典序最小的單詞。 +- **雙指針法**: + 1. 對字典中的單詞列表按長度降序、字典序升序排序,保證先處理最長且字典序最小的單詞。 + 2. 遍歷排序後的單詞列表,檢查每個單詞是否是給定字符串的子序列。 + 3. 使用雙指針檢查是否為子序列: + - 指針 `i` 遍歷字符串 `s`,指針 `j` 遍歷目標單詞。 + - 如果 `s[i] == word[j]`,則移動 `j`。 + - 如果 `j` 能到達目標單詞的末尾,說明該單詞是子序列。 + +- 返回第一個滿足條件的單詞。 + +```python +class Solution: + def findLongestWord(self, s: str, dictionary: List[str]) -> str: + def is_subsequence(word: str, s: str) -> bool: + i, j = 0, 0 + while i < len(s) and j < len(word): + if s[i] == word[j]: + j += 1 + i += 1 + return j == len(word) + + dictionary.sort(key=lambda x: (-len(x), x)) # 長度降序,字典序升序 + for word in dictionary: + if is_subsequence(word, s): + return word + return "" +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(m \cdot n)$,其中 $m$ 是字典中單詞的數量,$n$ 是字符串 `s` 的長度。排序的複雜度為 $O(m \log m)$,每個單詞的子序列檢查需要 $O(n)$。 +- **空間複雜度**: $O(1)$,除了排序和雙指針檢查外,未使用額外空間。 + +
+ + +--- + +## 進階難度 + +### [340. Longest Substring with At Most K Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/) + +需要利用其他數據結構方便統計當前的字符狀態。 + +
+ 題解 + +#### 解題思路 + +- 本題要求找到字串中最多包含 $k$ 種不同字元的最長子字串,適合使用 **滑動窗口法**: + 1. 使用雙指針 `l` 和 `r` 表示當前窗口的左右邊界,並用 `defaultdict(int)` 記錄窗口中每個字元的出現次數。 + 2. 當窗口中的字元種類數量超過 $k$ 時,通過移動左指針 `l` 縮小窗口,直到字元種類數量不超過 $k$。 + 3. 在每一步中,更新最長子字串的長度。 + +- **步驟**: + 1. 初始化一個 `defaultdict(int)` 來記錄字元出現次數。 + 2. 右指針 `r` 向右移動,將字元加入窗口,更新次數。 + 3. 當窗口內字元種類數量超過 $k$,左指針 `l` 向右移動,直到種類數量不超過 $k$。 + 4. 在每一步中記錄當前窗口的長度,並更新最長子字串的長度。 + +```python +from collections import defaultdict + +class Solution: + def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int: + if k == 0 or not s: + return 0 + + freq = defaultdict(int) + l, max_length = 0, 0 + + for r in range(len(s)): + freq[s[r]] += 1 # 更新右指針字元出現次數 + + while len(freq) > k: # 縮小窗口直到字元種類不超過 k + freq[s[l]] -= 1 + if freq[s[l]] == 0: + del freq[s[l]] + l += 1 + + max_length = max(max_length, r - l + 1) # 更新最長長度 + + return max_length +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是字串的長度。右指針遍歷字串一次,左指針最多遍歷字串一次。 +- **空間複雜度**: $O(k)$,雜湊表最多儲存 $k$ 種字元及其出現次數。 + +
diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json new file mode 100644 index 00000000..01ecb243 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/2-two-pointer-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "2. 玩轉雙指針", + "position": 2, + "link": { + "type": "generated-index", + "description": "第 2 章 玩轉雙指針" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md new file mode 100644 index 00000000..950c18cf --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-1-algorithm-explanation.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 11 +--- + +# 3.1 算法解釋 + +`二分搜尋` 也常被稱為 `二分法` 或 `折半搜尋` (binary search, bisect),每次搜尋時通過將待搜尋的單調區間分成兩部分並只取一部分繼續搜尋,將搜尋的複雜度大大減少。對於一個長度為 $O(n)$ 的陣列,二分搜尋的時間複雜度為 $O(\log n)$。 + +舉例來說,給定一個排好序的陣列 $\{3,4,5,6,7\}$,我們希望搜尋 4 是否在這個陣列中。第一次折半時考慮中位數 5,因為 5 大於 4,所以如果 4 存在於這個陣列,那麼它必定存在於 5 左邊這一半。於是我們的搜尋區間變成了 $\{3,4,5\}$。(注意,根據具體情況和您的解題習慣,這裡的 5 可以保留也可以不保留,這並不影響時間複雜度的等級。)第二次折半時考慮新的中位數 4,正好是我們需要搜尋的數字。於是我們發現,對於一個長度為 5 的陣列,我們只進行了 2 次搜尋。如果是遍歷陣列,最壞情況則需要搜尋 5 次。 + +我們也可以用更數學化的方式定義二分搜尋。給定一個在 $[a, b]$ 區間內的單調函數 $f(t)$,若 $f(a)$ 和 $f(b)$ 正負性相反,那麼必定存在一個解 $c$,使得 $f(c) = 0$。在上述例子中,$f(t)$ 是離散函數 $f(t) = t + 2$,搜尋 4 是否存在等價於求 $f(t) - 4 = 0$ 是否有離散解。因為 $f(1) - 4 = 3 - 4 = -1 < 0$、$f(5) - 4 = 7 - 4 = 3 > 0$,且函數在區間內單調遞增,因此我們可以利用二分搜尋求解。如果最後二分到了不能再分的情況,如只剩一個數字,且剩餘區間裡不存在滿足條件的解,則說明不存在離散解,即 4 不在這個陣列中。 + +具體到代碼上,二分搜尋時區間的左右端取開區間還是閉區間在絕大多數情況下都可以,因此有些初學者會容易搞不清楚如何定義區間開閉性。這裡提供兩個小訣竅:第一是嘗試熟練使用一種寫法,比如左閉右開(滿足 C++、Python 等語言的習慣)或左閉右閉(便於處理邊界條件),盡量只保持這一種寫法;第二是在解題時思考如果最後區間只剩下一個數或者兩個數,自己的寫法是否會陷入死循環,如果某種寫法無法跳出死循環,則考慮嘗試另一種寫法。 + +二分搜尋也可以看作雙指針的一種特殊情況,但我們一般會將二者區分。雙指針類型的題,指針通常是一步一步移動的,而在二分搜尋中,指針通常每次移動半個區間長度。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx new file mode 100644 index 00000000..65038daa --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-2-square-root.mdx @@ -0,0 +1,109 @@ +--- +sidebar_position: 12 +--- + +# 3.2 求平方根 + +## [69. Sqrt(x)](https://leetcode.com/problems/sqrtx/) + +### 題目描述 + +給定一個非負整數 `x`,求它的平方根並向下取整。 + +### 輸入輸出範例 + +輸入是一個整數,輸出也是一個整數。 + +``` +Input: 8 +Output: 2 +``` + +8 的平方根是 2.82842...,向下取整即為 2。 + + +### 題解 + +我們可以將這道題想像成:給定一個非負整數 `x`,求 $f(t) = t^2 − x = 0$ 的解。由於我們只考慮 $t ≥ 0$,因此 $f(t)$ 在定義域內是單調遞增的。考慮到 $f(0) = −x ≤ 0$,$f(x) = x^2 − x ≥ 0$,我們可以對 $[0, x]$ 區間使用二分搜尋找到 $f(t) = 0$ 的解。此處我們採用左閉右閉的寫法。 + +在 C++ 解法中,$mid = (l + r) / 2$ 可能會因為 $l + r$ 溢出而出錯,因此改為 $mid = l + (r − l) / 2$ 的寫法;直接計算 $mid ∗ mid$ 也可能溢出,因此我們比較 $mid$ 和 $x / mid$。 + + + + +```cpp +int mySqrt(int x) { + int l = 1, r = x, mid, x_div_mid; + while (l <= r) { + mid = l + (r - l) / 2; + x_div_mid = x / mid; + if (mid == x_div_mid) { + return mid; + } + if (mid < x_div_mid) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return r; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + l, r = 1, x + while l <= r: + mid = (l + r) // 2 + mid_sqr = mid**2 + if mid_sqr == x: + return mid + if mid_sqr < x: + l = mid + 1 + else: + r = mid - 1 + return r +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(\log x)$,因為每次迭代將搜索範圍縮小一半。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +此外,這道題還有一種更快的算法——`牛頓迭代法`,其公式為 $t_{n+1} = t_n - \frac{f(t_n)}{f'(t_n)}$。給定 $f(t) = t^2 − x = 0$,其迭代公式為 $t_{n+1} = \frac{t_n + \frac{x}{t_n}}{2}$。 + + + + +```cpp +int mySqrt(int x) { + long t = x; + while (t * t > x) { + t = (t + x / t) / 2; + } + return t; +} +``` + + + + +```py +def mySqrt(x: int) -> int: + t = x + while t**2 > x: + t = (t + x // t) // 2 + return t +``` + + + + + diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx new file mode 100644 index 00000000..327ac7e8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-3-interval-search.mdx @@ -0,0 +1,114 @@ +--- +sidebar_position: 13 +--- + +# 3.3 搜尋範圍 + +## [34. Find First and Last Position of Element in Sorted Array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/) + +### 題目描述 + +給定一個遞增的整數陣列和一個目標值,查找該值第一次和最後一次出現的位置。 + + +### 輸入輸出範例 + +輸入是一個陣列和一個值,輸出為該值第一次出現的位置和最後一次出現的位置(從 0 開始);如果該值不存在,則兩個返回值都設為 -1。 + +``` +Input: nums = [5,7,7,8,8,10], target = 8 +Output: [3,4] +``` + +數字 8 在第 3 位第一次出現,在第 4 位最後一次出現。 + +### 題解 + +這道題可以看作是實現 C++ 的 `lower_bound` 和 `upper_bound` 函數,或者 Python 的 `bisect_left` 和 `bisect_right` 函數。我們這裡採用左閉右開的寫法,當然左閉右閉也可以。 + + + + + +```cpp +int lowerBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] < target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +int upperBound(vector &nums, int target) { + int l = 0, r = nums.size(), mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l; +} + +vector searchRange(vector &nums, int target) { + if (nums.empty()) { + return vector{-1, -1}; + } + int lower = lowerBound(nums, target); + int upper = upperBound(nums, target) - 1; + if (lower == nums.size() || nums[lower] != target) { + return vector{-1, -1}; + } + return vector{lower, upper}; +} +``` + + + + +```py +def lowerBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] < target: + l = mid + 1 + else: + r = mid + return l + +def upperBound(nums: List[int], target: int) -> int: + l, r = 0, len(nums) + while l < r: + mid = (l + r) // 2 + if nums[mid] <= target: + l = mid + 1 + else: + r = mid + return l + +def searchRange(nums: List[int], target: int) -> List[int]: + if not nums: + return [-1, -1] + lower = lowerBound(nums, target) + upper = upperBound(nums, target) - 1 + if lower == len(nums) or nums[lower] != target: + return [-1, -1] + return [lower, upper] +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(\log n)$,其中 $n$ 是陣列的長度。`lowerBound` 和 `upperBound` 各執行一次二分搜尋,每次操作將搜索範圍減半。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx new file mode 100644 index 00000000..41e8222d --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-4-peak-finding.mdx @@ -0,0 +1,91 @@ +--- +sidebar_position: 14 +--- + +# 3.4 搜尋最大值 + +## [162. Find Peak Element](https://leetcode.com/problems/find-peak-element/) + +### 題目描述 + +給定一個陣列,定義最大值為比兩邊都大的數字,要求出任意一個最大值的位置。一個陣列中可能存在多個最大值,返回任意一個即可。要求時間複雜度為 $O(\log n)$。 + +### 輸入輸出範例 + +輸入是一個陣列,輸出為最大值的位置。 + +``` +Input: nums = [1,2,3,1] +Output: 2 +``` + +最大值 3 出現在位置 2。 + + +### 題解 + +為了實現 $O(\log n)$ 的時間複雜度,我們可以對陣列進行二分搜尋。在確保陣列兩端不是最大值後,若當前中點不是最大值,那麼其左右一側必定存在一個最大值。 + + + + + +```cpp +int findPeakElement(vector& nums) { + int n = nums.size(); + if (n == 1) { + return 0; + } + if (nums[0] > nums[1]) { + return 0; + } + if (nums[n - 1] > nums[n - 2]) { + return n - 1; + } + int l = 1, r = n - 2, mid; + while (l <= r) { + mid = l + (r - l) / 2; + if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1]) { + return mid; + } else if (nums[mid] > nums[mid - 1]) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return -1; +} +``` + + + + +```py +def findPeakElement(self, nums: List[int]) -> int: + n = len(nums) + if n == 1: + return 0 + if nums[0] > nums[1]: + return 0 + if nums[n - 1] > nums[n - 2]: + return n - 1 + l, r = 1, n - 2 + while l <= r: + mid = (l + r) // 2 + if nums[mid] > nums[mid + 1] and nums[mid] > nums[mid - 1]: + return mid + elif nums[mid] > nums[mid - 1]: + l = mid + 1 + else: + r = mid - 1 + return -1 +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(\log n)$,其中 $n$ 是陣列的長度。每次迭代將搜索範圍縮小一半。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx new file mode 100644 index 00000000..608c4dfe --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-5-rotated-array-search.mdx @@ -0,0 +1,103 @@ +--- +sidebar_position: 15 +--- + +# 3.5 搜尋旋轉陣列中的數字 + +## [81. Search in Rotated Sorted Array II](https://leetcode.com/problems/search-in-rotated-sorted-array-ii/) + +### 題目描述 + +一個原本遞增的陣列被首尾相連後按某個位置斷開(如 [1,2,2,3,4,5] → [2,3,4,5,1,2],在第一位和第二位斷開),我們稱其為旋轉陣列。給定一個值,判斷這個值是否存在於這個旋轉陣列中。 + +### 輸入輸出範例 + +輸入是一個陣列和一個值,輸出是一個布林值,表示陣列中是否存在該值。 + +``` +Input: nums = [2,5,6,0,0,1,2], target = 0 +Output: true +``` + +即使陣列被旋轉過,我們仍然可以利用這個陣列的遞增性,使用二分搜尋。對於當前的中點,如果它指向的值小於等於右端,那麼說明右區間是排好序的;反之,那麼說明左區間是排好序的。如果目標值位於排好序的區間內,我們可以對這個區間繼續二分搜尋;反之,我們對於另一半區間繼續二分搜尋。本題我們採用左閉右閉的寫法。 + + +### 題解 + + + + + +```cpp +bool search(vector& nums, int target) { + int l = 0, r = nums.size() - 1; + while (l <= r) { + int mid = l + (r - l) / 2; + if (nums[mid] == target) { + return true; + } + if (nums[mid] == nums[l]) { + // 無法判斷哪個區間是遞增的,但 l 位置一定不是 target。 + ++l; + } else if (nums[mid] == nums[r]) { + // 無法判斷哪個區間是遞增的,但 r 位置一定不是 target。 + --r; + } else if (nums[mid] < nums[r]) { + // 右區間是遞增的。 + if (target > nums[mid] && target <= nums[r]) { + l = mid + 1; + } else { + r = mid - 1; + } + } else { + // 左區間是遞增的。 + if (target >= nums[l] && target < nums[mid]) { + r = mid - 1; + } else { + l = mid + 1; + } + } + } + return false; +} +``` + + + + +```py +def search(nums: List[int], target: int) -> bool: + l, r = 0, len(nums) - 1 + while l <= r: + mid = (l + r) // 2 + if nums[mid] == target: + return True + if nums[mid] == nums[l]: + # 無法判斷哪個區間是遞增的,但 l 位置一定不是 target。 + l += 1 + elif nums[mid] == nums[r]: + # 無法判斷哪個區間是遞增的,但 r 位置一定不是 target。 + r -= 1 + elif nums[mid] < nums[r]: + # 右區間是遞增的。 + if nums[mid] < target <= nums[r]: + l = mid + 1 + else: + r = mid - 1 + else: + # 左區間是遞增的。 + if nums[l] <= target < nums[mid]: + r = mid - 1 + else: + l = mid + 1 + return False +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n)$,在最壞情況下,陣列中所有元素都相同,導致每次只能排除一個元素。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md new file mode 100644 index 00000000..ffc09961 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/3-6-exercises.md @@ -0,0 +1,187 @@ +--- +sidebar_position: 16 +--- + +# 3.6 練習 + +## 基礎難度 + +### [154. Find Minimum in Rotated Sorted Array II](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/) + +旋轉陣列的變形題之一。 + +
+ 題解 + +#### 解題思路 + +本題需要找到旋轉排序陣列中的最小值,且陣列中可能包含重複元素。利用 **二分搜尋法**,可以在 $O(\log n)$ 的平均時間複雜度下高效解決,儘管最壞情況可能退化到 $O(n)$。 + +- **重點問題**: + 1. 如果陣列中沒有重複元素,透過比較 `nums[mid]` 和 `nums[r]` 可以直接判斷哪個區間是遞增的。 + 2. 如果陣列中有重複元素,當 `nums[mid] == nums[r]` 時,無法直接確定哪一邊是遞增的,因此需要額外處理。 + +- **核心邏輯**: + 1. 計算中間值 `mid = (l + r) // 2`。 + 2. 如果 `nums[mid] < nums[r]`,說明右半部分是遞增的,最小值可能在左半部分或中間,更新右邊界 `r = mid`。 + 3. 如果 `nums[mid] > nums[r]`,說明左半部分是遞增的,最小值只能在右半部分,更新左邊界 `l = mid + 1`。 + 4. 如果 `nums[mid] == nums[r]`,無法確定遞增區間,縮小搜尋範圍,將右邊界減一 `r -= 1`。 + +#### 程式碼 + +```python +class Solution: + def findMin(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + while l < r: + mid = (l + r) // 2 + if nums[mid] < nums[r]: + r = mid # 最小值可能在左半部分或中間 + elif nums[mid] > nums[r]: + l = mid + 1 # 最小值一定在右半部分 + else: + r -= 1 # 無法確定區間遞增性,縮小範圍 + return nums[l] +``` + +#### 複雜度分析 + +- **時間複雜度**: + - 平均情況:$O(\log n)$,每次迭代將搜尋範圍減半。 + - 最壞情況:$O(n)$,當所有元素相同時,無法利用二分特性,只能線性縮小範圍。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +
+ + +--- + +### [540. Single Element in a Sorted Array](https://leetcode.com/problems/single-element-in-a-sorted-array/) + +在出現單獨數之前和之後,奇數位與偶數位的值發生了什麼變化? + +
+ 題解 + +#### 解題思路 + +本題需要在排序陣列中找到唯一不重複的元素,每個其他數字都恰好出現兩次。利用 **二分搜尋法**,可以有效地解決此問題。 + +1. **特性分析**: + - 不重複的單一元素會打破「成對分佈」的規律: + - 如果索引是偶數,且 `nums[mid] == nums[mid + 1]`,單一元素一定在右半部分。 + - 否則,單一元素在左半部分。 + - 調整 `mid` 為偶數,以便直接判斷其是否與右側元素配對。 + +2. **二分邏輯**: + - 若 `nums[mid] == nums[mid + 1]`,則單一元素在右側,移動左指標。 + - 若 `nums[mid] != nums[mid + 1]`,則單一元素在左側,移動右指標。 + +3. **最終結果**: + - 當 `left == right` 時,該索引即為單一元素所在位置。 + +#### 程式碼 + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + while l < r: + mid = (l + r) // 2 + if mid % 2 == 1: # 保證 mid 是偶數 + mid -= 1 + if nums[mid] == nums[mid + 1]: + l = mid + 2 # 單一元素在右側 + else: + r = mid # 單一元素在左側 + return nums[l] +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(\log n)$,因為每次迭代將搜尋範圍減半。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +
+ + + +--- + +## 進階難度 + +### [4. Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) + +需要對兩個陣列同時進行二分搜尋。 + +
+ 題解 + +#### 解題思路 + +本題需要在兩個排序陣列中找到中位數,要求時間複雜度為 $O(\log (m+n))$。我們可以利用 **二分搜尋法** 高效解決。 + +1. **特性分析**: + - 中位數將兩個陣列分為「左側」和「右側」兩部分,保證: + - 左側所有元素的數量等於或多於右側。 + - 左側所有元素小於等於右側。 + - 透過二分搜尋在其中一個陣列上劃分位置,從而確定整體的中位數。 + +2. **解法步驟**: + - 確保對短的陣列進行二分搜尋,以降低時間複雜度。 + - 設置兩個指標 `left` 和 `right`,表示短陣列的二分搜尋範圍。 + - 計算劃分位置: + - `i` 為短陣列的劃分位置。 + - `j` 為長陣列的劃分位置,根據總長度和 `i` 計算得出。 + - 比較劃分後的左右部分,判斷是否滿足條件: + - 左側最大值 $\leq$ 右側最小值。 + +3. **處理邊界條件**: + - 若劃分正確,根據總長度的奇偶性返回結果: + - 奇數時,返回左側最大值。 + - 偶數時,返回左側最大值與右側最小值的平均值。 + - 若劃分不正確,調整 `left` 或 `right`,繼續二分搜尋。 + +#### 程式碼 + +```python +class Solution: + def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: + # 保證 nums1 是較短的陣列 + if len(nums1) > len(nums2): + nums1, nums2 = nums2, nums1 + + m, n = len(nums1), len(nums2) + total_left = (m + n + 1) // 2 + + left, right = 0, m + while left <= right: + i = (left + right) // 2 # nums1 的劃分點 + j = total_left - i # nums2 的劃分點 + + nums1_left_max = float('-inf') if i == 0 else nums1[i - 1] + nums1_right_min = float('inf') if i == m else nums1[i] + nums2_left_max = float('-inf') if j == 0 else nums2[j - 1] + nums2_right_min = float('inf') if j == n else nums2[j] + + # 確保劃分正確 + if nums1_left_max <= nums2_right_min and nums2_left_max <= nums1_right_min: + # 如果總數是奇數,取左邊最大值 + if (m + n) % 2 == 1: + return max(nums1_left_max, nums2_left_max) + # 如果總數是偶數,取左邊最大值和右邊最小值的平均 + return (max(nums1_left_max, nums2_left_max) + min(nums1_right_min, nums2_right_min)) / 2 + + # 調整劃分 + elif nums1_left_max > nums2_right_min: + right = i - 1 + else: + left = i + 1 +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(\log \min(m, n))$,其中 $m$ 和 $n$ 分別為兩個陣列的長度。因為對較短的陣列進行二分搜尋。 +- **空間複雜度**: $O(1)$,只使用了常數額外空間。 + +
diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json new file mode 100644 index 00000000..36d8f9aa --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/3-binary-search-techniques/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "3. 居合斬!二分搜尋", + "position": 3, + "link": { + "type": "generated-index", + "description": "第 3 章 居合斬!二分搜尋" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx new file mode 100644 index 00000000..1cfd2cfc --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-1-common-sorting-algorithms.mdx @@ -0,0 +1,150 @@ +--- +sidebar_position: 17 +--- + +# 4.1 常用排序算法 + +雖然在 C++ 和 Python 裡都可以通過 sort 函數排序,而且在刷題時很少需要自己手寫排序算法,但熟悉各種排序算法可以加深對算法的基本理解,並有助於解決由這些排序算法引申出的題目。這裡展示兩種時間複雜度為 $O(n \log n)$ 的排序算法:`快速排序` 和 `合併排序`。其中前者速度較快,後者能保證相同值的元素在陣列中的相對位置不變(即“穩定排序”)。 + + +## 快速排序(Quicksort) + +快速排序的原理並不複雜:對於一個未排序片段,我們先隨機選擇一個位置作為樞軸,然後通過遍歷操作,將所有比樞軸小的數字移動到其左側,再將所有比樞軸大的數字移動到其右側。操作完成後,我們對樞軸左右側的片段再次進行快速排序即可。可證明,如果樞軸選取是隨機的,那麼該算法的平均複雜度可以達到 $O(n \log n)$,但最差情況下複雜度為 $O(n^2)$。 + +我們採用左閉右閉的二分寫法,初始化條件為 $l = 0, r = n - 1$。 + + + + +```cpp +void quickSort(vector &nums, int l, int r) { + if (l >= r) { + return; + } + // 在當前的 [l, r] 區間中,隨機選擇一個位置作為樞軸。 + int pivot = l + (rand() % (r - l + 1)); + int pivot_val = nums[pivot]; + // 將樞軸與 l 交換。 + swap(nums[l], nums[pivot]); + // 從 [l+1, r] 兩端向內遍歷,查找是否有位置不滿足遞增關係。 + int i = l + 1, j = r; + while (true) { + while (i < j && nums[j] >= pivot_val) { + --j; + } + while (i < j && nums[i] <= pivot_val) { + ++i; + } + if (i == j) { + break; + } + // i 位置的值大於樞軸值,j 位置的值小於樞軸值,將二者交換。 + swap(nums[i], nums[j]); + } + // i 和 j 相遇的位置即為新的樞軸,我們將樞軸與 l 重新交換回來。 + // 此時相遇位置左側一定比樞軸值小,右側一定比樞軸值大。 + int new_pivot = nums[i] <= nums[l] ? i : i - 1; + swap(nums[l], nums[new_pivot]); + quickSort(nums, l, new_pivot - 1); + quickSort(nums, new_pivot + 1, r); +} +``` + + + + +```py +def quickSort(nums: List[int], l: int, r: int) -> None: + if l >= r: + return + # 在當前的 [l, r] 區間中,隨機選擇一個位置作為樞軸。 + pivot = random.randint(l, r) + pivot_val = nums[pivot] + # 將樞軸與 l 交換。 + nums[l], nums[pivot] = nums[pivot], nums[l] + # 從 [l+1, r] 兩端向內遍歷,查找是否有位置不滿足遞增關係。 + i, j = l + 1, r + while True: + while i < j and nums[j] >= pivot_val: + j -= 1 + while i < j and nums[i] <= pivot_val: + i += 1 + if i == j: + break + # i 位置的值大於樞軸值,j 位置的值小於樞軸值,將二者交換。 + nums[i], nums[j] = nums[j], nums[i] + # i 和 j 相遇的位置即為新的樞軸,我們將樞軸與 l 重新交換回來。 + # 此時相遇位置左側一定比樞軸值小,右側一定比樞軸值大。 + new_pivot = i if nums[i] <= nums[l] else i - 1 + nums[l], nums[new_pivot] = nums[new_pivot], nums[l] + quickSort(nums, l, new_pivot - 1) + quickSort(nums, new_pivot + 1, r) +``` + + + + + +## 合併排序(Merge Sort) + +合併排序是典型的分治法,會在後續章節展開講解。簡單來說,對於一個未排序片段,我們可以先分別排序其左半側和右半側,然後將兩側重新合併(“治”);排序每個半側時可以通過遞迴再次將其切分為兩側(“分”)。 + +我們採用左閉右閉的二分寫法,初始化條件為 $l = 0, r = n - 1$,並提前建立一個與 nums 大小相同的陣列 cache,用來儲存臨時結果。 + + + + +```cpp +void mergeSort(vector &nums, vector &cache, int l, int r) { + if (l >= r) { + return; + } + // 分。 + int mid = l + (r - l) / 2; + mergeSort(nums, cache, l, mid); + mergeSort(nums, cache, mid + 1, r); + // 治。 + // i 和 j 同時向右前進,i 的範圍是 [l, mid],j 的範圍是 [mid+1, r]。 + int i = l, j = mid + 1; + for (int pos = l; pos <= r; ++pos) { + if (j > r || (i <= mid && nums[i] <= nums[j])) { + cache[pos] = nums[i++]; + } else { + cache[pos] = nums[j++]; + } + } + // 將 cache 的數據複製回 nums。 + for (int pos = l; pos <= r; ++pos) { + nums[pos] = cache[pos]; + } +} +``` + + + + +```py +def mergeSort(nums: List[int], cache: List[int], l: int, r: int) -> None: + if l >= r: + return + # 分。 + mid = (l + r) // 2 + mergeSort(nums, cache, l, mid) + mergeSort(nums, cache, mid + 1, r) + # 治。 + # i 和 j 同時向右前進,i 的範圍是 [l, mid],j 的範圍是 [mid+1, r]。 + i, j = l, mid + 1 + for pos in range(l, r + 1): + if j > r or (i <= mid and nums[i] <= nums[j]): + cache[pos] = nums[i] + i += 1 + else: + cache[pos] = nums[j] + j += 1 + # 將 cache 的數據複製回 nums。 + nums[l:r+1] = cache[l:r+1] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx new file mode 100644 index 00000000..32a24ab0 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-2-quick-select.mdx @@ -0,0 +1,85 @@ +--- +sidebar_position: 18 +--- + +# 4.2 快速選擇 + +## [215. Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) + +### 題目描述 + +在一個未排序的陣列中,找到第 $k$ 大的數字。 + +### 輸入輸出範例 + +輸入一個陣列和一個目標值 $k$,輸出第 $k$ 大的數字。題目保證一定有解。 + +``` +Input: [3,2,1,5,6,4] and k = 2 +Output: 5 +``` + +### 題解 + +`快速選擇` 通常用於解決 k-th Element 問題,可以在平均 $O(n)$ 時間複雜度和 $O(1)$ 空間複雜度下完成求解。快速選擇的實現與快速排序相似,但只需要找到第 $k$ 大的中樞(pivot),不需要對中樞左右再進行排序。與快速排序一樣,快速選擇一般需要先將陣列打亂,否則最壞情況下的時間複雜度為 $O(n^2)$。 + +如果直接使用上述快速排序的代碼運行,可能會在 LeetCode 平台上接近超時。我們可以使用空間換取時間,直接儲存比中樞值小和大的元素,盡量避免進行交換操作。 + + + + +```cpp +int findKthLargest(vector nums, int k) { + int pivot = rand() % nums.size(); + int pivot_val = nums[pivot]; + vector larger, equal, smaller; + for (int num : nums) { + if (num > pivot_val) { + larger.push_back(num); + } else if (num < pivot_val) { + smaller.push_back(num); + } else { + equal.push_back(num); + } + } + if (k <= larger.size()) { + return findKthLargest(larger, k); + } + if (k > larger.size() + equal.size()) { + return findKthLargest(smaller, k - larger.size() - equal.size()); + } + return pivot_val; +} +``` + + + + +```py +def findKthLargest(nums: List[int], k: int) -> int: + pivot_val = random.choice(nums) + larger, equal, smaller = [], [], [] + for num in nums: + if num > pivot_val: + larger.append(num) + elif num < pivot_val: + smaller.append(num) + else: + equal.append(num) + if k <= len(larger): + return findKthLargest(larger, k) + if k > len(larger) + len(equal): + return findKthLargest(smaller, k - len(larger) - len(equal)) + return pivot_val +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: + - 平均情況:$O(n)$,因為每次劃分會縮小問題規模。 + - 最壞情況:$O(n^2)$,當每次選擇的樞軸總是最差值(例如極大值或極小值)。 +- **空間複雜度**: $O(n)$,需要額外的空間來存放三個分組的元素。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx new file mode 100644 index 00000000..d9eb505b --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-3-bucket-sort.mdx @@ -0,0 +1,88 @@ +--- +sidebar_position: 19 +--- + +# 4.3 桶排序 + +## [347. Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) + +### 題目描述 + +給定一個陣列,求前 $k$ 個最常出現的數字。 + +### 輸入輸出範例 + +輸入是一個陣列和一個目標值 $k$。輸出是一個長度為 $k$ 的陣列。 + +``` +Input: nums = [1,1,1,1,2,2,3,4], k = 2 +Output: [1,2] +``` + +在這個範例中,最常出現的兩個數字是 1 和 2。 + +### 題解 + +顧名思義,`桶排序` 的意思是為每個值設立一個桶,桶內記錄這個值出現的次數(或其他屬性),然後對桶進行排序。針對範例來說,我們先通過桶排序得到四個桶 [1,2,3,4],它們的值分別為 [4,2,1,1],表示每個數字出現的頻率。 + +接著,我們對桶的頻率進行排序,前 $k$ 大的桶即是前 $k$ 個最常出現的數字。這裡我們可以使用各種排序算法,甚至可以再進行一次桶排序,把每個舊桶根據頻率放在不同的新桶內。針對範例來說,因為目前最大的頻率是 4,我們建立 [1,2,3,4] 四個新桶,它們分別放入的舊桶為 [[3,4],[2],[],[1]],表示不同數字出現的頻率。最後,我們從後往前遍歷,直到找到 k 個舊桶。 + +我們可以使用 C++ 中的 `unordered_map` 或 Python 中的 `dict` 實現雜湊表。 + + + + +```cpp +vector topKFrequent(vector& nums, int k) { + unordered_map counts; + for (int num : nums) { + ++counts[num]; + } + unordered_map> buckets; + for (auto [num, count] : counts) { + buckets[count].push_back(num); + } + vector top_k; + for (int count = nums.size(); count >= 0; --count) { + if (buckets.contains(count)) { + for (int num : buckets[count]) { + top_k.push_back(num); + if (top_k.size() == k) { + return top_k; + } + } + } + } + return top_k; +} +``` + + + + +```py +def topKFrequent(nums: List[int], k: int) -> List[int]: + counts = Counter(nums) + buckets = dict() + for num, count in counts.items(): + if count in buckets: + buckets[count].append(num) + else: + buckets[count] = [num] + top_k = [] + for count in range(len(nums), 0, -1): + if count in buckets: + top_k += buckets[count] + if len(top_k) >= k: + return top_k[:k] + return top_k[:k] +``` + + + + + +### 複雜度分析 +- **時間複雜度**: $O(n)$,統計頻率需要 $O(n)$ 時間,桶排序收集元素的時間複雜度也是 $O(n)$,其中 $n$ 是 `nums` 的長度。 + +- **空間複雜度**: $O(n)$:`counts` 和 `buckets` 需要儲存所有元素及其頻率,最壞情況下需要 $O(n)$ 空間。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md new file mode 100644 index 00000000..9f74424b --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/4-4-exercises.md @@ -0,0 +1,113 @@ +--- +sidebar_position: 20 +--- + +# 4.4 練習 + +## 基礎難度 + +### [451. Sort Characters By Frequency](https://leetcode.com/problems/sort-characters-by-frequency/) + +桶排序的變形題。 + +
+ 題解 + +#### 解題思路 + +本題要求根據字元的出現頻率對字元進行排序,並返回排序後的字串。可以使用 **雜湊表** 和 **桶排序** 來高效解決這個問題。 + +1. **統計字元頻率**: + - 使用 `Counter` 統計每個字元的出現次數,將結果儲存到 `counts`。 + +2. **桶排序**: + - 建立一個桶 `buckets`,其中索引表示字元的出現頻率,值是具有該頻率的字元列表。 + - 根據字元的頻率將它們放入對應的桶中。 + +3. **生成結果**: + - 從高頻到低頻遍歷桶,根據頻率將字元重複相應次數,拼接成結果字串。 + +#### 程式碼 + +```python +class Solution: + def frequencySort(self, s: str) -> str: + counts = Counter(s) + buckets = dict() + result = [] + for char, count in counts.items(): + if count in buckets: + buckets[count].append(char) + else: + buckets[count] = [char] + for count in range(len(s), 0, -1): + if count in buckets: + for char in buckets[count]: + result.append(char*count) + return ''.join(result) +``` + +#### 複雜度分析 + +- **時間複雜度**: + - $O(n)$,其中 $n$ 是字串的長度。統計頻率需要 $O(n)$,桶排序和拼接結果也需要 $O(n)$。 + +- **空間複雜度**: + - $O(n)$,用於儲存字元頻率的雜湊表和桶。 + +
+ + +--- + +## 進階難度 + +### [75. Sort Colors](https://leetcode.com/problems/sort-colors/) + +非常經典的荷蘭國旗問題,考察如何對三個重複且混亂的值進行排序。 + +
+ 題解 + +#### 解題思路 + +本題要求對包含 `0`、`1` 和 `2` 的陣列進行排序,使得相同數字的元素相鄰,並且按照 `0`、`1`、`2` 的順序排列。我們可以在 $O(n)$ 的時間複雜度內使用 **雙指標(雙指針)** 來完成排序,該方法被稱為 **荷蘭國旗問題**。 + +1. **初始化三個指標**: + - `left`:指向下一個要放置 `0` 的位置。 + - `right`:指向下一個要放置 `2` 的位置。 + - `i`:當前遍歷的索引。 + +2. **遍歷陣列**: + - 當 `nums[i] == 0` 時,將 `nums[i]` 與 `nums[left]` 交換,然後將 `left` 和 `i` 向右移動。 + - 當 `nums[i] == 2` 時,將 `nums[i]` 與 `nums[right]` 交換,並將 `right` 向左移動(此時不移動 `i`,因為交換過來的值可能還需要處理)。 + - 當 `nums[i] == 1` 時,僅將 `i` 向右移動。 + +3. **終止條件**: + - 當 `i` 超過 `right` 時,排序完成。 + +#### 程式碼 + +```python +class Solution: + def sortColors(self, nums: List[int]) -> None: + left, i, right = 0, 0, len(nums) - 1 + + while i <= right: + if nums[i] == 0: + nums[left], nums[i] = nums[i], nums[left] + left += 1 + i += 1 + elif nums[i] == 2: + nums[right], nums[i] = nums[i], nums[right] + right -= 1 + else: + i += 1 +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是陣列的長度。每個元素最多只被遍歷一次。 +- **空間複雜度**: $O(1)$,僅使用了常數額外空間。 + +
diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json new file mode 100644 index 00000000..4aad536a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/4-sorting-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "4. 千奇百怪的排序算法", + "position": 4, + "link": { + "type": "generated-index", + "description": "第 4 章 千奇百怪的排序算法" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md new file mode 100644 index 00000000..b39abea7 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-1-algorithm-explanation.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 21 +--- + +# 5.1 算法解釋 + +`深度優先搜尋 (DFS)` 和 `廣度優先搜尋 (BFS)` 是兩種最常見的優先搜尋方法,廣泛應用於圖與樹等結構的搜尋中。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx new file mode 100644 index 00000000..10e2dd30 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-2-depth-first-search.mdx @@ -0,0 +1,398 @@ +--- +sidebar_position: 22 +--- + +# 5.2 深度優先搜尋 + +`深度優先搜尋 (DFS)` 是一種搜尋方法,在搜尋到一個新節點時,會立即對該節點進行遍歷。因此,遍歷需要使用 `先入後出 (LIFO) 的堆疊`,也可以透過與堆疊等價的 `遞迴` 來實現。對於樹結構而言,由於每次總是對新節點進行遍歷,因此看起來像是往“深”的方向前進。在 Python 中,我們可以使用 collections.deque 來實現 C++ 中的堆疊。然而,在大多數情況下,我們會選擇使用 C++ 的 vector 或 Python 的 list 來實現堆疊,因為它們不僅是先入後出的數據結構,還支持隨機存取。 + +考慮以下簡單的樹結構,從節點 1 開始進行遍歷。如果遍歷順序是從左子節點到右子節點,那麼按照優先往“深”的方向前進的策略,遍歷過程將是:1(起始節點)→ 2(更深層的左子節點)→ 4(更深層的左子節點)→ 2(無子節點,返回父節點)→ 1(所有子節點已完成遍歷,返回父節點)→ 3(更深層的右子節點)→ 1(無子節點,返回父節點)→ 結束程序(所有子節點已完成遍歷)。如果我們使用堆疊實現,堆疊頂部元素的變化過程將是:1 → 2 → 4 → 3。 + +``` + 1 + / \ + 2 3 + / +4 +``` + +深度優先搜尋也可以用來 `檢測迴路`:記錄每個遍歷過的節點的父節點,若某節點被再次遍歷且父節點不同,則說明存在迴路。另一種方法是利用拓撲排序判斷是否有迴路,若最後有節點的入度不為零,則說明存在迴路。 + +有時我們需要對已經搜尋過的節點進行標記,以防止重複搜索,這種做法稱為 `狀態記錄` 或 `記憶化 (memoization)`。 + +## [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/) + +### 題目描述 + +給定一個二維的 0-1 矩陣,其中 `0` 表示海洋,`1` 表示陸地。獨立的或相鄰的陸地可以形成島嶼,每個格子僅與其上下左右四個格子相鄰。求最大的島嶼面積。 + +### 輸入輸出範例 + +輸入是一個二維陣列,輸出是一個整數,表示最大的島嶼面積。 + +``` +Input: +[[1,0,1,1,0,1,0,1], + [1,0,1,1,0,1,1,1], + [0,0,0,0,0,0,0,1]] +Output: 6 +``` + +最大的島嶼面積為 6,位於最右側。 + +### 題解 + +此題是一個非常標準的搜索問題,我們可以用來練習深度優先搜索(DFS)。一般來說,深度優先搜索類型的題目可以分為主函數和輔函數兩部分。主函數負責遍歷所有的搜索位置,判斷是否可以開始搜索,如果可以則調用輔函數進行搜索。輔函數則負責深度優先搜索的遞迴調用。 + +當然,我們也可以使用堆疊(stack)來實現深度優先搜索,但由於堆疊與遞迴的運作原理相同,而遞迴相對來說實現起來更為方便,因此在刷題時建議使用遞迴的寫法,這樣也有利於進行回溯(見下節)。不過在實際工程中,直接使用堆疊可能才是更好的選擇,原因有二:一是更容易理解,二是不容易出現遞迴堆疊溢出的情況。 + +我們先展示使用堆疊的寫法。這裡我們使用了一個小技巧,對於四個方向的遍歷,可以創建一個陣列 `[-1, 0, 1, 0, -1]`,每相鄰兩位即對應上下左右四個方向之一。當然,您也可以顯式地寫成 `[-1, 0]`、`[1, 0]`、`[0, 1]` 和 `[0, -1]`,以便於理解。 + + + + + +```cpp +int maxAreaOfIsland(vector>& grid) { + vector direction{-1, 0, 1, 0, -1}; + int m = grid.size(), n = grid[0].size(), max_area = 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + stack> island; + // 初始化第一個節點。 + int local_area = 1; + grid[i][j] = 0; + island.push({i, j}); + // 深度優先搜索 (DFS)。 + while (!island.empty()) { + auto [r, c] = island.top(); + island.pop(); + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + // 將滿足條件的相鄰節點加入堆疊。 + if (x >= 0 && x < m && y >= 0 && y < n && + grid[x][y] == 1) { + ++local_area; + grid[x][y] = 0; + island.push({x, y}); + } + } + } + max_area = max(max_area, local_area); + } + } + } + return max_area; +} +``` + + + + +```py +def maxAreaOfIsland(grid: List[List[int]]) -> int: + direction = [-1, 0, 1, 0, -1] + m, n, max_area = len(grid), len(grid[0]), 0 + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + island = [] + # 初始化第一個節點。 + local_area = 1 + grid[i][j] = 0 + island.append((i, j)) + # 深度優先搜索 (DFS)。 + while len(island) > 0: + r, c = island.pop() + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + # 將滿足條件的相鄰節點加入堆疊。 + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: + local_area += 1 + grid[x][y] = 0 + island.append((x, y)) + max_area = max(max_area, local_area) + return max_area +``` + + + + + +### 複雜度分析(堆疊) + +- **時間複雜度**: $O(m \times n)$,其中 $m$ 和 $n$ 分別是網格的行數和列數。每個節點最多訪問一次。 +- **空間複雜度**: $O(m \times n)$,最壞情況下堆疊中可能包含整個網格的所有陸地節點。 + +下面我們展示遞迴寫法,注意進行遞迴搜尋時,一定要檢查邊界條件。可以在每次呼叫輔助函式之前檢查,也可以在輔助函式的一開始進行檢查。這裡我們沒有利用 [-1, 0, 1, 0, -1] 陣列進行上下左右四個方向的搜尋,而是直接顯式地寫出來四種不同的遞迴函式。兩種寫法都可以,讀者可以掌握任意一種。 + + + + +```cpp +// 輔助函式。 +int dfs(vector>& grid, int r, int c) { + if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size() || + grid[r][c] == 0) { + return 0; + } + grid[r][c] = 0; + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)); +} + +// 主函式。 +int maxAreaOfIsland(vector>& grid) { + int max_area = 0; + for (int i = 0; i < grid.size(); ++i) { + for (int j = 0; j < grid[0].size(); ++j) { + max_area = max(max_area, dfs(grid, i, j)); + } + } + return max_area; +} +``` + + + + +```py +# 輔助函式。 +def dfs(grid: List[List[int]], r: int, c: int) -> int: + if r < 0 or r >= len(grid) or c < 0 or c >= len(grid[0]) or grid[r][c] == 0: + return 0 + grid[r][c] = 0 + return (1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) + + dfs(grid, r, c + 1) + dfs(grid, r, c - 1)) + +# 主函式。 +def maxAreaOfIsland(grid: List[List[int]]) -> int: + max_area = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + max_area = max(max_area, dfs(grid, i, j)) + return max_area +``` + + + + + +### 複雜度分析(遞迴) + +- **時間複雜度**: $O(m \times n)$,其中 $m$ 是網格的行數,$n$ 是網格的列數。每個節點最多訪問一次。 + +- **空間複雜度**: $O(m \times n)$,最壞情況下遞迴堆疊的深度可能等於整個網格的大小(當所有節點都是 `1` 時)。 + +## [547. Number of Provinces](https://leetcode.com/problems/number-of-provinces/) + +### 題目描述 + +給定一個二維的 0-1 矩陣,如果第 (i, j) 位置是 1,則表示第 i 個城市和第 j 個城市處於同一城市圈。已知城市的相鄰關係是可以傳遞的,即如果 a 和 b 相鄰,b 和 c 相鄰,那麼 a 和 c 也相鄰,換言之這三個城市處於同一個城市圈之內。求一共有多少個城市圈。 + +### 輸入輸出範例 + +輸入是一個二維陣列,輸出是一個整數,表示城市圈數量。因為城市相鄰關係具有對稱性,該二維陣列為對稱矩陣。同時,因為自己也處於自己的城市圈,對角線上的值全部為 1。 + +``` +Input: +[[1,1,0], + [1,1,0], + [0,0,1]] +Output: 2 +``` + +在這個範例中,[1,2] 處於一個城市圈,[3] 處於另一個城市圈。 + +### 題解 + +在上一道題目中,圖的表示方法是,每個位置代表一個節點,每個節點與上下左右四個節點相鄰。而在這一道題目裡面,每一行(列)表示一個節點,它的每列(行)表示是否存在一個相鄰節點。上一道題目擁有 $m \times n$ 個節點,每個節點有 4 條邊;而本題擁有 $n$ 個節點,每個節點最多有 $n$ 條邊,表示和所有城市都相鄰,最少可以有 1 條邊,表示當前城市圈只有自己。當清楚了圖的表示方法後,這道題目與上一道題目本質上是同一道題:搜索城市圈(島嶼圈)的個數。我們這裡採用遞迴的寫法。 + +:::warning + +對於節點連接類問題,我們也可以利用並查集來進行快速的連接和搜索。我們將會在之後的章節講解。 + +::: + + + + +```cpp +// 輔助函式。 +void dfs(vector>& isConnected, int i, vector& visited) { + visited[i] = true; + for (int j = 0; j < isConnected.size(); ++j) { + if (isConnected[i][j] == 1 && !visited[j]) { + dfs(isConnected, j, visited); + } + } +} + +// 主函式。 +int findCircleNum(vector>& isConnected) { + int n = isConnected.size(), count = 0; + // 防止重複搜索已被搜索過的節點 + vector visited(n, false); + for (int i = 0; i < n; ++i) { + if (!visited[i]) { + dfs(isConnected, i, visited); + ++count; + } + } + return count; +} +``` + + + + +```py +# 輔助函式。 +def dfs(isConnected: List[List[int]], city: int, visited: Set[int]): + visited.add(city) + for i in range(len(isConnected)): + if isConnected[city][i] == 1 and i not in visited: + dfs(isConnected, i, visited) + +# 主函式。 +def findCircleNum(isConnected: List[List[int]]) -> int: + count = 0 + # 防止重複搜索已被搜索過的節點 + visited = set() + for i in range(len(isConnected)): + if i not in visited: + dfs(isConnected, i, visited) + count += 1 + return count +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n^2)$,其中 $n$ 是城市的數量。遍歷整個 `isConnected` 矩陣,並對每個城市進行 DFS。 + +- **空間複雜度**: $O(n)$,用於儲存 `visited` 集合和遞迴呼叫的堆疊空間。 + + +## [417. Pacific Atlantic Water Flow](https://leetcode.com/problems/pacific-atlantic-water-flow/) + +### 題目描述 + +給定一個二維的非負整數矩陣,每個位置的值表示海拔高度。假設左邊和上邊是太平洋,右邊和下邊是大西洋,求從哪些位置向下流水可以流到太平洋和大西洋。水只能從海拔高的位置流向海拔低或相同的位置。 + +### 輸入輸出範例 + +輸入是一個二維的非負整數矩陣,表示海拔高度。輸出是一個二維的陣列,其中第二維大小固定為 2,表示滿足條件的位置坐標。 + +``` +Input: + 太平洋 ~ ~ ~ ~ ~ + ~ 1 2 2 3 (5) * + ~ 3 2 3 (4) (4) * + ~ 2 4 (5) 3 1 * + ~ (6) (7) 1 4 5 * + ~ (5) 1 1 2 4 * + * * * * * 大西洋 +Output: [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] +``` + +在此範例中,有括號的區域為滿足條件的位置。 + + +### 題解 + +雖然題目要求找到可以向下流到達兩個大洋的位置,如果對所有位置進行搜索,複雜度會非常高且無法剪枝。因此我們可以反向思考,從兩個大洋開始模擬水往上流,這樣只需要對矩形的四條邊進行搜索。完成搜索後,遍歷整個矩陣,找到兩個大洋向上流都能到達的位置,即為滿足條件的位置。 + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// 輔助函式。 +void dfs(const vector>& heights, vector>& can_reach, + int r, int c) { + if (can_reach[r][c]) { + return; + } + can_reach[r][c] = true; + for (int i = 0; i < 4; ++i) { + int x = r + direction[i], y = c + direction[i + 1]; + if (x >= 0 && x < heights.size() && y >= 0 && y < heights[0].size() && + heights[r][c] <= heights[x][y]) { + dfs(heights, can_reach, x, y); + } + } +} + +// 主函式。 +vector> pacificAtlantic(vector>& heights) { + int m = heights.size(), n = heights[0].size(); + vector> can_reach_p(m, vector(n, false)); + vector> can_reach_a(m, vector(n, false)); + vector> can_reach_p_and_a; + for (int i = 0; i < m; ++i) { + dfs(heights, can_reach_p, i, 0); + dfs(heights, can_reach_a, i, n - 1); + } + for (int i = 0; i < n; ++i) { + dfs(heights, can_reach_p, 0, i); + dfs(heights, can_reach_a, m - 1, i); + } + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (can_reach_p[i][j] && can_reach_a[i][j]) { + can_reach_p_and_a.push_back({i, j}); + } + } + } + return can_reach_p_and_a; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# 輔助函式。 +def dfs(heights: List[List[int]], can_reach: List[List[int]], r: int, c: int): + if can_reach[r][c]: + return + can_reach[r][c] = True + for i in range(4): + x, y = r + direction[i], c + direction[i + 1] + if (x >= 0 and x < len(heights) and y >= 0 and y < len(heights[0]) and + heights[x][y] >= heights[r][c]): + dfs(heights, can_reach, x, y) + +# 主函式。 +def pacificAtlantic(heights: List[List[int]]) -> List[List[int]]: + m, n = len(heights), len(heights[0]) + can_reach_p = [[False for _ in range(n)] for _ in range(m)] + can_reach_a = [[False for _ in range(n)] for _ in range(m)] + for i in range(m): + dfs(heights, can_reach_p, i, 0) + dfs(heights, can_reach_a, i, n - 1) + for j in range(n): + dfs(heights, can_reach_p, 0, j) + dfs(heights, can_reach_a, m - 1, j) + return [ + [i, j] for i in range(m) for j in range(n) + if can_reach_p[i][j] and can_reach_a[i][j] + ] +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(m \times n)$,其中 $m$ 是網格的行數,$n$ 是網格的列數。每個節點最多訪問一次。 + +- **空間複雜度**: $O(m \times n)$,用於儲存兩個布林矩陣和遞迴堆疊空間。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx new file mode 100644 index 00000000..806e5059 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-3-backtracking.mdx @@ -0,0 +1,399 @@ +--- +sidebar_position: 23 +--- + +# 5.3 回溯法 + +`回溯法`(backtracking)是優先搜索的一種特殊情況,又稱為試探法,常用於需要記錄節點狀態的深度優先搜索。通常來說,排列、組合、選擇類問題使用回溯法比較方便。 + +顧名思義,回溯法的核心是回溯。在搜索到某一節點的時候,如果我們發現目前的節點(及其子節點)並不是需求目標時,我們回退到原來的節點繼續搜索,並且`把在目前節點修改的狀態還原`。這樣的好處是我們可以始終只對圖的總狀態進行修改,而非每次遍歷時新建一個圖來儲存狀態。在具體的寫法上,它與普通的深度優先搜索一樣,都有 [修改當前節點狀態]→[遞迴子節點] 的步驟,只是多了回溯的步驟,變成了 [修改當前節點狀態]→[遞迴子節點]→[回復當前節點狀態]。 + +沒有接觸過回溯法的讀者可能會不明白我在講什麼,這也完全正常,希望以下幾道題可以讓您理解回溯法。如果還是不明白,可以記住兩個小訣竅,`一是按引用傳遞狀態,二是所有的狀態修改在遞迴完成後回復`。 + +回溯法修改一般有兩種情況,一種是修改最後一位輸出,比如排列組合;一種是修改訪問標記,比如矩陣裡搜尋字串。 + + +## [46. Permutations](https://leetcode.com/problems/permutations/) + +### 題目描述 + +給定一個無重複數字的整數陣列,求其所有排列方式。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,輸出是一個二維陣列,表示輸入陣列的所有排列方式。 + +``` +Input: [1,2,3] +Output: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]] +``` + +輸出的順序無需固定,只需包含所有排列即可。 + +### 題解 + +如何生成所有排列方式呢?對於每個位置 \(i\),我們可以將其與之後的任意位置交換,然後處理位置 \(i+1\),直到處理到最後一位。為了避免每次遍歷時新建一個陣列儲存前 \(i\) 個已交換好的數字,我們可以利用回溯法,僅修改原陣列,並在遞迴完成後復原。 + +以範例 `[1,2,3]` 為例,按照此方法,我們的輸出順序為:`[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]]`,確保涵蓋所有排列。 + + + + + +```cpp +// 輔助函式。 +void backtracking(vector &nums, int level, + vector> &permutations) { + if (level == nums.size() - 1) { + permutations.push_back(nums); // 儲存當前排列。 + return; + } + for (int i = level; i < nums.size(); ++i) { + swap(nums[i], nums[level]); // 修改當前節點狀態。 + backtracking(nums, level + 1, permutations); // 遞迴子節點。 + swap(nums[i], nums[level]); // 回復當前節點狀態。 + } +} + +// 主函式。 +vector> permute(vector &nums) { + vector> permutations; + backtracking(nums, 0, permutations); + return permutations; +} +``` + + + + +```py +# 輔助函式。 +def backtracking(nums: List[int], level: int, permutations: List[List[int]]): + if level == len(nums) - 1: + permutations.append(nums[:]) # 使用淺拷貝保存當前排列。 + return + for i in range(level, len(nums)): + nums[i], nums[level] = nums[level], nums[i] # 修改當前節點狀態。 + backtracking(nums, level + 1, permutations) # 遞迴子節點。 + nums[i], nums[level] = nums[level], nums[i] # 回復當前節點狀態。 + +# 主函式。 +def permute(nums: List[int]) -> List[List[int]]: + permutations = [] + backtracking(nums, 0, permutations) + return permutations +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n \times n!)$,其中 $n$ 是輸入數字的個數。總共有 $n!$ 個排列,每個排列的長度為 $n$。 +- **空間複雜度**: $O(n)$,遞迴堆疊的深度最多為 $n$。 + +## [77. Combinations](https://leetcode.com/problems/combinations/) + +### 題目描述 + +給定一個整數 n 和一個整數 k,求在 1 到 n 中選取 k 個數字的所有組合方法。 + +### 輸入輸出範例 + +輸入是兩個正整數 n 和 k,輸出是一個二維陣列,表示所有組合方式。 + +``` +Input: n = 4, k = 2 +Output: [[2,4], [3,4], [2,3], [1,2], [1,3], [1,4]] +``` + +這裡二維陣列的每個維度都可以以任意順序輸出。 + +### 題解 + +類似於排列問題,我們也可以進行回溯。排列回溯的是交換的位置,而組合回溯的是是否把當前的數字加入結果中。 + + + + +```cpp +// 輔助函式。 +void backtracking(vector>& combinations, vector& pick, int pos, + int n, int k) { + if (pick.size() == k) { + combinations.push_back(pick); + return; + } + for (int i = pos; i <= n; ++i) { + pick.push_back(i); // 修改當前節點狀態 + backtracking(combinations, pick, i + 1, n, k); // 遞迴子節點 + pick.pop_back(); // 回改當前節點狀態 + } +} + +// 主函式。 +vector> combine(int n, int k) { + vector> combinations; + vector pick; + backtracking(combinations, pick, 1, n, k); + return combinations; +} +``` + + + + +```py +# 輔助函式。 +def backtracking( + combinations: List[List[int]], pick: List[int], pos: int, n: int, k: int +): + if len(pick) == k: + combinations.append(pick[:]) # int為基本類型,可以淺拷貝 + return + for i in range(pos, n + 1): + pick.append(i) # 修改當前節點狀態 + backtracking(combinations, pick, i + 1, n, k) # 遞迴子節點 + pick.pop() # 回改當前節點狀態 + +# 主函式。 +def combine(n: int, k: int) -> List[List[int]]: + combinations = [] + pick = [] + backtracking(combinations, pick, 1, n, k) + return combinations +``` + + + + + +### 複雜度分析 +- **時間複雜度**: $O(C(n, k))$,其中 $C(n, k) = \frac{n!}{k!(n-k)!}$ 是 $n$ 中選擇 $k$ 個的組合數量,每次生成組合需要 $O(k)$ 的操作。 +- **空間複雜度**: $O(k)$,遞迴深度與暫存的組合長度相同,最多為 $k$。 + + +## [79. Word Search](https://leetcode.com/problems/word-search/) + +### 題目描述 + +給定一個字母矩陣,所有的字母都與上下左右四個方向上的字母相連。給定一個字串,求字串能不能在字母矩陣中尋找到。 + +### 輸入輸出範例 + +輸入是一個二維字元陣列和一個字串,輸出是一個布林值,表示字串是否可以被尋找到。 + +``` +Input: word = "ABCCED", board = +[[’A’,’B’,’C’,’E’], + [’S’,’F’,’C’,’S’], + [’A’,’D’,’E’,’E’]] +Output: true +``` + +從左上角的 ‘A’ 開始,我們可以先向右、再向下、最後向左,找到連續的 "ABCCED"。 + +### 題解 + +不同於排列組合問題,本題採用的並不是修改輸出方式,而是修改訪問標記。在我們對任意位置進行深度優先搜尋時,我們先標記當前位置為已訪問,以避免重複遍歷(如防止向右搜尋後又向左返回);在所有的可能都搜尋完成後,再回改當前位置為未訪問,防止干擾其他位置搜尋到當前位置。使用回溯法時,我們可以只對一個二維的訪問矩陣進行修改,而不用把每次的搜尋狀態作為一個新對象傳入遞迴函式中。 + + + + + +```cpp +// 輔助函式。 +bool backtracking(vector>& board, string& word, + vector>& visited, int i, int j, int word_pos) { + if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || + visited[i][j] || board[i][j] != word[word_pos]) { + return false; + } + if (word_pos == word.size() - 1) { + return true; + } + visited[i][j] = true; // 修改當前節點狀態 + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) || + backtracking(board, word, visited, i - 1, j, word_pos + 1) || + backtracking(board, word, visited, i, j + 1, word_pos + 1) || + backtracking(board, word, visited, i, j - 1, word_pos + 1)) { + return true; // 遞迴子節點 + } + visited[i][j] = false; // 回改當前節點狀態 + return false; +} + +// 主函式。 +bool exist(vector>& board, string word) { + int m = board.size(), n = board[0].size(); + vector> visited(m, vector(n, false)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (backtracking(board, word, visited, i, j, 0)) { + return true; + } + } + } + return false; +} +``` + + + + +```py +# 輔助函式。 +def backtracking(board: List[List[str]], word: str, + visited: List[List[bool]], i: int, j: int, word_pos: int): + if (i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) + or visited[i][j] or board[i][j] != word[word_pos]): + return False + if word_pos == len(word) - 1: + return True + visited[i][j] = True # 修改當前節點狀態 + if (backtracking(board, word, visited, i + 1, j, word_pos + 1) or + backtracking(board, word, visited, i - 1, j, word_pos + 1) or + backtracking(board, word, visited, i, j + 1, word_pos + 1) or + backtracking(board, word, visited, i, j - 1, word_pos + 1)): + return True # 遞迴子節點 + visited[i][j] = False # 回改當前節點狀態 + return False + +# 主函式。 +def exist(board: List[List[str]], word: str) -> bool: + m, n = len(board), len(board[0]) + visited = [[False for _ in range(n)] for _ in range(m)] + return any([ + backtracking(board, word, visited, i, j, 0) + for i in range(m) for j in range(n) + ]) +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(m \times n \times 4^L)$,其中 $m$ 與 $n$ 是矩陣的行數與列數,$L$ 是字串的長度。矩陣中每個單元格最多需要進行 $4^L$ 次遞迴檢查。 +- **空間複雜度**: $O(m \times n)$,用於儲存訪問狀態的二維布林陣列 `visited`。 + + +## [51. N-Queens](https://leetcode.com/problems/n-queens/) + +### 題目描述 + +給定一個大小為 n 的正方形國際象棋棋盤,求有多少種方式可以放置 n 個皇后並使得她們互不攻擊,即每一行、列、左斜、右斜最多只有一個皇后。 + +
+![](n-queens.png) +
題目 51 - 八皇后的一種解法
+
+ +### 輸入輸出範例 + +輸入是一個整數 n,輸出是一個二維字串陣列,表示所有的棋盤表示方法。 + +``` +Input: 4 +Output: [ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] +``` + +在這個範例中,點代表空白位置,Q 代表皇后。 + +### 題解 + +類似於在矩陣中尋找字串,本題也是透過修改狀態矩陣來進行回溯。不過不同的是,我們需要對每一行、列、左斜、右斜建立訪問陣列,用來記錄這些方向是否已經放置過皇后。如果我們按照每一行遍歷來插入皇后,就不需要為行方向建立訪問陣列。 + + + + +```cpp +// 輔助函式 +void backtracking(vector> &solutions, vector &board, + vector &column, vector &ldiag, + vector &rdiag, int row) { + int n = board.size(); + if (row == n) { + solutions.push_back(board); + return; + } + for (int i = 0; i < n; ++i) { + if (column[i] || ldiag[n - row + i - 1] || rdiag[row + i]) { + continue; + } + // 修改當前節點狀態 + board[row][i] = 'Q'; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = true; + // 遞迴子節點 + backtracking(solutions, board, column, ldiag, rdiag, row + 1); + // 回改當前節點狀態 + board[row][i] = '.'; + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = false; + } +} + +// 主函式。 +vector> solveNQueens(int n) { + vector> solutions; + vector board(n, string(n, ’.’)); + vector column(n, false); + vector ldiag(2 * n - 1, false); + vector rdiag(2 * n - 1, false); + backtracking(solutions, board, column, ldiag, rdiag, 0); + return solutions; +} +``` + + + + +```py +# 輔助函式。 +def backtracking(solutions: List[List[str]], board: List[List[str]], + column: List[bool], ldiag: List[bool], rdiag: List[bool], row: int): + n = len(board) + if row == n: + solutions.append(["".join(row) for row in board]) + return + for i in range(n): + if column[i] or ldiag[n - row + i - 1] or rdiag[row + i]: + continue + # 修改當前節點狀態 + board[row][i] = "Q" + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = True + # 遞迴子節點 + backtracking(solutions, board, column, ldiag, rdiag, row + 1) + # 回改當前節點狀態 + board[row][i] = "." + column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = False + +# 主函式。 +def solveNQueens(n: int) -> List[List[str]]: + solutions = [] + board = [["." for _ in range(n)] for _ in range(n)] + column = [False] * n + ldiag = [False] * (2 * n - 1) + rdiag = [False] * (2 * n - 1) + backtracking(solutions, board, column, ldiag, rdiag, 0) + return solutions +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n!)$,每一行(row)最多嘗試 $n$ 個位置,且需要遞迴 $n$ 層。 +- **空間複雜度**: $O(n^2)$,主要來自棋盤狀態記錄的 $O(n^2)$ 和輔助陣列(`column`、`ldiag`、`rdiag`)的 $O(n)$,以及遞迴堆疊的 $O(n)$,但棋盤占用空間為主導因素。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx new file mode 100644 index 00000000..d27c76e6 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-4-breadth-first-search.mdx @@ -0,0 +1,475 @@ +--- +sidebar_position: 24 +--- + +# 5.4 廣度優先搜尋 + +`廣度優先搜尋`(breadth-first search,BFS)不同於深度優先搜尋,它是一層層進行遍歷的,因此`需要用先入先出的佇列 (queue)` 而非先入後出的堆疊 (stack) 進行遍歷。由於是按層次進行遍歷,廣度優先搜尋時按照「廣」的方向進行遍歷,也常常用來處理最短路徑等問題。在 Python 中,我們可以用 `collections.deque` 來實現 C++ 中的 `queue`。 + + +``` + 1 + / \ + 2 3 + / +4 +``` + +這裡要注意,深度優先搜尋和廣度優先搜尋都可以處理`可達性`問題,即從一個節點開始是否能達到另一個節點。因為深度優先搜尋可以利用遞迴快速實現,很多人會習慣使用深度優先搜尋解決此類問題。實際軟體工程中,筆者很少見到遞迴的寫法,因為一方面難以理解,另一方面可能產生堆疊溢出的情況;而用堆疊實現的深度優先搜尋和用佇列實現的廣度優先搜尋在寫法上並沒有太大差異,因此使用哪一種搜尋方式需要根據實際的功能需求來判斷。另外,如果需要自定義搜尋優先順序,我們可以利用優先佇列,這個我們會在資料結構的章節講到。 + +## [1091. Shortest Path in Binary Matrix](https://leetcode.com/problems/shortest-path-in-binary-matrix/) + +### 題目描述 + +給定一個二維 0-1 矩陣,其中 1 表示障礙,0 表示道路,每個位置與周圍八個格子相連。求從左上角到右下角的最短到達距離。如果沒有可到達的方法,返回 -1。 + +### 輸入輸出範例 + +輸入是一個二維整數陣列,輸出是一個整數,表示最短距離。 + +``` +Input: +[[0,0,1], + [1,1,0], + [1,1,0]] +Output: 4 +``` + +最短到達方法為先向右,轉彎之後再向下。 + +### 題解 + +利用佇列,我們可以很直觀地利用廣度優先搜尋,搜索最少擴展層數,即最短到達目的地的距離。注意不要重複搜索相同位置。 + + + + + +```cpp +int shortestPathBinaryMatrix(vector>& grid) { + if (grid[0][0] == 1) { + return -1; + } + int m = grid.size(), n = grid[0].size(); + int dist = 0, count; + queue> q; + q.push({0, 0}); + grid[0][0] = -1; // -1表示visited + count = q.size(); + while (count > 0) { + ++dist; + while (count--) { + auto [r, c] = q.front(); + q.pop(); + if (r == m - 1 && c == n - 1) { + return dist; + } + for (int dx = -1; dx <= 1; ++dx) { + for (int dy = -1; dy <= 1; ++dy) { + if (dx == 0 && dy == 0) { + continue; + } + int x = r + dx, y = c + dy; + if (x < 0 || y < 0 || x >= m || y >= n || grid[x][y] != 0) { + continue; + } + grid[x][y] = -1; + q.push({x, y}); + } + } + } + count = q.size(); + } + return -1; +} +``` + + + + +```py +def shortestPathBinaryMatrix(grid: List[List[int]]) -> int: + if grid[0][0] == 1: + return -1 + m, n = len(grid), len(grid[0]) + dist = 0 + q = collections.deque() + q.append((0, 0)) + grid[0][0] = -1 # -1表示visited + count = len(q) + while count > 0: + dist += 1 + while count > 0: + count -= 1 + r, c = q.popleft() + if r == m - 1 and c == n - 1: + return dist + for dx in range(-1, 2): + for dy in range(-1, 2): + if dx == 0 and dy == 0: + continue + x, y = r + dx, c + dy + if x < 0 or y < 0 or x >= m or y >= n or grid[x][y] != 0: + continue + grid[x][y] = -1 + q.append((x, y)) + count = len(q) + return -1 +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n^2)$,最差情況下需遍歷整個棋盤,其中 $n$ 為棋盤的邊長。 +- **空間複雜度**: $O(n^2)$,主要來自佇列 `q` 和訪問標記。 + + +## [934. Shortest Bridge](https://leetcode.com/problems/shortest-bridge/) + +### 題目描述 + +給定一個二維 0-1 矩陣,其中 1 表示陸地,0 表示海洋,每個位置與上下左右相連。已知矩陣中有且只有兩個島嶼,求最少需要填海造陸多少個位置,才能將兩個島嶼相連。 + +### 輸入輸出範例 + +輸入是一個二維整數矩陣,輸出是一個非負整數,表示需要填海造陸的位置數。 + +``` +Input: +[[1,1,1,1,1], + [1,0,0,0,1], + [1,0,1,0,1], + [1,0,0,0,1], + [1,1,1,1,1]] +Output: 1 +``` + +### 題解 + +本題的實際目的是求兩個島嶼間的最短距離。因此,我們可以先通過任意搜尋方法找到其中一個島嶼,然後利用廣度優先搜尋來查找其與另一個島嶼的最短距離。以下程式碼展示了如何利用深度優先搜尋找到第一個島嶼。 + + + + + +```cpp +vector direction{-1, 0, 1, 0, -1}; +// 輔助函式。 + +void dfs(queue>& points, vector>& grid, int i, + int j) { + int m = grid.size(), n = grid[0].size(); + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 2) { + return; + } + if (grid[i][j] == 0) { + points.push({i, j}); + return; + } + grid[i][j] = 2; + for (int k = 0; k < 4; ++k) { + dfs(points, grid, i + direction[k], j + direction[k + 1]); + } +} + +// 主函式。 +int shortestBridge(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + queue> points; + // DFS尋找第一個島嶼,並將1改為2 + bool flipped = false; + for (int i = 0; i < m && !flipped; ++i) { + for (int j = 0; j < n && !flipped; ++j) { + if (grid[i][j] == 1) { + dfs(points, grid, i, j); + flipped = true; + } + } + } + // BFS尋找第二個島嶼,並將過程中經過的0改為2 + int level = 0; + while (!points.empty()) { + ++level; + int n_points = points.size(); + while (n_points--) { + auto [r, c] = points.front(); + points.pop(); + grid[r][c] = 2; + for (int k = 0; k < 4; ++k) { + int x = r + direction[k], y = c + direction[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n) { + if (grid[x][y] == 2) { + continue; + } + if (grid[x][y] == 1) { + return level; + } + grid[x][y] = 2; + points.push({x, y}); + } + } + } + } + return 0; +} +``` + + + + +```py +direction = [-1, 0, 1, 0, -1] + +# 輔助函式。 +def dfs(points: Deque[Tuple[int, int]], grid: List[List[int]], i: int, j: int): + m, n = len(grid), len(grid[0]) + if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 2: + return + if grid[i][j] == 0: + points.append((i, j)) + return + grid[i][j] = 2 + for k in range(4): + dfs(points, grid, i + direction[k], j + direction[k + 1]) + +def shortestBridge(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + points = collections.deque() + # DFS尋找第一個島嶼,並將1改為2 + flipped = False + for i in range(m): + if flipped: + break + for j in range(n): + if grid[i][j] == 1: + dfs(points, grid, i, j) + flipped = True + break + # BFS尋找第二個島嶼,並將過程中經過的0改為2 + level = 0 + while len(points) > 0: + level += 1 + points_at_current_level = len(points) + for _ in range(points_at_current_level): + r, c = points.popleft() + grid[r][c] = 2 + for k in range(4): + x, y = r + direction[k], c + direction[k + 1] + if x >= 0 and x < m and y >= 0 and y < n: + if grid[x][y] == 2: + continue + if grid[x][y] == 1: + return level + grid[x][y] = 2 + points.append((x, y)) + return level +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(n^2)$,其中 $n$ 是棋盤的邊長。DFS 遍歷第一個島嶼需要 $O(n^2)$,BFS 最多遍歷剩餘的格子,也需要 $O(n^2)$。 +- **空間複雜度**: $O(n^2)$,主要來自 `deque` 儲存邊界點,以及遞迴調用的堆疊空間。 + +## [126. Word Ladder II](https://leetcode.com/problems/word-ladder-ii/) + +### 題目描述 + +給定一個起始字串和一個終止字串,以及一個單詞表,求是否可以將起始字串每次改變一個字元,直到變成終止字串,且所有中間的修改過程表示的字串都可以在單詞表中找到。若存在,輸出需要修改次數最少的所有更改方式。 + + +### 輸入輸出範例 + +輸入是兩個字串,輸出是一個二維字串陣列,表示每種字串修改方式。 + +``` +Input: beginWord = "hit", endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] +Output: +[["hit","hot","dot","dog","cog"], + ["hit","hot","lot","log","cog"]] +``` + +### 題解 + + +我們可以把起始字串、終止字串,以及單詞表裡所有的字串想像成節點。若兩個字串只有一個字元不同,那麼它們相連。因為題目需要輸出修改次數最少的所有修改方式,因此我們可以使用廣度優先搜尋,求得起始節點到終止節點的最短距離。 + +我們同時還使用了一個小技巧:我們並不是直接從起始節點進行廣度優先搜尋,直到找到終止節點為止;而是從起始節點和終止節點分別進行廣度優先搜尋,每次只延展當前層節點數最少的那一端,這樣我們可以減少搜尋的總節點數。舉例來說,假設最短距離為 4,如果我們只從一端搜尋 4 層,總遍歷節點數最多是 $1 + 2 + 4 + 8 + 16 = 31$;而如果我們從兩端各搜尋兩層,總遍歷節點數最多只有 $2 × (1 + 2 + 4) = 14$。 + +在搜尋結束後,我們還需要通過回溯法來重建所有可能的路徑。 + +這道題略微複雜,需要讀者耐心思考和實現代碼。LeetCode 對此題的時間要求非常嚴格,即使是官方題解也經常容易超時,可以嘗試多次提交。 + + + + +```cpp +// 輔助函式。 +void backtracking(const string &src, const string &dst, + unordered_map> &next_words, + vector &path, vector> &ladder) { + if (src == dst) { + ladder.push_back(path); + return; + } + if (!next_words.contains(src)) { + return; + } + for (const auto &w : next_words[src]) { + path.push_back(w); // 修改當前節點狀態 + backtracking(w, dst, next_words, path, ladder); // 遞迴子節點 + path.pop_back(); // 回改當前節點狀態 + } +} + +// 主函式。 +vector> findLadders(string beginWord, string endWord, + vector &wordList) { + vector> ladder; + // 使用雜湊集合儲存字典,方便查找。 + unordered_set word_dict; + for (const auto &w : wordList) { + word_dict.insert(w); + } + if (!word_dict.contains(endWord)) { + return ladder; + } + word_dict.erase(beginWord); + word_dict.erase(endWord); + // 建立兩個queue,從beginWord和endWord同時延展,每次延展最小的。 + // 因為之後的去重操作需要遍歷queue,我們這裡用雜湊表實現它, + // 只要保證是分層次遍歷即可。 + unordered_set q_small{beginWord}, q_large{endWord}; + unordered_map> next_words; + bool reversed_path = false, found_path = false; + while (!q_small.empty()) { + unordered_set q; + for (const auto &w : q_small) { + string s = w; + for (int i = 0; i < s.size(); ++i) { + for (int j = 0; j < 26; ++j) { + s[i] = j + 'a'; + if (q_large.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + found_path = true; + } + if (word_dict.contains(s)) { + reversed_path ? next_words[s].push_back(w) + : next_words[w].push_back(s); + q.insert(s); + } + } + s[i] = w[i]; + } + } + if (found_path) { + break; + } + // 環路一定不是最短解,所以這裡需要去重和避免無限循環。 + for (const auto &w : q) { + word_dict.erase(w); + } + // 更新兩個queue,並維持大小關係。 + if (q.size() <= q_large.size()) { + q_small = q; + } else { + reversed_path = !reversed_path; + q_small = q_large; + q_large = q; + } + } + if (found_path) { + vector path{beginWord}; + backtracking(beginWord, endWord, next_words, path, ladder); + } + return ladder; +} +``` + + + + +```py +# 輔助函式。 +def backtracking(src: str, dst: str, next_words: Dict[str, List[str]], + path: List[str], ladder: List[List[str]]): + if src == dst: + ladder.append(path[:]) + return + if src not in next_words: + return + for w in next_words[src]: + path.append(w) # 修改當前節點狀態 + backtracking(w, dst, next_words, path, ladder) # 遞迴子節點 + path.pop() # 回改當前節點狀態 + +# 主函式。 +def findLadders(beginWord: str, endWord: str, + wordList: List[str]) -> List[List[str]]: + ladder = [] + # 使用雜湊集合儲存字典,方便查找。 + word_dict = set(wordList) + if endWord not in word_dict: + return ladder + word_dict = word_dict.difference(set([beginWord, endWord])) + # 建立兩個queue,從beginWord和endWord同時延展,每次延展最小的。 + # 因為之後的去重操作需要遍歷queue,我們這裡用雜湊表實現它, + # 只要保證是分層次遍歷即可。 + q_small, q_large = set([beginWord]), set([endWord]) + next_words = dict() + reversed_path, found_path = False, False + while len(q_small) > 0: + q = set() + for w in q_small: + for i in range(len(w)): + for j in range(26): + s = w[:i] + chr(ord("a") + j) + w[i + 1:] + if s in q_large: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + found_path = True + if s in word_dict: + if reversed_path: + next_words[s] = next_words.get(s, []) + [w] + else: + next_words[w] = next_words.get(w, []) + [s] + q.add(s) + if found_path: + break + # 環路一定不是最短解,所以這裡需要去重和避免無限循環。 + word_dict = word_dict.difference(q) + # 更新兩個queue,並維持大小關係。 + if len(q) <= len(q_large): + q_small = q + else: + reversed_path = not reversed_path + q_small = q_large + q_large = q + + if found_path: + path = [beginWord] + backtracking(beginWord, endWord, next_words, path, ladder) + return ladder +``` + + + + + +### 複雜度分析 + +- **時間複雜度**: $O(N \times M^2)$,其中 $N$ 是單詞數量,$M$ 是單詞的長度。 + - 每個單詞的鄰居生成需要 $O(M \times 26)$ 次檢查。 + - BFS 最多需要處理 $N$ 個單詞。 + +- **空間複雜度**: $O(N \times M)$,主要來自 `next_words` 字典和 BFS 佇列。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md new file mode 100644 index 00000000..0f42bbf8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/5-5-exercises.md @@ -0,0 +1,432 @@ +--- +sidebar_position: 25 +--- + +# 5.5 練習 + +## 基礎難度 + +### [130. Surrounded Regions](https://leetcode.com/problems/surrounded-regions/) + +從最外側開始填充,然後再考慮內部區域。 + +
+題解 + +#### 問題描述 + +給定一個 `m x n` 的二維矩陣,包含 `'X'` 和 `'O'`,找出所有被 `'X'` 包圍的區域,並將這些區域內的 `'O'` 替換為 `'X'`。被包圍的區域指的是完全被 `'X'` 包圍的 `'O'` 區域(上下左右四個方向)。 + +#### 解題思路 + +1. **關鍵觀察**: + - 位於矩陣邊界上的 `'O'` 以及與邊界相連的 `'O'` 不會被包圍。 + - 需要先將這些邊界上的 `'O'` 以及與其相連的 `'O'` 標記出來。 + +2. **解法設計**: + - 遍歷矩陣的四條邊界,對每個邊界上的 `'O'` 執行深度優先搜尋(DFS)或廣度優先搜尋(BFS),將與邊界相連的 `'O'` 標記為特殊字符(例如 `'T'`)。 + - 遍歷矩陣: + - 將剩餘的 `'O'` 替換為 `'X'`。 + - 將之前標記為 `'T'` 的恢復為 `'O'`。 + +3. **演算法步驟**: + - 使用 DFS 或 BFS 標記所有邊界的 `'O'`。 + - 替換剩餘的內部 `'O'`,恢復被標記的字符。 + +#### Python 範例程式碼 + +```python +class Solution: + def solve(self, board: List[List[str]]) -> None: + if not board or not board[0]: + return + + rows, cols = len(board), len(board[0]) + + def dfs(r, c): + if r < 0 or c < 0 or r >= rows or c >= cols or board[r][c] != 'O': + return + board[r][c] = 'T' # 標記為暫存字符 + # 向四個方向遞迴 + dfs(r + 1, c) + dfs(r - 1, c) + dfs(r, c + 1) + dfs(r, c - 1) + + # 標記邊界上的 'O' + for r in range(rows): + dfs(r, 0) + dfs(r, cols - 1) + for c in range(cols): + dfs(0, c) + dfs(rows - 1, c) + + # 處理矩陣 + for r in range(rows): + for c in range(cols): + if board[r][c] == 'O': + board[r][c] = 'X' # 替換被包圍的 'O' + elif board[r][c] == 'T': + board[r][c] = 'O' # 恢復邊界連通的 'O' +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(m \times n)$,其中 $m$ 和 $n$ 分別是矩陣的行數和列數。DFS 遍歷整個矩陣。 +- **空間複雜度**: $O(m \times n)$,最壞情況下遞迴堆疊深度等於矩陣大小。 + +
+ + +--- + +### [257. Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/) + +輸出二元樹中所有從根節點到葉子節點的路徑。使用回溯法與否有什麼區別? + +
+題解 + +#### 問題描述 + +給定一個二元樹,返回所有從根節點到葉節點的路徑。每條路徑以字符串形式表示,節點之間用 `"->"` 連接。 + +#### 解題思路 + +1. **問題分解**: + - 路徑從根節點開始,延伸至每個葉節點。 + - 使用遞迴遍歷二元樹,逐步構造路徑。 + - 當到達葉節點時,將完整路徑加入結果列表。 + +2. **演算法設計**: + - 使用深度優先搜尋(DFS)從根節點開始遍歷。 + - 每次進入新節點時,將其值加入當前路徑。 + - 若節點為葉節點,將當前路徑轉為字符串並加入結果。 + - 若不是葉節點,繼續對其左右子節點遞迴。 + +3. **特別處理**: + - 如果樹為空,直接返回空列表。 + +#### Python 範例程式碼 + +```python +class Solution: + def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]: + def dfs(node, path, paths): + if not node: + return + path.append(str(node.val)) # 加入當前節點值 + if not node.left and not node.right: # 如果是葉節點 + paths.append("->".join(path)) # 將路徑轉為字符串 + else: + dfs(node.left, path, paths) # 遞迴左子樹 + dfs(node.right, path, paths) # 遞迴右子樹 + path.pop() # 回溯 + + paths = [] + dfs(root, [], paths) + return paths +``` + +#### 複雜度分析 + +- **時間複雜度**: $O(n)$,其中 $n$ 是樹中節點數量。每個節點訪問一次。 +- **空間複雜度**: $O(h)$,其中 $h$ 是樹的高度。遞迴堆疊的最大深度與樹的高度成正比。 + +
+ + +--- + +## 進階難度 + +### [47. Permutations II](https://leetcode.com/problems/permutations-ii/) + +排列問題的進階版本,如何處理重複的元素? + +
+題解 + +#### 問題描述 + +給定一個可能包含重複元素的數字序列 `nums`,返回所有不重複的全排列。 + +#### 解題思路 + +1. **關鍵觀察**: + - 因為輸入數列可能包含重複數字,我們需要確保結果中的排列是唯一的。 + - 使用 `Counter` 來記錄每個數字的剩餘次數,可以在迭代中避免重複。 + +2. **解法設計**: + - 透過回溯法 (Backtracking) 枚舉所有排列: + - 每次選取數字前,檢查其計數是否大於 0。 + - 選取後,將計數減 1,並繼續遞迴。 + - 回溯時恢復該數字的計數,並從當前路徑中移除該數字。 + - 當路徑長度等於輸入數列長度時,將路徑加入結果。 + +--- + +#### Python 範例程式碼 + +```python +from collections import Counter + +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + def btrack(path, counter): + if len(path) == len(nums): # 當路徑長度等於數列長度時,加入結果 + ans.append(path[:]) + return + for x in counter: # 遍歷所有唯一的數字 + if counter[x] > 0: + path.append(x) # 將數字加入路徑 + counter[x] -= 1 # 減少該數字的剩餘次數 + btrack(path, counter) # 遞迴 + path.pop() # 回溯時移除數字 + counter[x] += 1 # 恢復計數 + + ans = [] + btrack([], Counter(nums)) # 初始化計數器並開始回溯 + return ans +``` + +--- + +#### 複雜度分析 + +- **時間複雜度**: $O(n \times n!)$,其中 $n$ 是輸入數字的個數。 + - 總共有 $n!$ 個排列,每個排列的生成過程需要 $O(n)$ 時間。 +- **空間複雜度**: $O(n)$,用於遞迴堆疊和路徑的暫存空間。 + +
+ + + +--- + +### [40. Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) + +組合問題的進階版本,如何處理重複的元素? + +
+題解 + +#### 問題描述 + +給定一個整數數組 `candidates` 和一個目標值 `target`,找出所有不重複的組合,使得組合中的數字總和等於 `target`。 +`candidates` 中的每個數字只能在每個組合中使用一次。 + +--- + +#### 解題思路 + +1. **關鍵觀察**: + - 每個數字只能使用一次,因此需要在遍歷過程中跳過重複的數字。 + - 使用排序來幫助識別相鄰的重複數字,並在回溯過程中跳過它們。 + +2. **解法設計**: + - 先對 `candidates` 排序,方便後續處理重複元素。 + - 使用回溯法 (Backtracking): + - 每次選擇一個數字,將其加入當前路徑,並減少剩餘的目標值。 + - 遞迴處理下一個數字,確保索引只向後移動以避免重複使用。 + - 回溯時將數字移出路徑。 + - 如果當前數字與前一個數字相同且前一個數字未被使用,則跳過當前數字。 + +3. **重複處理**: + - 透過 `if i > start and candidates[i] == candidates[i - 1]` 跳過重複數字。 + +--- + +#### Python 範例程式碼 + +```python +class Solution: + def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]: + def backtrack(start, path, remaining): + if remaining == 0: # 如果目標值達成,加入結果 + ans.append(path[:]) + return + for i in range(start, len(candidates)): + # 跳過重複數字 + if i > start and candidates[i] == candidates[i - 1]: + continue + # 如果當前數字大於剩餘目標值,提前終止 + if candidates[i] > remaining: + break + path.append(candidates[i]) # 選擇當前數字 + backtrack(i + 1, path, remaining - candidates[i]) # 遞迴處理 + path.pop() # 回溯,移除當前數字 + + candidates.sort() # 排序以便處理重複元素 + ans = [] + backtrack(0, [], target) + return ans +``` + +--- + +#### 複雜度分析 + +- **時間複雜度**: $O(2^n)$,其中 $n$ 是 `candidates` 的長度。 + - 雖然排序需要 $O(n \log n)$ 時間,但主要的時間花費在回溯過程中,最壞情況下可能有 $2^n$ 種組合需要檢查。 +- **空間複雜度**: $O(n)$,遞迴堆疊的深度最多為 $n$。 + +
+ + +--- + +### [37. Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) + +非常經典的數獨問題,可以利用回溯法解決。事實上,針對數獨類型的問題,有許多進階的搜索方法和剪枝策略可以提升求解速度,例如啟發式搜索。 + +
+題解 + +#### 問題描述 + +編寫一個函式來解決數獨問題。 +數獨的解法需要滿足以下條件: +1. 每行的數字 `1-9` 必須唯一。 +2. 每列的數字 `1-9` 必須唯一。 +3. 每個 $3 \times 3$ 的小方格內數字 `1-9` 必須唯一。 + +輸入是一個 $9 \times 9$ 的二維列表,其中 `'.'` 表示空格,需用數字填充。 + +--- + +#### 解題思路 + +1. **問題拆解**: + - 使用回溯法 (Backtracking) 試圖填入數字。 + - 對每個空格測試數字 `1-9`,檢查是否符合數獨規則。 + - 如果符合則遞迴嘗試填寫下一格,否則回溯。 + +2. **有效性檢查**: + - 在每次填入數字時,檢查是否滿足數獨的行、列和 $3 \times 3$ 區域規則。 + +3. **優化**: + - 使用遞迴優先填入空格數量最少的位置,以減少無效測試次數。 + +--- + +#### Python 範例程式碼 + +```python +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + def is_valid(r, c, num): + # 檢查列是否有重複 + if num in board[r]: + return False + # 檢查行是否有重複 + if num in (board[i][c] for i in range(9)): + return False + # 檢查 3x3 小方格是否有重複 + box_r, box_c = r // 3 * 3, c // 3 * 3 + for i in range(box_r, box_r + 3): + for j in range(box_c, box_c + 3): + if board[i][j] == num: + return False + return True + + def backtrack(): + for r in range(9): + for c in range(9): + if board[r][c] == '.': # 找到一個空格 + for num in map(str, range(1, 10)): # 試圖填入 '1' 到 '9' + if is_valid(r, c, num): # 檢查是否合法 + board[r][c] = num + if backtrack(): # 遞迴嘗試下一步 + return True + board[r][c] = '.' # 回溯 + return False # 若無法填入任何數字則失敗 + return True # 若所有格子都已填滿,返回成功 + + backtrack() +``` + +--- + +#### 複雜度分析 + +- **時間複雜度**: 最壞情況為 $O(9^{81})$,即最多需要嘗試每個格子可能的數字排列。但實際情況下,由於剪枝和限制,平均會遠小於最壞情況。 +- **空間複雜度**: $O(81)$,遞迴堆疊的深度最多為 81 層。 + +
+ + +--- + +### [310. Minimum Height Trees](https://leetcode.com/problems/minimum-height-trees/) + +如何將這道題轉化為搜索類型的問題?應該使用深度優先搜索還是廣度優先搜索? + +
+題解 + +#### 問題描述 + +給定一個無向圖,表示為 $n$ 個節點的樹,其中每個節點被編號為 `0` 到 `n-1`,樹的邊緣表示為一個列表 `edges`,其中 `edges[i] = [a, b]` 表示節點 `a` 和節點 `b` 之間的邊。 +目標是找到所有樹的**最小高度樹**(Minimum Height Trees, MHT)的根。返回所有可能的根節點。 + +--- + +#### 解題思路 + +1. **關鍵觀察**: + - 樹的「中心節點」可以是 1 或 2 個節點,這些節點構成最小高度樹的根。 + - 使用拓撲排序修剪樹中的葉子節點,直到剩下 1 或 2 個節點為止。 + +2. **解法**: + - 利用 BFS 和鄰接表來實現拓撲排序。 + - 每次移除葉子節點,並更新鄰接節點的度數,將新的葉子節點加入隊列。 + - 當剩餘節點數量小於等於 2 時,返回這些節點。 + +--- + +#### Python 範例程式碼 + +```python +from collections import deque, defaultdict + +class Solution: + def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: + if n == 1: + return [0] + + # 建立鄰接表和度數表 + graph = defaultdict(list) + degree = [0] * n + for a, b in edges: + graph[a].append(b) + graph[b].append(a) + degree[a] += 1 + degree[b] += 1 + + # 初始化葉子節點 + leaves = deque([i for i in range(n) if degree[i] == 1]) + + # 拓撲排序修剪葉子 + remaining_nodes = n + while remaining_nodes > 2: + remaining_nodes -= len(leaves) + for _ in range(len(leaves)): + leaf = leaves.popleft() + for neighbor in graph[leaf]: + degree[neighbor] -= 1 + if degree[neighbor] == 1: + leaves.append(neighbor) + + # 剩下的節點即為樹的中心 + return list(leaves) +``` + +--- + +#### 複雜度分析 + +- **時間複雜度**: $O(n)$,每條邊只被訪問一次。 +- **空間複雜度**: $O(n)$,用於鄰接表和隊列。 + +
\ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json new file mode 100644 index 00000000..5d112130 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "5. 一切皆可搜尋", + "position": 5, + "link": { + "type": "generated-index", + "description": "第 5 章 一切皆可搜尋" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png new file mode 100644 index 00000000..f6ea0755 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/5-searching-algorithms/n-queens.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md new file mode 100644 index 00000000..2768d5e5 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-1-algorithm-explanation.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 26 +--- + +# 6.1 算法解釋 + +這裡我們引用一下維基百科的描述:「`動態規劃`(Dynamic Programming, DP)在尋找有許多`重疊子問題`情況的最優解時非常有效。它將問題重新分解成子問題。為了避免多次解決這些子問題,它們的結果會逐步被計算並保存,從簡單的問題開始,直到整個問題被解決。因此,動態規劃保存遞迴中的結果,從而避免在解決相同問題時浪費時間⋯⋯ 動態規劃只能應用於有`最優子結構`的問題。最優子結構的意思是,局部最優解能夠決定全局最優解(對某些問題來說這個要求不完全滿足,因此有時需要引入一定的近似)。簡單來說,問題能夠分解成子問題來解決。」 + +通俗來說,動態規劃與其他遍歷算法(如深度優先搜索或廣度優先搜索)的最大區別在於,動態規劃`保存子問題的解,避免重複計算`。解決動態規劃問題的關鍵是找到`狀態轉移方程`,通過計算與保存子問題的解來求解最終問題。 + +同時,我們也可以對動態規劃進行`空間壓縮`,以節省空間消耗。這一技巧筆者會在後續題目中介紹。 + +在某些情況下,動態規劃可以視為帶有`狀態記錄`(memoization)的優先搜索。狀態記錄的意思是,如果一個子問題在優先搜索時已經計算過一次,可以將結果保存下來,之後再次遍歷到該子問題時可以直接返回保存的結果。動態規劃是自下而上的,先解決子問題再解決父問題;而帶有狀態記錄的優先搜索是自上而下的,從父問題搜索到子問題,如果重複搜索到同一個子問題則記錄其狀態以防重複計算。如果題目需求的是最終狀態,使用動態規劃會比較方便;如果需要輸出所有的路徑,則使用帶有狀態記錄的優先搜索會更適合。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx new file mode 100644 index 00000000..2d665b15 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-2-basic-dp-1d.mdx @@ -0,0 +1,249 @@ +--- +sidebar_position: 27 +--- + +# 6.2 基本動態規劃:一維 + +## [70. Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) + +### 題目描述 + +給定 $n$ 階台階,每次可以走一步或兩步,求有多少種方法可以走完這些台階。 + +### 輸入輸出範例 + +輸入是一個數字,表示台階的數量;輸出是爬完台階的總方法數。 + +``` +Input: 3 +Output: 3 +``` + +在這個例子中,一共有三種方法可以爬完這三階台階: +1. 每次走一步。 +2. 先走一步,再走兩步。 +3. 先走兩步,再走一步。 + +### 題解 + +這是一道經典的費波那契數列題目。定義一個陣列 `dp`,其中 `dp[i]` 表示到達第 $i$ 階的方法數。由於每次可以走一步或兩步,所以第 $i$ 階可以從第 $(i-1)$ 階或第 $(i-2)$ 階到達。換句話說,到達第 $i$ 階的方法數是到達第 $(i-1)$ 階的方法數加上到達第 $(i-2)$ 階的方法數。因此我們得到了狀態轉移方程:`dp[i] = dp[i-1] + dp[i-2]`。注意初始條件的處理。 + +:::warning + +為了方便處理邊界情況,我們可以在構造 `dp` 陣列時多留一個位置,用於表示初始狀態。本題即額外留了一個第 0 階的初始位置。 + + +::: + + + + +```cpp +int climbStairs(int n) { + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + dp = [1] * (n + 1) + for i in range(2, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + return dp[n] +``` + + + + + +進一步的,我們可以對動態規劃進行空間壓縮。因為 dp[i] 只與 dp[i-1] 和 dp[i-2] 有關,因此可以只用兩個變數來儲存 dp[i-1] 和 dp[i-2],使得原來的 $O(n)$ 空間複雜度優化為 $O(1)$ 複雜度。 + + + + +```cpp +int climbStairs(int n) { + int prev_prev = 1, prev = 1, cur = 1; + for (int i = 2; i <= n; ++i) { + cur = prev_prev + prev; + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def climbStairs(n: int) -> int: + prev_prev = prev = cur = 1 + for _ in range(2, n + 1): + cur = prev_prev + prev + prev_prev = prev + prev = cur + return cur +``` + + + + + + +## [198. House Robber](https://leetcode.com/problems/house-robber/) + +### 題目描述 + +假如你是一个劫匪,并且決定搶劫一條街上的房子,每個房子內的財物數量各不相同。如果你搶了兩棟相鄰的房子,則會觸發警報機關。求在不觸發機關的情況下最多可以搶劫多少錢。 + +### 輸入輸出範例 + +輸入是一個一維陣列,表示每個房子的財物數量;輸出是劫匪可以最多搶劫的財物數量。 + +``` +Input: [2,7,9,3,1] +Output: 12 +``` + +在這個範例中,最多的搶劫方式為搶劫第 1、3、5 個房子。 + +### 題解 + +定義一個陣列 `dp`,其中 `dp[i]` 表示搶劫到第 `i` 個房子時,可以搶劫的最大金額。我們考慮 `dp[i]` 的值,此時可以搶劫的最大金額有兩種可能: + +1. **選擇不搶劫這個房子**:此時累計的金額為 `dp[i-1]`; +2. **選擇搶劫這個房子**:那麼此前累計的最大金額只能是 `dp[i-2]`,因為我們無法搶劫第 `i-1` 個房子,否則會觸發警報。 + +因此,這道題的狀態轉移方程為: + +$$ +dp[i] = \max(dp[i-1], dp[i-2] + \text{nums}[i-1]) +$$ + + + + +```cpp +int rob(vector& nums) { + int n = nums.size(); + vector dp(n + 1, 0); + dp[1] = nums[0]; + for (int i = 2; i <= n; ++i) { + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]); + } + return dp[n]; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + n = len(nums) + dp = [0] * (n + 1) + dp[1] = nums[0] + for i in range(2, n + 1): + dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]) + return dp[n] +``` + + + + + +同樣的,我們可以像題目 70 那樣,對空間進行壓縮。由於 `dp[i]` 只與 `dp[i-1]` 和 `dp[i-2]` 有關,因此我們可以僅使用兩個變數來儲存這兩個值,將原來的 $O(n)$ 空間複雜度優化為 $O(1)$ 空間複雜度。 + + + + +```cpp +int rob(vector& nums) { + int prev_prev = 0, prev = 0, cur = 0; + for (int i = 0; i < nums.size(); ++i) { + cur = max(prev_prev + nums[i], prev); + prev_prev = prev; + prev = cur; + } + return cur; +} +``` + + + + +```py +def rob(nums: List[int]) -> int: + prev_prev = prev = cur = 0 + for i in range(len(nums)): + cur = max(prev_prev + nums[i], prev) + prev_prev = prev + prev = cur + return cur +``` + + + + + +## [413. Arithmetic Slices](https://leetcode.com/problems/arithmetic-slices/) + +### 題目描述 + +給定一個陣列,求這個陣列中連續且等差的子陣列一共有多少個。 + +### 輸入輸出範例 + +輸入是一維陣列,輸出是滿足等差條件的連續子陣列個數。 + +``` +Input: nums = [1,2,3,4] +Output: 3 +``` + +在這個範例中,等差數列有 [1,2,3]、[2,3,4] 和 [1,2,3,4]。 + +### 題解 + +因為要求是等差數列,可以很自然地想到子陣列必定滿足 `num[i] - num[i-1] = num[i-1] - num[i-2]`。這裡我們對於 `dp` 陣列的定義是以 `i` 結尾,且滿足該條件的子陣列數量。因為等差子陣列可以在任意一個位置終結,所以我們需要對 `dp` 陣列求和以進行子陣列統計。 + + + + +```cpp +int numberOfArithmeticSlices(vector& nums) { + int n = nums.size(); + vector dp(n, 0); + for (int i = 2; i < n; ++i) { + if (nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]) { + dp[i] = dp[i - 1] + 1; + } + } + return accumulate(dp.begin(), dp.end(), 0); +} +``` + + + + +```py +def numberOfArithmeticSlices(nums: List[int]) -> int: + n = len(nums) + dp = [0] * n + for i in range(2, n): + if nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]: + dp[i] = dp[i - 1] + 1 + return sum(dp) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx new file mode 100644 index 00000000..beefab02 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-3-basic-dp-2d.mdx @@ -0,0 +1,306 @@ +--- +sidebar_position: 28 +--- + +# 6.3 基本動態規劃:二維 + +## [64. Minimum Path Sum](https://leetcode.com/problems/minimum-path-sum/) + +### 題目描述 + +給定一個 $m × n$ 大小的非負整數矩陣,求從左上角開始到右下角結束的、經過的數字的和最小的路徑。每次只能向右或者向下移動。 + +### 輸入輸出範例 + +輸入是二維陣列,輸出是最優路徑的數字和。 + +``` +Input: +[[1,3,1], + [1,5,1], + [4,2,1]] +Output: 7 +``` + +在這個範例中,最短路徑為 1->3->1->1->1。 + +### 題解 + +我們可以定義一個同樣是二維的 `dp` 陣列,其中 `dp[i][j]` 表示從左上角開始到 `(i, j)` 位置的最優路徑的數字和。因為每次只能向下或者向右移動,我們可以很直觀地得到狀態轉移方程 `dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])`,其中 `grid` 表示原陣列。 + +:::warning + +在 Python 中,多維陣列的初始化比較特殊,直接初始化為 `[[val] * n] * m` 會導致只是創造了 `m` 個 `[[val] * n]` 的引用。正確的初始化方法為 `[[val for _ in range(n)] for _ in range(m)]`。 + +::: + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector> dp(m, vector(n, 0)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[i][j] = grid[i][j]; + } else if (i == 0) { + dp[i][j] = grid[i][j] + dp[i][j - 1]; + } else if (j == 0) { + dp[i][j] = grid[i][j] + dp[i - 1][j]; + } else { + dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m - 1][n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [[0 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[i][j] = grid[i][j] + elif i == 0: + dp[i][j] = grid[i][j] + dp[i][j - 1] + elif j == 0: + dp[i][j] = grid[i][j] + dp[i - 1][j] + else: + dp[i][j] = grid[i][j] + min(dp[i][j - 1], dp[i - 1][j]) + return dp[m - 1][n - 1] +``` + + + + + +因為 dp 矩陣的每一個值只和左邊和上面的值相關,我們可以使用空間壓縮將 dp 陣列壓縮為一維。對於第 i 行,在遍歷到第 j 列的時候,因為第 j-1 列已經更新過了,所以 dp[j-1] 代表 dp[i][j-1] 的值;而 dp[j] 待更新,當前儲存的值是在第 i-1 行的時候計算的,所以代表 dp[i-1][j] 的值。 + +:::warning + +如果不是很熟悉空間壓縮技巧,建議您優先嘗試寫出非空間壓縮的解法,若時間充裕且能力允許再進行空間壓縮。 + +::: + + + + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector dp(n, 0); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (i == 0 && j == 0) { + dp[j] = grid[i][j]; + } else if (i == 0) { + dp[j] = grid[i][j] + dp[j - 1]; + } else if (j == 0) { + dp[j] = grid[i][j] + dp[j]; + } else { + dp[j] = grid[i][j] + min(dp[j], dp[j - 1]); + } + } + } + return dp[n - 1]; +} +``` + + + + +```py +def minPathSum(grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + dp = [0 for _ in range(n)] + for i in range(m): + for j in range(n): + if i == j == 0: + dp[j] = grid[i][j] + elif i == 0: + dp[j] = grid[i][j] + dp[j - 1] + elif j == 0: + dp[j] = grid[i][j] + dp[j] + else: + dp[j] = grid[i][j] + min(dp[j - 1], dp[j]) + return dp[n - 1] +``` + + + + + + +## [542. 01 Matrix](https://leetcode.com/problems/01-matrix/) + +### 題目描述 + +給定一個由 0 和 1 組成的二維矩陣,求每個位置到最近的 0 的距離。 + +### 輸入輸出範例 + +輸入是一個二維 0-1 陣列,輸出是一個同樣大小的非負整數陣列,表示每個位置到最近的 0 的距離。 + +``` +Input: +[[0,0,0], + [0,1,0], + [1,1,1]] + +Output: +[[0,0,0], + [0,1,0], + [1,2,1]] +``` + +### 題解 + +一般來說,因為這道題涉及到四個方向上的最近搜尋,所以很多人的第一反應可能會是廣度優先搜尋。但是對於一個大小 $O(mn)$ 的二維陣列,對每個位置進行四向搜尋,最壞情況的時間複雜度(即全是 1)會達到驚人的 $O(m^2n^2)$。 + +一種方法是使用一個二維布林值陣列進行記憶化,使得廣度優先搜尋不會重複遍歷相同位置;另一種更簡單的方法是,我們從左上到右下進行一次動態搜尋,再從右下到左上進行一次動態搜尋。兩次動態搜尋即可完成四個方向上的查找。 + + + + + +```cpp +vector> updateMatrix(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + vector> dp(m, vector(n, numeric_limits::max() - 1)); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (matrix[i][j] != 0) { + if (i > 0) { + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + } + if (j > 0) { + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } else { + dp[i][j] = 0; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (matrix[i][j] != 0) { + if (i < m - 1) { + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1); + } + if (j < n - 1) { + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1); + } + } + } + } + return dp; +} +``` + + + + +```py +def updateMatrix(matrix: List[List[int]]) -> List[List[int]]: + m, n = len(matrix), len(matrix[0]) + dp = [[sys.maxsize - 1 for _ in range(n)] for _ in range(m)] + for i in range(m): + for j in range(n): + if matrix[i][j] != 0: + if i > 0: + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1) + if j > 0: + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1) + else: + dp[i][j] = 0 + for i in range(m - 1, -1, -1): # m-1 to 0, reversed + for j in range(n - 1, -1, -1): # n-1 to 0, reversed + if matrix[i][j] != 0: + if i < m - 1: + dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1) + if j < n - 1: + dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1) + return dp +``` + + + + + +## [221. Maximal Square](https://leetcode.com/problems/maximal-square/) + +### 題目描述 + +給定一個二維的 0-1 矩陣,求全由 1 構成的最大正方形面積。 + +### 輸入輸出範例 + +輸入是一個二維 0-1 陣列,輸出是最大正方形面積。 + +``` +Input: +[["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"]] +Output: 4 +``` + +### 題解 + +對於在矩陣內搜尋正方形或長方形的題型,一種常見的做法是定義一個二維 dp 陣列,其中 dp[i][j] 表示滿足題目條件的、以 (i, j) 為右下角的正方形或者長方形的屬性。對於本題,則表示以 (i, j) 為右下角的全由 1 構成的最大正方形邊長。如果當前位置是 0,那麼 dp[i][j] 即為 0;如果當前位置是 1,我們假設 dp[i][j] = k,其充分條件為 dp[i-1][j-1]、dp[i][j-1] 和 dp[i-1][j] 的值必須都不小於 k − 1,否則 (i, j) 位置不可以構成一個面積為 $k^2$ 的正方形。同理,如果這三個值中的最小值為 k − 1,則 (i, j) 位置一定且最大可以構成一個面積為 $k^2$ 的正方形。 + + +
+ + ![](6.1.png) + +
圖 6.1: 題目 221 - 左邊為一個 0-1 矩陣,右邊為其對應的 dp 矩陣,我們可以發現最大的正方形邊長為 3
+
+ + + + +```cpp +int maximalSquare(vector>& matrix) { + int m = matrix.size(), n = matrix[0].size(); + int max_side = 0; + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (matrix[i - 1][j - 1] == ’1’) { + dp[i][j] = + min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1; + } + max_side = max(max_side, dp[i][j]); + } + } + return max_side * max_side; +} +``` + + + + +```py +def maximalSquare(matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1 + return max(max(row) for row in dp) ** 2 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx new file mode 100644 index 00000000..8f95ccaf --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-4-partition-problems.mdx @@ -0,0 +1,347 @@ +--- +sidebar_position: 29 +--- + +# 6.4 分割類型題 + +## [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) + +### 題目描述 + +給定一個正整數,求其最少可以由幾個完全平方數相加構成。 + +### 輸入輸出範例 + +輸入是給定的正整數,輸出也是一個正整數,表示輸入的數字最少可以由幾個完全平方數相加構成。 + +``` +Input: n = 13 +Output: 2 +``` + +在這個樣例中,13 的最少構成方法為 4 + 9。 + +### 題解 + +對於分割類型題,動態規劃的狀態轉移方程通常並不依賴相鄰的位置,而是依賴於滿足分割條件的位置。我們定義一個一維矩陣 dp,其中 dp[i] 表示數字 i 最少可以由幾個完全平方數相加構成。在本題中,位置 i 只依賴 $i - j^2$ 的位置,如 i - 1、i - 4、i - 9 等等,才能滿足完全平方分割的條件。因此 dp[i] 可以取的最小值即為 1 + min(dp[i-1], dp[i-4], dp[i-9] · · · )。注意邊界條件的處理。 + + + + + +```cpp +int numSquares(int n) { + vector dp(n + 1, numeric_limits::max()); + dp[0] = 0; + for (int i = 1; i <= n; ++i) { + for (int j = 1; j * j <= i; ++j) { + dp[i] = min(dp[i], dp[i - j * j] + 1); + } + } + return dp[n]; +} +``` + + + + +```py +def numSquares(n: int) -> int: + dp = [0] + [sys.maxsize] * n + for i in range(1, n + 1): + for j in range(1, int(floor(sqrt(i))) + 1): + dp[i] = min(dp[i], dp[i - j * j] + 1) + return dp[n] +``` + + + + + +## [91. Decode Ways](https://leetcode.com/problems/decode-ways/) + +### 題目描述 + +已知字母 A-Z 可以表示成數字 1-26。給定一個數字串,求有多少種不同的字符串等價於這個數字串。 + +### 輸入輸出範例 + +輸入是一個由數字組成的字符串,輸出是滿足條件的解碼方式總數。 + +``` +Input: "226" +Output: 3 +``` + +在這個範例中,有三種解碼方式:BZ(2 26)、VF(22 6) 或 BBF(2 2 6)。 + +### 題解 + +這是一道很經典的動態規劃題,難度不大但十分考驗耐心。這是因為只有 1-26 可以表示字母,因此對於一些特殊情況,例如數字 0 或相鄰兩數字大於 26 時,需要有不同的狀態轉移方程,詳見如下程式碼。 + + + + +```cpp +int numDecodings(string s) { + int n = s.length(); + int prev = s[0] - '0'; + if (prev == 0) { + return 0; + } + if (n == 1) { + return 1; + } + vector dp(n + 1, 1); + for (int i = 2; i <= n; ++i) { + int cur = s[i - 1] - '0'; + if ((prev == 0 || prev > 2) && cur == 0) { + // 00, 30, 40, ..., 90 為非法組合。 + return 0; + } + if ((prev < 2 && prev > 0) || (prev == 2 && cur <= 6)) { + // 10, 11, ..., 25, 26。 + if (cur == 0) { + // 10, 20,只能解碼為兩位數。 + dp[i] = dp[i - 2]; + } else { + // 可解碼為單位數,也可解碼為兩位數。 + dp[i] = dp[i - 2] + dp[i - 1]; + } + } else { + // 合法但只能解碼為單位數。 + dp[i] = dp[i - 1]; + } + prev = cur; + } + return dp[n]; +} +``` + + + + +```py +def numDecodings(s: str) -> int: + n = len(s) + prev = ord(s[0]) - ord("0") + if prev == 0: + return 0 + if n == 1: + return 1 + dp = [1] * (n + 1) + for i in range(2, n + 1): + cur = ord(s[i - 1]) - ord("0") + if (prev == 0 or prev > 2) and cur == 0: + # 00, 30, 40, ..., 90 為非法組合。 + return 0 + if 0 < prev < 2 or (prev == 2 and cur <= 6): + # 10, 11, ..., 25, 26。 + if cur == 0: + # 10, 20,只能解碼為兩位數。 + dp[i] = dp[i - 2] + else: + # 可解碼為單位數,也可解碼為兩位數。 + dp[i] = dp[i - 2] + dp[i - 1] + else: + # 合法但只能解碼為單位數。 + dp[i] = dp[i - 1] + prev = cur + return dp[n] +``` + + + + + +## [139. Word Break](https://leetcode.com/problems/word-break/) + +### 題目描述 + +給定一個字串和一個字串集合,求是否存在一種分割方式,使得原字串分割後的子字串都可以在集合內找到。 + +### 輸入輸出範例 + +``` +Input: s = "applepenapple", wordDict = ["apple", "pen"] +Output: true +``` + +在這個範例中,字串可以被分割為 [“apple”,“pen”,“apple”]。 + +### 題解 + +類似於完全平方數分割問題,這道題的分割條件由集合內的字串決定,因此在考慮每個分割位置時,需要遍歷字串集合,以確定當前位置是否可以成功分割。注意對於位置 0,需要初始化值為真。 + + + + +```cpp +bool wordBreak(string s, vector& wordDict) { + int n = s.length(); + vector dp(n + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (const string& word : wordDict) { + int m = word.length(); + if (i >= m && s.substr(i - m, m) == word) { + dp[i] = dp[i - m]; + } + // 提前剪枝,略微加速運算。 + // 如果不剪枝,上一行代碼需要變更為 dp[i] = dp[i] || dp[i - m]; + if (dp[i]) { + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def wordBreak(s: str, wordDict: List[str]) -> bool: + n = len(s) + dp = [True] + [False] * n + for i in range(1, n + 1): + for word in wordDict: + m = len(word) + if i >= m and s[i - m : i] == word: + dp[i] = dp[i - m] + # 提前剪枝,略微加速運算。 + # 如果不剪枝,上一行代碼需要變更為 dp[i] = dp[i] or dp[i-m] + if dp[i]: + break + return dp[n] +``` + + + + + +## [1105. Filling Bookcase Shelves](https://leetcode.com/problems/filling-bookcase-shelves/) + +### 題目描述 + +給定一個陣列,每個元素代表一本書的厚度和高度。問對於一個固定寬度的書架,如果按照陣列中書的順序從左到右、從上到下擺放,最小總高度是多少。 + +### 輸入輸出範例 + +``` +Input: books = [[1,1],[2,3],[2,3],[1,1],[1,1],[1,1],[1,2]], shelfWidth = 4 +Output: 6 +``` + + +
+ + ![](https://assets.leetcode.com/uploads/2019/06/24/shelves.png) + +
圖 6.2: 書架擺放問題 - 範例圖解
+
+ +### 題解 + +令 dp[i] 表示放置第 i 本書時的最小總高度,則 dp[i] 可以是在第 i-1 本書下面重新放一排,也可以是在滿足不超過前一排寬度的情況下放在前一排。 + + + + +```cpp +int minHeightShelves(vector>& books, int shelfWidth) { + int n = books.size(); + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) { + int w = books[i - 1][0], h = books[i - 1][1]; + dp[i] = dp[i - 1] + h; + for (int j = i - 1; j > 0; --j) { + int prev_w = books[j - 1][0], prev_h = books[j - 1][1]; + w += prev_w; + if (w > shelfWidth) { + break; + } + h = max(h, prev_h); + dp[i] = min(dp[i], dp[j - 1] + h); + } + } + return dp[n]; +} +``` + + + + +```py +def minHeightShelves(books: List[List[int]], shelfWidth: int) -> int: + n = len(books) + dp = [0] * (n + 1) + for i, (w, h) in enumerate(books, 1): + dp[i] = dp[i - 1] + h + for j in range(i - 1, 0, -1): + prev_w, prev_h = books[j - 1] + w += prev_w + if w > shelfWidth: + break + h = max(h, prev_h) + dp[i] = min(dp[i], dp[j - 1] + h) + return dp[n] +``` + + + + + +## [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) + +### 題目描述 + +給定一個不重複數字的陣列和一個目標數,求加起來等於目標數的所有排列的總數量。(雖然這道題叫做 Combination Sum,但不同順序的組合會被當作不同答案,因此本質上是排列。) + +### 輸入輸出範例 + +``` +Input: nums = [1,2,3], target = 4 +Output: 7 +``` + +七種不同的排列為 (1, 1, 1, 1)、(1, 1, 2)、(1, 2, 1)、(1, 3)、(2, 1, 1)、(2, 2) 和 (3, 1)。 + + +### 題解 + +令 dp[i] 表示加起來等於 i 時,滿足條件的排列數量。在內循環中我們可以直接對所有合法數字進行取用。這裡注意,在 C++ 解法中,因為求和時很容易超過 `int` 的上界,我們用 `double` 儲存 dp 陣列。 + + + + +```cpp +int combinationSum4(vector& nums, int target) { + vector dp(target + 1, 0); + dp[0] = 1; + for (int i = 1; i <= target; ++i) { + for (int num : nums) { + if (num <= i) { + dp[i] += dp[i - num]; + } + } + } + return dp[target]; +} +``` + + + + +```py +def combinationSum4(nums: List[int], target: int) -> int: + dp = [1] + [0] * target + for i in range(1, target + 1): + dp[i] = sum(dp[i - num] for num in nums if i >= num) + return dp[target] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx new file mode 100644 index 00000000..6acdb1c0 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-5-subsequence-problems.mdx @@ -0,0 +1,189 @@ +--- +sidebar_position: 30 +--- + +# 6.5 子序列問題 + +## [300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) + +### 題目描述 + +給定一個未排序的整數陣列,求最長的遞增子序列。 + +:::warning + +按照 LeetCode 的慣例,子序列(subsequence)不必連續,而子陣列(subarray)或子字串(substring)必須連續。 + +::: + +### 輸入輸出範例 + +輸入是一個一維陣列,輸出是一個正整數,表示最長遞增子序列的長度。 + +``` +Input: [10,9,2,5,3,7,101,4] +Output: 4 +``` + +在這個範例中,最長遞增子序列之一是 [2,3,7,101]。 + +### 題解 + +對於子序列問題,第一種動態規劃方法是,定義一個 dp 陣列,其中 dp[i] 表示以 i 結尾的子序列的屬性。在處理好每個位置後,統計一遍各個位置的結果即可得到題目要求的結果。 + +在本題中,dp[i] 可以表示以 i 結尾的、最長子序列長度。對於每一個位置 i,如果其之前的某個位置 j 所對應的數字小於位置 i 所對應的數字,則我們可以獲得一個以 i 結尾的、長度為 dp[j] + 1 的子序列。為了遍歷所有情況,我們需要 i 和 j 進行兩層循環,其時間複雜度為 $O(n^2)$。 + + + + +```cpp +int lengthOfLIS(vector& nums) { + int max_len = 0, n = nums.size(); + vector dp(n, 1); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + if (nums[i] > nums[j]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + max_len = max(max_len, dp[i]); + } + return max_len; +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + n = len(nums) + dp = [1] * n + for i in range(n): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[i], dp[j] + 1) + return max(dp) +``` + + + + + +本題還可以使用二分搜尋將時間複雜度降低為 $O(n \log n)$。我們定義一個 dp 陣列,其中 dp[k] 儲存長度為 k+1 的最長遞增子序列的最後一個數字。我們遍歷每一個位置 i,如果其對應的數字大於 dp 陣列中所有數字的值,那麼我們把它放在 dp 陣列尾部,表示最長遞增子序列長度加 1;如果我們發現這個數字在 dp 陣列中比數字 a 大、比數字 b 小,則我們將 b 更新為此數字,使得之後構成遞增序列的可能性增大。以這種方式維護的 dp 陣列永遠是遞增的,因此可以用二分搜尋加速搜尋。 + +以範例為例,對於陣列 [10,9,2,5,3,7,101,4],我們每輪的更新搜尋情況為: + +``` +num dp +10 [10] +9 [9] +2 [2] +5 [2,5] +3 [2,3] +7 [2,3,7] +101 [2,3,7,101] +4 [2,3,4,101] +``` + +最終我們知道最長遞增子序列的長度是 4。注意 dp 陣列最終的形式並不一定是合法的排列形式,如 [2,3,4,101] 並不是子序列;但之前覆蓋掉的 [2,3,7,101] 是最優解之一。 + +類似的,對於其他題目,如果狀態轉移方程的結果遞增或遞減,且需要進行插入或搜尋操作,我們也可以使用二分法進行加速。 + + + + +```cpp +int lengthOfLIS(vector& nums) { + vector dp{nums[0]}; + for (int num : nums) { + if (dp.back() < num) { + dp.push_back(num); + } else { + *lower_bound(dp.begin(), dp.end(), num) = num; + } + } + return dp.size(); +} +``` + + + + +```py +def lengthOfLIS(nums: List[int]) -> int: + dp = [nums[0]] + for num in nums: + if dp[-1] < num: + dp.append(num) + else: + dp[bisect.bisect_left(dp, num, 0, len(dp))] = num + return len(dp) +``` + + + + + +## [1143. Longest Commom Subsequence](https://leetcode.com/problems/longest-common-subsequence/) + +### 題目描述 + +給定兩個字串,求它們最長的公共子序列長度。 + +### 輸入輸出範例 + +輸入是兩個字串,輸出是一個整數,表示它們滿足題目條件的長度。 + +``` +Input: text1 = "abcde", text2 = "ace" +Output: 3 +``` + +在這個範例中,最長公共子序列是「ace」。 + +### 題解 + +對於子序列問題,第二種動態規劃方法是,定義一個 dp 陣列,其中 dp[i] 表示到位置 i 為止的子序列的性質,並不必須以 i 結尾。這樣 dp 陣列的最後一位結果即為題目所求,不需要再對每個位置進行統計。 + +在本題中,我們可以建立一個二維陣列 dp,其中 dp[i][j] 表示到第一個字串位置 i 為止、到第二個字串位置 j 為止、最長的公共子序列長度。這樣一來我們就可以很方便地分情況討論這兩個位置對應的字母相同與不同的情況了。 + + + + +```cpp +int longestCommonSubsequence(string text1, string text2) { + int m = text1.length(), n = text2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (text1[i - 1] == text2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def longestCommonSubsequence(text1: str, text2: str) -> int: + m, n = len(text1), len(text2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if text1[i - 1] == text2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + return dp[m][n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx new file mode 100644 index 00000000..ec02f125 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-6-knapsack-problem.mdx @@ -0,0 +1,423 @@ +--- +sidebar_position: 31 +--- + +# 6.6 背包問題 + +`背包問題(knapsack problem)` 是一種組合優化的 NP 完全問題:有 n 個物品和載重為 w 的背包,每個物品都有自己的重量 weight 和價值 value,求拿哪些物品可以使得背包所裝下物品的總價值最大。如果限定每種物品只能選擇 0 個或 1 個,則問題稱為 `0-1 背包問題(0-1 knapsack)`;如果不限定每種物品的數量,則問題稱為 `無界背包問題或完全背包問題(unbounded knapsack)`。 + +我們可以用動態規劃來解決背包問題。以 0-1 背包問題為例。我們可以定義一個二維陣列 dp 儲存最大價值,其中 dp[i][j] 表示前 i 件物品重量不超過 j 的情況下能達到的最大價值。在我們遍歷到第 i 件物品時,在當前背包總載重為 j 的情況下,如果我們不將物品 i 放入背包,那麼 dp[i][j] = dp[i-1][j],即前 i 個物品的最大價值等於只取前 i-1 個物品時的最大價值;如果我們將物品 i 放入背包,假設第 i 件物品重量為 weight,價值為 value,那麼我們得到 dp[i][j] = dp[i-1][j-weight] + value。我們只需在遍歷過程中對這兩種情況取最大值即可,總時間複雜度和空間複雜度都為 $O(nw)$。 + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +
+ + ![](6.3.png) + +
圖 6.3: 0-1 背包問題 - 狀態轉移矩陣範例
+
+ +我們可以進一步對 0-1 背包進行空間優化,將空間複雜度降低為 $O(w)$。如圖所示,假設我們目前考慮物品 $i = 2$,且其重量為 $weight = 2$,價值為 $value = 3$;對於背包載重 $j$,我們可以得到 $dp[2][j] = max(dp[1][j], dp[1][j-2] + 3)$。這裡可以發現我們永遠只依賴於上一排 $i = 1$ 的資訊,之前算過的其他物品都不需要再使用。因此我們可以去掉 $dp$ 矩陣的第一個維度,在考慮物品 $i$ 時變成 $dp[j] = max(dp[j], dp[j-weight] + value)$。這裡要注意我們在遍歷每一行的時候必須 **逆向遍歷**,這樣才能夠調用上一行物品 $i-1$ 時 $dp[j-weight]$ 的值;若按照從左往右的順序進行正向遍歷,則 $dp[j-weight]$ 的值在遍歷到 $j$ 之前就已經被更新成物品 $i$ 的值了。 + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = w; j >= weight; --j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(w, weight - 1, -1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +在完全背包問題中,一個物品可以拿多次。如圖上半部分所示,假設我們遍歷到物品 $i = 2$,且其重量為 $weight = 2$,價值為 $value = 3$;對於背包載重 $j = 5$,最多只能裝下 2 個該物品。那麼我們的狀態轉移方程就變成了 $dp[2][5] = max(dp[1][5], dp[1][3] + 3, dp[1][1] + 6)$。如果採用這種方法,假設背包載重無窮大而物品的重量無窮小,我們這裡的比較次數也會趨近於無窮大,遠超 $O(nw)$ 的時間複雜度。 + +
+ + ![](6.4.png) + +
圖 6.4: 完全背包問題 - 狀態轉移矩陣範例
+
+ +怎麼解決這個問題呢?我們發現在 $dp[2][3]$ 的時候我們其實已經考慮了 $dp[1][3]$ 和 $dp[2][1]$ 的情況,而在 $dp[2][1]$ 時也已經考慮了 $dp[1][1]$ 的情況。因此,如圖下半部分所示,對於拿多個物品的情況,我們只需考慮 $dp[2][3]$ 即可,即 $dp[2][5] = max(dp[1][5], dp[2][3] + 3)$。這樣,我們就得到了完全背包問題的狀態轉移方程:$dp[i][j] = max(dp[i-1][j], dp[i][j-w] + v)$,其與 0-1 背包問題的差別僅僅是把狀態轉移方程中的第二個 $i-1$ 變成了 $i$。 + + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector> dp(n + 1, vector(w + 1, 0)); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = 1; j <= w; ++j) { + if (j >= weight) { + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value); + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[n][w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [[0 for _ in range(w + 1)] for _ in range(n + 1)] + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(1, w + 1): + if j >= weight: + dp[i][j] = max(dp[i - 1][j], dp[i][j - weight] + value) + else: + dp[i][j] = dp[i - 1][j] + return dp[n][w] +``` + + + + + +同樣的,我們也可以利用空間壓縮將時間複雜度降低為 $O(w)$。這裡要注意我們在遍歷每一行的時候必須`正向遍歷`,因為我們需要利用當前物品在第 $j-weight$ 列的信息。 + + + + +```cpp +int knapsack(vector weights, vector values, int n, int w) { + vector dp(w + 1, 0); + for (int i = 1; i <= n; ++i) { + int weight = weights[i - 1], value = values[i - 1]; + for (int j = weight; j <= w; ++j) { + dp[j] = max(dp[j], dp[j - weight] + value); + } + } + return dp[w]; +} +``` + + + + +```py +def knapsack(weights: List[int], values: List[int], n: int, w: int) -> int: + dp = [0] * (w + 1) + for i in range(1, n + 1): + weight, value = weights[i - 1], values[i - 1] + for j in range(weight, w + 1): + dp[j] = max(dp[j], [j - weight] + value) + return dp[w] +``` + + + + + +:::warning + +壓縮空間時到底需要`正向`還是`逆向`遍歷呢?物品和重量哪個放在外層,哪個放在內層呢?這取決於狀態轉移方程的依賴關係。在思考空間壓縮前,不妨將狀態轉移矩陣畫出來,方便思考如何進行空間壓縮,以及壓縮哪個維度更省空間。 + +::: + +## [416. Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/) + +### 題目描述 + +給定一個正整數陣列,求是否可以把這個陣列分成和相等的兩部分。 + +### 輸入輸出範例 + +輸入是一個一維正整數陣列,輸出是一個布林值,表示是否可以滿足題目要求。 + +``` +Input: [1,5,11,5] +Output: true +``` + +在這個範例中,滿足條件的分割方法是 [1,5,5] 和 [11]。 + +### 題解 + +本題等價於 0-1 背包問題,設所有數字和為 sum,我們的目標是選取一部分物品,使得它們的總和為 sum/2。這道題不需要考慮價值,因此我們只需要通過一個布林值矩陣來表示狀態轉移矩陣。注意邊界條件的處理。 + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector> dp(n + 1, vector(target + 1, false)); + dp[0][0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = 0; j <= target; ++j) { + if (j < nums[i - 1]) { + dp[i][j] = dp[i - 1][j]; + } else { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; + } + } + } + return dp[n][target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [[False for _ in range(target + 1)] for _ in range(n + 1)] + dp[0][0] = True + for i in range(1, n + 1): + for j in range(target + 1): + if j < nums[i - 1]: + dp[i][j] = dp[i - 1][j] + else: + dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]] + return dp[n][target] +``` + + + + + +同樣的,我們也可以對本題進行空間壓縮。注意對數字和的遍歷需要逆向。 + + + + +```cpp +bool canPartition(vector &nums) { + int nums_sum = accumulate(nums.begin(), nums.end(), 0); + if (nums_sum % 2 != 0) { + return false; + } + int target = nums_sum / 2, n = nums.size(); + vector dp(target + 1, false); + dp[0] = true; + for (int i = 1; i <= n; ++i) { + for (int j = target; j >= nums[i - 1]; --j) { + dp[j] = dp[j] || dp[j - nums[i - 1]]; + } + } + return dp[target]; +} +``` + + + + +```py +def canPartition(nums: List[int]) -> bool: + nums_sum = sum(nums) + if nums_sum % 2 != 0: + return False + target, n = nums_sum // 2, len(nums) + dp = [True] + [False] * target + for i in range(1, n + 1): + for j in range(target, nums[i - 1] - 1, -1): + dp[j] = dp[j] or dp[j - nums[i - 1]] + return dp[target] +``` + + + + + +## [474. Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes/) + +### 題目描述 + +給定 $m$ 個數字 0 和 $n$ 個數字 1,以及一些由 0-1 構成的字串,求利用這些數字最多可以構成多少個給定的字串,字串只可以構成一次。 + +### 輸入輸出範例 + +輸入兩個整數 $m$ 和 $n$,表示 0 和 1 的數量,以及一維字串陣列,表示待構成的字串; +輸出是一個整數,表示最多可以生成的字串個數。 + +``` +Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3 +Output: 4 +``` + +在這個範例中,我們可以用 5 個 0 和 3 個 1 構成 [“10”, “0001”, “1”, “0”]。 + +### 題解 + +這是一個多維費用的 0-1 背包問題,有兩個背包大小,分別是 0 的數量和 1 的數量。以下直接展示將三維空間壓縮到二維後的寫法。 + + + + +```cpp +int findMaxForm(vector& strs, int m, int n) { + vector> dp(m + 1, vector(n + 1, 0)); + for (const string& s : strs) { + int zeros = 0, ones = 0; + for (char c : s) { + if (c == ’0’) { + ++zeros; + } else { + ++ones; + } + } + for (int i = m; i >= zeros; --i) { + for (int j = n; j >= ones; --j) { + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def findMaxForm(strs: List[str], m: int, n: int) -> int: + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for s in strs: + zeros = len(list(filter(lambda c: c == "0", s))) + ones = len(s) - zeros + for i in range(m, zeros - 1, -1): + for j in range(n, ones - 1, -1): + dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) + return dp[m][n] +``` + + + + + +## [322. Coin Change](https://leetcode.com/problems/coin-change/) + +### 題目描述 + +給定一些硬幣的面額,求最少可以用多少顆硬幣組成給定的金額。 + +### 輸入輸出範例 + +輸入一個一維整數陣列,表示硬幣的面額;以及一個整數,表示給定的金額。輸出一個整數,表示滿足條件的最少的硬幣數量。若不存在解,則返回 -1。 + +``` +Input: coins = [1, 2, 5], amount = 11 +Output: 3 +``` + +在這個範例中,最少的組合方法是 11 = 5 + 5 + 1。 + +### 題解 + +因為每個硬幣可以用無限多次,這道題本質上是完全背包。我們直接展示二維空間壓縮為一維的寫法。 + +這裡注意,我們把 `dp` 陣列初始化為 `amount + 1` 而不是 `-1` 的原因是,在動態規劃過程中有求最小值的操作,如果初始化成 `-1` 則會導致結果始終為 `-1`。至於為什麼取這個值,是因為 `i` 最大可以取 `amount`,而最多的組成方式是只用 1 元硬幣,因此 `amount + 1` 一定大於所有可能的組合方式,取最小值時一定不會是它。在動態規劃完成後,若結果仍然是此值,則說明不存在滿足條件的組合方法,返回 `-1`。 + + + + +```cpp +int coinChange(vector& coins, int amount) { + vector dp(amount + 1, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; ++i) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] != amount + 1 ? dp[amount] : -1; +} +``` + + + + +```py +def coinChange(coins: List[int], amount: int) -> int: + dp = [0] + [amount + 1] * amount + for i in range(1, amount + 1): + for coin in coins: + if i >= coin: + dp[i] = min(dp[i], dp[i - coin] + 1) + return dp[amount] if dp[amount] != amount + 1 else -1 +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx new file mode 100644 index 00000000..2889a682 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-7-string-editing.mdx @@ -0,0 +1,138 @@ +--- +sidebar_position: 32 +--- + +# 6.7 字符串編輯 + +## [72. Edit Distance](https://leetcode.com/problems/edit-distance/) + +### 題目描述 + +給定兩個字符串,已知你可以刪除、替換和插入任意字符串的任意字符,求最少編輯幾步可以將兩個字符串變成相同。 + +### 輸入輸出範例 + +輸入是兩個字符串,輸出是一個整數,表示最少的步驟。 + +``` +Input: word1 = "horse", word2 = "ros" +Output: 3 +``` + +在這個範例中,一種最優編輯方法是 horse -> rorse -> rose -> ros。 + +### 題解 + +類似於題目 1143,我們使用一個二維陣列 `dp[i][j]`,表示將第一個字符串到位置 `i` 為止,和第二個字符串到位置 `j` 為止,最多需要幾步編輯。 + +- 當第 `i` 位和第 `j` 位對應的字符相同時,`dp[i][j] = dp[i-1][j-1]`; +- 當兩者對應的字符不相同時: + - 修改的消耗為 `dp[i-1][j-1] + 1`; + - 插入 `i` 位置/刪除 `j` 位置的消耗為 `dp[i][j-1] + 1`; + - 插入 `j` 位置/刪除 `i` 位置的消耗為 `dp[i-1][j] + 1`。 + + + + +```cpp +int minDistance(string word1, string word2) { + int m = word1.length(), n = word2.length(); + vector> dp(m + 1, vector(n + 1, 0)); + for (int i = 0; i <= m; ++i) { + for (int j = 0; j <= n; ++j) { + if (i == 0 || j == 0) { + dp[i][j] = i + j; + } else { + dp[i][j] = dp[i - 1][j - 1] + (word1[i - 1] != word2[j - 1]); + dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1); + dp[i][j] = min(dp[i][j], dp[i][j - 1] + 1); + } + } + } + return dp[m][n]; +} +``` + + + + +```py +def minDistance(word1: str, word2: str) -> int: + m, n = len(word1), len(word2) + dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + for i in range(m + 1): + for j in range(n + 1): + if i == 0 or j == 0: + dp[i][j] = i + j + else: + dp[i][j] = min( + dp[i - 1][j - 1] + int(word1[i - 1] != word2[j - 1]), + dp[i][j - 1] + 1, + dp[i - 1][j] + 1, + ) + return dp[m][n] +``` + + + + + +## [650. 2 Keys Keyboard](https://leetcode.com/problems/2-keys-keyboard/) + +### 題目描述 + +給定一個字母 A,已知你可以每次選擇複製全部字符,或者粘貼之前複製的字符,求最少需要幾次操作可以把字符串延展到指定長度。 + +### 輸入輸出範例 + +輸入是一個正整數,代表指定長度;輸出是一個整數,表示最少操作次數。 + +``` +Input: 3 +Output: 3 +``` + +在這個範例中,一種最優的操作方法是先複製一次,再貼上兩次。 + +### 題解 + +不同於以往通過加減實現的動態規劃,這裡需要乘除法來計算位置,因為粘貼操作是倍數增加的。我們使用一個一維陣列 dp,其中位置 i 表示延展到長度 i 的最少操作次數。對於每個位置 j,如果 j 可以被 i 整除,那麼長度 i 就可以由長度 j 操作得到,其操作次數等價於把一個長度為 j 的 A 延展到長度為 i/j。因此我們可以得到遞推公式 dp[i] = dp[j] + dp[i/j]。 + + + + +```cpp +int minSteps(int n) { + vector dp(n + 1, 0); + for (int i = 2; i <= n; ++i) { + dp[i] = i; + for (int j = 2; j * j <= i; ++j) { + if (i % j == 0) { + dp[i] = dp[j] + dp[i / j]; + // 提前剪枝,因為j從小到大,因此操作數量一定最小。 + break; + } + } + } + return dp[n]; +} +``` + + + + +```py +def minSteps(n: int) -> int: + dp = [0] * 2 + list(range(2, n + 1)) + for i in range(2, n + 1): + for j in range(2, floor(sqrt(i)) + 1): + if i % j == 0: + dp[i] = dp[j] + dp[i // j] + # 提前剪枝,因為j從小到大,因此操作數量一定最小。 + break + return dp[n] +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx new file mode 100644 index 00000000..d02e1f32 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-8-stock-trading.mdx @@ -0,0 +1,183 @@ +--- +sidebar_position: 33 +--- + +# 6.8 股票交易 + +`股票交易`類問題通常可以用動態規劃來解決。對於稍微複雜一些的股票交易類問題,比如需要冷卻時間或者交易費用,則可以通過動態規劃實現的`狀態機`來解決。 + +## [121. Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) + +### 題目描述 + +給定一段時間內每天某只股票的固定價格,已知你只可以買賣各一次,求最大的收益。 + +### 輸入輸出範例 + +輸入一個一維整數陣列,表示每天的股票價格;輸出一個整數,表示最大的收益。 + +``` +Input: [7,1,5,3,6,4] +Output: 5 +``` + +在這個範例中,最大的利潤為在第二天價格為 1 時買入,在第五天價格為 6 時賣出。 + +### 題解 + +我們可以遍歷一遍陣列,在每一個位置 i 時,記錄 i 位置之前所有價格中的最低價格,然後將當前的價格作為賣出價格,查看當前收益是否為最大收益即可。注意本題中以及之後題目中的 buy 和 sell 表示買賣操作時,用戶賬戶的收益。因此買時為負,賣時為正。 + + + + +```cpp +int maxProfit(vector& prices) { + int buy = numeric_limits::lowest(), sell = 0; + for (int price : prices) { + buy = max(buy, -price); + sell = max(sell, buy + price); + } + return sell; +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + buy, sell = -sys.maxsize, 0 + for price in prices: + buy = max(buy, -price) + sell = max(sell, buy + price) + return sell +``` + + + + + +## [188. Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) + +### 題目描述 + +給定一段時間內每天某只股票的固定價格,已知你只可以買賣各 $k$ 次,且每次只能擁有一支股票,求最大的收益。 + +### 輸入輸出範例 + +輸入一個一維整數陣列,表示每天的股票價格;以及一個整數,表示可以買賣的次數 $k$。輸出一個整數,表示最大的收益。 + +``` +Input: [3,2,6,5,0,3], k = 2 +Output: 7 +``` + +在這個範例中,最大的利潤為在第二天價格為 2 時買入,在第三天價格為 6 時賣出;再在第五天價格為 0 時買入,在第六天價格為 3 時賣出。 + +### 題解 + +類似地,我們可以建立兩個動態規劃陣列 `buy` 和 `sell`,對於每天的股票價格,`buy[j]` 表示在第 $j$ 次買入時的最大收益,`sell[j]` 表示在第 $j$ 次賣出時的最大收益。 + + + + + +```cpp +int maxProfit(int k, vector& prices) { + int days = prices.size(); + vector buy(k + 1, numeric_limits::lowest()), sell(k + 1, 0); + for (int i = 0; i < days; ++i) { + for (int j = 1; j <= k; ++j) { + buy[j] = max(buy[j], sell[j - 1] - prices[i]); + sell[j] = max(sell[j], buy[j] + prices[i]); + } + } + return sell[k]; +} +``` + + + + +```py +def maxProfit(k: int, prices: List[int]) -> int: + days = len(prices) + buy, sell = [-sys.maxsize] * (k + 1), [0] * (k + 1) + for i in range(days): + for j in range(1, k + 1): + buy[j] = max(buy[j], sell[j - 1] - prices[i]) + sell[j] = max(sell[j], buy[j] + prices[i]) + return sell[k] +``` + + + + + +## [309. Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) + +### 題目描述 + +給定一段時間內每天某只股票的固定價格,已知每次賣出之後必須冷卻一天,且每次只能擁有一支股票,求最大的收益。 + +### 輸入輸出範例 + +輸入一個一維整數陣列,表示每天的股票價格;輸出一個整數,表示最大的收益。 + +``` +Input: [1,2,3,0,2] +Output: 3 +``` + +在這個範例中,最大的利潤獲取操作是買入、賣出、冷卻、買入、賣出。 + +### 題解 + +我們可以使用狀態機來解決這類複雜的狀態轉移問題。通過建立多個狀態以及它們的轉移方式,我們可以很容易地推導出各個狀態的轉移方程。如圖所示,我們可以建立四個狀態來表示帶有冷卻的股票交易,以及它們之間的轉移方式。 + +
+ + ![](6.5.png) + +
圖 6.5: 題目 309 - 狀態機狀態轉移
+
+ + + + +```cpp +int maxProfit(vector& prices) { + int n = prices.size(); + vector buy(n), sell(n), s1(n), s2(n); + s1[0] = buy[0] = -prices[0]; + sell[0] = s2[0] = 0; + for (int i = 1; i < n; ++i) { + buy[i] = s2[i - 1] - prices[i]; + s1[i] = max(buy[i - 1], s1[i - 1]); + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i]; + s2[i] = max(s2[i - 1], sell[i - 1]); + } + return max(sell[n - 1], s2[n - 1]); +} +``` + + + + +```py +def maxProfit(prices: List[int]) -> int: + n = len(prices) + buy, sell, s1, s2 = [0] * n, [0] * n, [0] * n, [0] * n + s1[0] = buy[0] = -prices[0] + sell[0] = s2[0] = 0 + for i in range(1, n): + buy[i] = s2[i - 1] - prices[i] + s1[i] = max(buy[i - 1], s1[i - 1]) + sell[i] = max(buy[i - 1], s1[i - 1]) + prices[i] + s2[i] = max(s2[i - 1], sell[i - 1]) + return max(sell[n - 1], s2[n - 1]) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md new file mode 100644 index 00000000..02541d9a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6-9-exercises.md @@ -0,0 +1,61 @@ +--- +sidebar_position: 34 +--- + +# 6.9 練習 + +## 基礎難度 + +### [213. House Robber II](https://leetcode.com/problems/house-robber-ii/) + +強盜搶劫問題的 follow-up,如何處理環形陣列呢? + +--- + +### [53. Maximum Subarray](https://leetcode.com/problems/maximum-subarray/) + +經典的一維動態規劃題目,試著把一維空間優化為常量吧。 + +--- + +### [343. Integer Break](https://leetcode.com/problems/integer-break/) + +分割類型題,先嘗試用動態規劃求解,再思考是否有更簡單的解法。 + +--- + +### [583. Delete Operation for Two Strings](https://leetcode.com/problems/delete-operation-for-two-strings/) + +最長公共子序列的變種題。 + +--- + +## 進階難度 + +### [646. Maximum Length of Pair Chain](https://leetcode.com/problems/maximum-length-of-pair-chain/) + +最長遞增子序列的變種題,同樣的,嘗試用二分進行加速。 + +--- + +### [10. Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching/) + +正則表達式匹配,非常考驗耐心。需要根據正則表達式的不同情況,即字符、星號,點號等,分情況討論。 + +--- + +### [376. Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/) + +最長擺動子序列,通項公式比較特殊,需要仔細思考。 + +--- + +### [494. Target Sum](https://leetcode.com/problems/target-sum/) + +如果告訴你這道題是 0-1 背包,你是否會有一些思路? + +--- + +### [714. Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) + +建立狀態機,股票交易類問題就會迎刃而解。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png new file mode 100644 index 00000000..6b075633 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.1.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png new file mode 100644 index 00000000..4ff0572c Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.3.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png new file mode 100644 index 00000000..4acc447e Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.4.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png new file mode 100644 index 00000000..97774d35 Binary files /dev/null and b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/6.5.png differ diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json new file mode 100644 index 00000000..bf74ea61 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/6-dynamic-programming/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "6. 深入淺出動態規劃", + "position": 6, + "link": { + "type": "generated-index", + "description": "第 6 章 深入淺出動態規劃" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md new file mode 100644 index 00000000..abe36bc5 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-1-algorithm-explanation.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 35 +--- + +# 7.1 算法解釋 + +顧名思義,`分治問題`由“分”(divide)和“治”(conquer)兩部分組成,通過把原問題分為子問題,再將子問題進行處理合併,從而實現對原問題的求解。我們在排序章節展示的合併排序就是典型的分治問題,其中“分”即為把大陣列平均分成兩個小陣列,通過遞迴實現,最終我們會得到多個長度為 1 的子陣列;“治”即為把已經排好序的兩個小陣列合併為一個排好序的大陣列,從長度為 1 的子陣列開始,最終合成一個大陣列。 + +我們也使用數學表達式來表示這個過程。定義 $T(n)$ 表示處理一個長度為 $n$ 的陣列的時間複雜度,則合併排序的時間複雜度遞推公式為 $T(n) = 2T(n/2) + O(n)$。其中 $2T(n/2)$ 表示我們分成了兩個長度減半的子問題,$O(n)$ 則為合併兩個長度為 $n/2$ 陣列的時間複雜度。 + +:::info 定理 7.1. 主定理 + +考慮 $T(n) = aT(n/b) + f(n)$,定義 $k = \log_{b} a$ +1. 如果 $f(n) = O(n^p)$ 且 $p < k$,那麼 $T(n) = O(n^k)$ +2. 如果存在 $c \geq 0$ 滿足 $f(n) = O(n^k \log^c n)$,那麼 $T(n) = O(n^k \log^{c+1} n)$ +3. 如果 $f(n) = O(n^p)$ 且 $p > k$,那麼 $T(n) = O(f(n))$ + +::: + +通過主定理我們可以知道,合併排序屬於第二種情況,且時間複雜度為 $O(n \log n)$。其他的分治問題也可以通過主定理求得時間複雜度。 + +另外,自上而下的分治可以和 memoization 結合,避免重複遍歷相同的子問題。如果方便推導,也可以換用自下而上的動態規劃方法求解。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx new file mode 100644 index 00000000..17bb29c3 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-2-expression-problems.mdx @@ -0,0 +1,154 @@ +--- +sidebar_position: 36 +--- + +# 7.2 表達式問題 + +## [241. Different Ways to Add Parentheses](https://leetcode.com/problems/different-ways-to-add-parentheses/) + +### 題目描述 + +給定一個只包含加、減和乘法的數學表達式,求通過加括號可以得到多少種不同的結果。 + +### 輸入輸出範例 + +輸入是一個字符串,表示數學表達式;輸出是一個陣列,儲存所有不同的加括號結果。 + +``` +Input: "2-1-1" +Output: [0, 2] +``` + +在這個範例中,有兩種加括號結果:((2-1)-1) = 0 和 (2-(1-1)) = 2。 + +### 題解 + +利用分治思想,我們可以把加括號轉化為,對於每個運算符號,先執行處理兩側的數學表達式,再處理此運算符號。注意邊界情況,即字符串內無運算符號,只有數字。 + + + + +```cpp +vector diffWaysToCompute(string expression) { + vector ways; + unordered_map> op_funcs; + op_funcs[’+’] = [](int x, int y) { return x + y; }; + op_funcs[’-’] = [](int x, int y) { return x - y; }; + op_funcs[’*’] = [](int x, int y) { return x * y; }; + for (int i = 0; i < expression.length(); ++i) { + char c = expression[i]; + if (!op_funcs.contains(c)) { + continue; + } + auto left = diffWaysToCompute(expression.substr(0, i)); + auto right = diffWaysToCompute(expression.substr(i + 1)); + for (int l : left) { + for (int r : right) { + ways.push_back(op_funcs[c](l, r)); + } + } + } + return ways.empty() ? vector{stoi(expression)} : ways; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + ways = [] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i, c in enumerate(expression): + if c not in op_funcs: + continue + left = diffWaysToCompute(expression[:i]) + right = diffWaysToCompute(expression[i + 1 :]) + ways += [op_funcs[c](l, r) for l in left for r in right] + return [int(expression)] if len(ways) == 0 else ways +``` + + + + + +我們發現,某些被 `divide` 的子字串可能重複出現多次,因此我們可以利用 `memoization` 來避免重複計算。例如,我們可以建立一個雜湊表,`key` 是 `(l, r)`,`value` 是 `ways`。當再次遇到相同的 `(l, r)` 時,我們可以直接返回已經計算過的 `ways`。或者,與其我們從上到下用分治法結合 `memoization`,不如直接從下到上使用動態規劃處理。 + + + + +```cpp +vector diffWaysToCompute(string expression) { + // 利用 istringstream,將數字和運算符進行分詞。 + vector nums; + vector ops; + int num = 0; + char op = ’ ’; + istringstream ss(expression); + while (ss >> num) { + nums.push_back(num); + if (ss >> op) { + ops.push_back(op); + } + } + int n = nums.size(); + vector>> dp(n, vector>(n, vector())); + unordered_map> op_funcs; + op_funcs[’+’] = [](int a, int b) { return a + b; }; + op_funcs[’-’] = [](int a, int b) { return a - b; }; + op_funcs[’*’] = [](int a, int b) { return a * b; }; + for (int i = 0; i < n; ++i) { + for (int j = i; j >= 0; --j) { + if (i == j) { + dp[j][i].push_back(nums[i]); + continue; + } + for (int k = j; k < i; ++k) { + for (auto l : dp[j][k]) { + for (auto r : dp[k + 1][i]) { + dp[j][i].push_back(op_funcs[ops[k]](l, r)); + } + } + } + } + } + return dp[0][n - 1]; +} +``` + + + + +```py +def diffWaysToCompute(expression: str) -> List[int]: + # re.split 可以直接將運算符(\D)和數字分開。 + sections = re.split(r"(\D)", expression) + nums = [int(num) for num in sections if num.isdigit()] + ops = [op for op in sections if not op.isdigit()] + n = len(nums) + dp = [[[] for _ in range(n)] for _ in range(n)] + op_funcs = { + "+": (lambda x, y: x + y), + "-": (lambda x, y: x - y), + "*": (lambda x, y: x * y), + } + for i in range(n): + for j in range(i, -1, -1): + if i == j: + dp[j][i].append(nums[i]) + continue + for k in range(j, i): + dp[j][i] += [op_funcs[ops[k]](l, r) + for l in dp[j][k] for r in dp[k + 1][i]] + + return dp[0][n - 1] + +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md new file mode 100644 index 00000000..be141f55 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/7-3-exercises.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 37 +--- + +# 7.3 練習 + +## 基礎難度 + +### [932. Beautiful Array](https://leetcode.com/problems/beautiful-array/) + +嘗試使用從上到下的分治(遞迴)寫法進行求解,並最好加入 `memoization` 優化;之後再嘗試使用從下到上的動態規劃寫法求解。 + +--- + +## 進階難度 + +### [312. Burst Balloons](https://leetcode.com/problems/burst-balloons/) + +嘗試使用從上到下的分治(遞迴)寫法進行求解,並最好加入 `memoization` 優化;之後再嘗試使用從下到上的動態規劃寫法求解。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json new file mode 100644 index 00000000..2a461e56 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/7-divide-and-conquer/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "7. 化繁為簡的分治法", + "position": 7, + "link": { + "type": "generated-index", + "description": "第 7 章 化繁為簡的分治法" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md new file mode 100644 index 00000000..5b73d0be --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-1-introduction.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 38 +--- + +# 8.1 引言 + +對於 LeetCode 上數量不少的數學題,我們盡量將其按照類型劃分講解。然而許多數學題的解法並不具通用性,因此我們很難一次性將所有解題套路完整講解清楚。因此,我們挑選了一些經典或典型的題目,供大家參考。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx new file mode 100644 index 00000000..f9679ed6 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-2-lcm-gcd.mdx @@ -0,0 +1,71 @@ +--- +sidebar_position: 39 +--- + +# 8.2 公倍數與公因數 + +利用`輾轉相除法`,我們可以很方便地求得兩個數的最大公因數(greatest common divisor,GCD);將兩個數相乘再除以最大公因數即可得到最小公倍數(least common multiple, LCM)。 + + + + +```cpp +int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); +} + +int lcm(int a, int b) { + return a * b / gcd(a, b); +} +``` + + + + +```py +def gcd(a: int, b: int) -> int: + return a if b == 0 else gcd(b, a % b) + +def lcm(a: int, b: int) -> int: + return (a * b) // gcd(a, b) +``` + + + + + +進一步地,我們也可以通過擴展歐幾里得算法(extended gcd)在求得 a 和 b 最大公因數的同時,也得到它們的係數 x 和 y,從而使 ax + by = gcd(a, b)。因為 Python 中 int 只能按值傳遞,我們可以用一個長度固定為 1 的 list() 來進行傳遞引用的操作。 + + + + +```cpp +int xGCD(int a, int b, int &x, int &y) { + if (b == 0) { + x = 1, y = 0; + return a; + } + int x_inner, y_inner; + int gcd = xGCD(b, a % b, x_inner, y_inner); + x = y_inner, y = x_inner - (a / b) * y_inner; + return gcd; +} +``` + + + + +```py +def xGCD(a: int, b: int, x: List[int], y: List[int]) -> int: + if b == 0: + x[0], y[0] = 1, 0 + return a + x_inner, y_inner = [0], [0] + gcd = xGCD(b, a % b, x_inner, y_inner) + x[0], y[0] = y_inner, x_inner - (a / b) * y_inner + return gcd +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx new file mode 100644 index 00000000..ec93336c --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-3-prime-numbers.mdx @@ -0,0 +1,136 @@ +--- +sidebar_position: 40 +--- + +# 8.3 質數 + +質數又稱素數,指的是在大於 1 的自然數中,除了 1 和它本身以外不再有其他因數的自然數。值得注意的是,每一個數都可以分解成質數的乘積。 + +## [204. Count Primes](https://leetcode.com/problems/count-primes/) + +### 題目描述 + +給定一個數字 n,求小於 n 的質數的個數。 + +### 輸入輸出範例 + +輸入一個整數,輸出也是一個整數,表示小於輸入數的質數的個數。 + +``` +Input: 10 +Output: 4 +``` + +在這個範例中,小於 10 的質數只有 [2, 3, 5, 7]。 + +### 題解 + +`埃拉托斯特尼篩法`(Sieve of Eratosthenes,簡稱埃氏篩法)是非常常用的,用於判斷一個整數是否為質數的方法。它也可以在判斷一個整數 $n$ 時,同時判斷所有小於 $n$ 的整數,因此非常適合這道題目。其原理也十分簡單:從 $1$ 到 $n$ 遍歷,假設當前遍歷到 $m$,則把所有小於 $n$ 且是 $m$ 的倍數的整數標記為和數;遍歷完成後,沒有被標記為和數的數字即為質數。 + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int count = n - 2; // 移除不是質數的 1 + for (int i = 2; i < n; ++i) { + if (primes[i]) { + for (int j = 2 * i; j < n; j += i) { + if (primes[j]) { + primes[j] = false; + --count; + } + } + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + count = n - 2 # 移除不是質數的 1 + for i in range(2, n): + if primes[i]: + for j in range(2 * i, n, i): + if primes[j]: + primes[j] = False + count -= 1 + return count +``` + + + + + +利用質數的一些性質,我們可以進一步優化該演算法。 + + + + +```cpp +int countPrimes(int n) { + if (n <= 2) { + return 0; + } + vector primes(n, true); + int sqrtn = sqrt(n); + int count = n / 2; // 偶數一定不是質數 + int i = 3; + // 最小質因子一定小於等於平方根。 + while (i <= sqrtn) { + // 向右找倍數,注意避免偶數和重複遍歷。 + for (int j = i * i; j < n; j += 2 * i) { + if (primes[j]) { + --count; + primes[j] = false; + } + } + i += 2; + // 向右前進查找位置,注意避免偶數和重複遍歷。 + while (i <= sqrtn && !primes[i]) { + i += 2; + } + } + return count; +} +``` + + + + +```py +def countPrimes(n: int) -> int: + if n <= 2: + return 0 + primes = [True for _ in range(n)] + sqrtn = sqrt(n) + count = n // 2 # 偶數一定不是質數 + i = 3 + # 最小質因子一定小於等於平方根。 + while i <= sqrtn: + # 向右找倍數,注意避免偶數和重複遍歷。 + for j in range(i * i, n, 2 * i): + if primes[j]: + count -= 1 + primes[j] = False + i += 2 + # 向右前進查找位置,注意避免偶數和重複遍歷。 + while i <= sqrtn and not primes[i]: + i += 2 + return count +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx new file mode 100644 index 00000000..fc8a8085 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-4-number-processing.mdx @@ -0,0 +1,315 @@ +--- +sidebar_position: 41 +--- + +# 8.4 數字處理 + +## [504. Base 7](https://leetcode.com/problems/base-7/) + +### 題目描述 + +給定一個十進制整數,求它在七進制下的表示。 + +### 輸入輸出範例 + +輸入一個整數,輸出一個字串,表示其七進制。 + +``` +Input: 100 +Output: "202" +``` + +在這個範例中,100 的七進制表示法來源於 100 = 2 * 49 + 0 * 7 + 2 * 1。 + +### 題解 + +`進制轉換`類型的題目,通常是利用除法和取模(mod)來進行計算,同時也要注意一些細節,如負數和零。如果輸出是數字類型而非字串,也需要考慮是否會超出整數上下界。 + + + + +```cpp +string convertToBase7(int num) { + if (num == 0) { + return "0"; + } + string base7; + bool is_negative = num < 0; + num = abs(num); + while (num) { + int quotient = num / 7, remainder = num % 7; + base7 = to_string(remainder) + base7; + num = quotient; + } + return is_negative ? "-" + base7 : base7; +} +``` + + + + +```py +def convertToBase7(num: int) -> str: + if num == 0: + return "0" + base7 = "" + is_negative = num < 0 + num = abs(num) + while num: + quotient, remainder = num // 7, num % 7 + base7 = str(remainder) + base7 + num = quotient + return "-" + base7 if is_negative else base7 +``` + + + + + +## [172. Factorial Trailing Zeroes](https://leetcode.com/problems/factorial-trailing-zeroes/) + +### 題目描述 + +給定一個非負整數,判斷它的階乘結果的結尾有幾個 0。 + +### 輸入輸出範例 + +輸入一個非負整數,輸出一個非負整數,表示輸入的階乘結果的結尾有幾個 0。 + +``` +Input: 12 +Output: 2 +``` + +在這個範例中,12! = 479001600 的結尾有兩個 0。 + +### 題解 + +每個尾部的 0 由 2 × 5 = 10 而來,因此我們可以把階乘的每一個元素拆成質數相乘,統計有多少個 2 和 5。明顯的,質因子 2 的數量遠多於質因子 5 的數量,因此我們可以只統計階乘結果裡有多少個質因子 5。 + + + + +```cpp +int trailingZeroes(int n) { + return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5); +} +``` + + + + +```py +def trailingZeroes(n: int) -> int: + return 0 if n == 0 else n // 5 + trailingZeroes(n // 5) +``` + + + + + +## [415. Add Strings](https://leetcode.com/problems/add-strings/) + +### 題目描述 + +給定兩個由數字組成的字符串,求它們相加的結果。 + +### 輸入輸出範例 + +輸入是兩個字符串,輸出是一個整數,表示輸入的數字和。 + +``` +Input: num1 = "99", num2 = "1" +Output: 100 +``` + +因為相加運算是從後往前進行的,所以可以先翻轉字符串,再逐位計算。這種類型的題目考察的是細節,如進位、位數差等等。 + +### 題解 + + + + +```cpp +string addStrings(string num1, string num2) { + string added_str; + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + int len1 = num1.length(), len2 = num2.length(); + if (len1 <= len2) { + swap(num1, num2); + swap(len1, len2); + } + int add_bit = 0; + for (int i = 0; i < len1; ++i) { + int cur_sum = + (num1[i] - ’0’) + (i < len2 ? num2[i] - ’0’ : 0) + add_bit; + added_str += to_string(cur_sum % 10); + add_bit = cur_sum >= 10; + } + if (add_bit) { + added_str += "1"; + } + reverse(added_str.begin(), added_str.end()); + return added_str; +} +``` + + + + +```py +def addStrings(num1: str, num2: str) -> str: + added_str = "" + num1 = num1[::-1] + num2 = num2[::-1] + len1, len2 = len(num1), len(num2) + if len1 <= len2: + num1, num2 = num2, num1 + len1, len2 = len2, len1 + add_bit = 0 + for i in range(len1): + cur_sum = int(num1[i]) + (int(num2[i]) if i < len2 else 0) + add_bit + added_str += str(cur_sum % 10) + add_bit = int(cur_sum >= 10) + if add_bit: + added_str += "1" + return added_str[::-1] +``` + + + + + + +## [326. Power of Three](https://leetcode.com/problems/power-of-three/) + +### 題目描述 + +判斷一個數字是否是 3 的次方。 + +### 輸入輸出範例 + +輸入一個整數,輸出一個布林值。 + +``` +Input: n = 27 +Output: true +``` + +### 題解 + +有兩種方法,一種是利用對數。設 log3 n = m,如果 n 是 3 的整數次方,那麼 m 一定是整數。 + + + + +```cpp +bool isPowerOfThree(int n) { + return fmod(log10(n) / log10(3), 1) == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + return n > 0 and math.fmod(math.log10(n) / math.log10(3), 1) == 0 +``` + + + + + +另一種方法是,因為在 C++ `int` 範圍內 3 的最大次方是 $3^{19} = 1162261467$,如果 n 是 3 的整數次方,那麼 1162261467 除以 n 的餘數一定是零;反之亦然。然而對於 Python 來說,因為 `int` 理論上可以取無窮大,我們只能循環判斷。 + + + + +```cpp +bool isPowerOfThree(int n) { + return n > 0 && 1162261467 % n == 0; +} +``` + + + + +```py +def isPowerOfThree(n: int) -> bool: + if n <= 0: + return False + while n % 3 == 0: + n //= 3 + return n == 1 +``` + + + + + +## [50. Pow(x, n)](https://leetcode.com/problems/powx-n/) + +### 題目描述 + +計算 x 的 n 次方。 + +### 輸入輸出範例 + +輸入一個浮點數表示 x 和一個整數表示 n,輸出一個浮點數表示次方結果。 + +``` +Input: x = 2.00000, n = 10 +Output: 1024.00000 +``` + +### 題解 + +利用遞迴,我們可以較為輕鬆地解決本題。注意邊界條件的處理。 + + + + +```cpp +double myPow(double x, int n) { + if (n == 0) { + return 1; + } + if (x == 0) { + return 0; + } + if (n == numeric_limits::min()) { + return 1 / (x * myPow(x, numeric_limits::max())); + } + if (n < 0) { + return 1 / myPow(x, -n); + } + if (n % 2 != 0) { + return x * myPow(x, n - 1); + } + double myPowSqrt = myPow(x, n >> 1); + return myPowSqrt * myPowSqrt; +} +``` + + + + +```py +def myPow(x: float, n: int) -> float: + if n == 0: + return 1 + if x == 0: + return 0 + if n < 0: + return 1 / myPow(x, -n) + if n % 2 != 0: + return x * myPow(x, n - 1) + myPowSqrt = myPow(x, n >> 1) + return myPowSqrt * myPowSqrt +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx new file mode 100644 index 00000000..45d1d3f2 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-5-random-sampling.mdx @@ -0,0 +1,234 @@ +--- +sidebar_position: 42 +--- + +# 8.5 隨機與取樣 + +## [384. Shuffle an Array](https://leetcode.com/problems/shuffle-an-array/) + +### 題目描述 + +給定一個陣列,要求實現兩個指令函數。第一個函數「shuffle」可以隨機打亂這個陣列,第二個函數「reset」可以恢復原來的順序。 + +### 輸入輸出範例 + +輸入是一個存有整數數字的陣列,以及一個包含指令函數名稱的陣列。輸出是一個二維陣列,表示每個指令生成的陣列。 + +``` +Input: nums = [1,2,3], actions: ["shuffle","shuffle","reset"] +Output: [[2,1,3],[3,2,1],[1,2,3]] +``` + +在這個範例中,前兩次打亂的結果只要是隨機生成即可。 + +### 題解 + +我們採用經典的 `Fisher-Yates 洗牌算法`,其原理是通過隨機交換位置來實現隨機打亂,有正向和反向兩種寫法,且實現非常方便。注意這裡「reset」函數以及 Solution 類的構造函數的實現細節。 + + + + +```cpp +class Solution { + public: + Solution(vector nums) : nums_(nums) {} + + vector reset() { return nums_; } + + vector shuffle() { + vector shuffled(nums_); + int n = nums_.size(); + // 可以使用反向或者正向洗牌,效果相同。 + // 反向洗牌: + for (int i = n - 1; i >= 0; --i) { + swap(shuffled[i], shuffled[rand() % (i + 1)]); + } + // 正向洗牌: + // for (int i = 0; i < n; ++i) { + // int pos = rand() % (n - i); + // swap(shuffled[i], shuffled[i+pos]); + // } + return shuffled; + } + + private: + vector nums_; +}; +``` + + + + +```py +class Solution: + def __init__(self, nums: List[int]): + self.base = nums[:] + + def reset(self) -> List[int]: + return self.base[:] + + def shuffle(self) -> List[int]: + shuffled = self.base[:] + n = len(self.base) + # 可以使用反向或者正向洗牌,效果相同。 + # 反向洗牌: + for i in range(n - 1, -1, -1): + j = random.randint(0, i) + shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + # 正向洗牌: + # for i in range(n): + # j = i + random.randint(0, n - i - 1) + # shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + return shuffled +``` + + + + + +## [528. Random Pick with Weight](https://leetcode.com/problems/random-pick-with-weight/) + +### 題目描述 + +給定一個陣列,陣列每個位置的值表示該位置的權重,要求按照權重的概率去隨機抽樣。 + +### 輸入輸出範例 + +輸入是一維正整數陣列,表示權重;以及一個包含指令字串的一維陣列,表示運行幾次隨機抽樣。輸出是一維整數陣列,表示隨機抽樣的整數在陣列中的位置。 + +``` +Input: weights = [1,3], actions: ["pickIndex","pickIndex","pickIndex"] +Output: [0,1,1] +``` + +在這個範例中,每次選擇的位置都是不確定的,但選擇第 0 個位置的期望為 1/4,選擇第 1 個位置的期望為 3/4。 + +### 題解 + +我們可以先使用前綴和(partial_sum)計算到每個位置為止之前所有數字的總和,這個結果對於正整數陣列是單調遞增的。每當需要抽樣時,我們可以先隨機生成一個數字,然後使用二分法查找該數字在前綴和中的位置,以模擬加權抽樣的過程。這裡的二分法可以用 lower_bound 實現。 + +以範例為例,權重陣列 [1,3] 的前綴和為 [1,4]。如果我們隨機生成的數字為 1,那麼 lower_bound 返回的位置為 0;如果我們隨機生成的數字是 2、3、4,那麼 lower_bound 返回的位置為 1。 + +關於前綴和的更多技巧,我們將在接下來的章節中繼續深入講解。 + + + + +```cpp +class Solution { + public: + Solution(vector weights) : cumsum_(weights) { + partial_sum(cumsum_.begin(), cumsum_.end(), cumsum_.begin()); + } + + int pickIndex() { + int val = (rand() % cumsum_.back()) + 1; + return lower_bound(cumsum_.begin(), cumsum_.end(), val) - + cumsum_.begin(); + } + + private: + vector cumsum_; +}; +``` + + + + +```py +class Solution: + def __init__(self, weights: List[int]): + self.cumsum = weights[:] + for i in range(1, len(weights)): + self.cumsum[i] += self.cumsum[i - 1] + + def pickIndex(self) -> int: + val = random.randint(1, self.cumsum[-1]) + return bisect.bisect_left(self.cumsum, val, 0, len(self.cumsum)) +``` + + + + + +## [382. Linked List Random Node](https://leetcode.com/problems/linked-list-random-node/) + +### 題目描述 + +給定一個單向鏈結串列,要求設計一個演算法,可以隨機取得其中的一個數字。 + +### 輸入輸出範例 + +輸入是一個單向鏈結串列,輸出是一個數字,表示鏈結串列裡其中一個節點的值。 + +``` +Input: 1->2->3->4->5 +Output: 3 +``` + +在這個範例中,我們有均等的概率得到任意一個節點,比如 3。 + +### 題解 + +不同於陣列,在未遍歷完鏈結串列前,我們無法知道鏈結串列的總長度。這裡我們可以使用水庫抽樣:遍歷一次鏈結串列,在遍歷到第 $m$ 個節點時,有 $\frac{1}{m}$ 的概率選擇這個節點覆蓋掉之前的選擇。 + +我們提供一個簡單的,對於水庫算法隨機性的證明。對於長度為 $n$ 的鏈結串列的第 $m$ 個節點,最後被抽樣的充要條件是它被選擇,且之後的節點都沒有被選擇。這種情況發生的概率為: + +$$ +\frac{1}{m} × \frac{m}{m+1} × \frac{m+1}{m+2} × · · · × \frac{n−1}{n} = \frac{1}{n} +$$ + +因此每個點都有均等的概率被選擇。 + +當然,這道題我們也可以預處理鏈結串列,遍歷一遍之後把它轉化成陣列。 + + + + +```cpp +class Solution { + public: + Solution(ListNode* node) : head_(node) {} + + int getRandom() { + int pick = head_->val; + ListNode* node = head_->next; + int i = 2; + while (node) { + if (rand() % i == 0) { + pick = node->val; + } + ++i; + node = node->next; + } + return pick; + } + + private: + ListNode* head_; +}; +``` + + + + +```py +class Solution: + def __init__(self, head: Optional[ListNode]): + self.head = head + + def getRandom(self) -> int: + pick = self.head.val + node = self.head.next + i = 2 + while node is not None: + if random.randint(0, i - 1) == 0: + pick = node.val + i += 1 + node = node.next + return pick +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md new file mode 100644 index 00000000..165a9a1c --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/8-6-exercises.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 43 +--- + +# 8.6 練習 + +## 基礎難度 + +### [168. Excel Sheet Column Title](https://leetcode.com/problems/excel-sheet-column-title/) + +7 進制轉換的變種題,需要注意的一點是從 1 開始而不是 0。 + +--- + +### [67. Add Binary](https://leetcode.com/problems/add-binary/) + +字符串加法的變種題。 + +--- + +### [238. Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self/) + +你可以不使用除法做這道題嗎?我們很早之前講過的題目 135 或許能給你一些思路。 + +--- + +## 進階難度 + +### [462. Minimum Moves to Equal Array Elements II](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/) + +這道題是筆者最喜歡的 LeetCode 題目之一,需要先推理出怎麼樣移動是最優的,再考慮如何進行移動。你或許需要一些前些章節講過的算法。 + +--- + +### [169. Majority Element](https://leetcode.com/problems/majority-element/) + +如果想不出簡單的解決方法,搜尋一下 Boyer-Moore Majority Vote 算法吧。 + +--- + +### [470. Implement Rand10() Using Rand7()](https://leetcode.com/problems/implement-rand10-using-rand7/) + +如何用一個隨機數生成器生成另一個隨機數生成器?你可能需要利用原來的生成器多次。 + +--- + +### [202. Happy Number](https://leetcode.com/problems/happy-number/) + +你可以簡單的用一個 `while` 循環解決這道題,但是有沒有更好的解決辦法?如果我們把每個數字想像成一個節點,是否可以轉化為環路檢測? \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json new file mode 100644 index 00000000..007997b1 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/8-mathematical-solutions/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "8. 巧解數學問題", + "position": 8, + "link": { + "type": "generated-index", + "description": "第 8 章 巧解數學問題" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md new file mode 100644 index 00000000..93254a53 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-1-common-techniques.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 44 +--- + +# 9.1 常用技巧 + +`位運算`是演算法題目中較為特殊的一種類型,利用二進制位運算的特性可以實現一些奇妙的優化與計算。以下是一些常見的位運算符號及其功能: + + +- `∧`:按位異或 +- `&`:按位與 +- `|`:按位或 +- `~`:取反 +- `<<`:算術左移 +- `>>`:算術右移 + +以下是一些常見的位運算特性,其中 `0s` 和 `1s` 分別表示只由 `0` 或 `1` 構成的二進制數字。 + +``` +x ^ 0s = x x & 0s = 0 x | 0s = x +x ^ 1s = ~x x & 1s = x x | 1s = 1s +x ^ x = 0 x & x = x x | x = x +``` + +除此之外,以下是一些經常用到的特殊技巧: + +1. **消去最低位的 1**:`n & (n - 1)` + - 此操作可以去除 n 的位級表示中最低的那一位。例如: + ``` + n = 11110100 + n - 1 = 11110011 + n & (n - 1) = 11110000 + ``` + +2. **獲取最低位的 1**:`n & (-n)` + - 此操作可以得到 n 的位級表示中最低的那一位。例如: + ``` + n = 11110100 + -n = 00001100 + n & (-n) = 00000100 + ``` + +以上僅是常用的位運算技巧,如果讀者感興趣,可以進一步探索更多不常見但強大的位運算方法,這裡不再贅述。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx new file mode 100644 index 00000000..00c82e9d --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-2-basic-bitwise-problems.mdx @@ -0,0 +1,179 @@ +--- +sidebar_position: 45 +--- + +# 9.2 位運算基礎問題 + +## [461. Hamming Distance](https://leetcode.com/problems/hamming-distance/) + +### 題目描述 + +給定兩個十進制數字,求它們二進制表示的漢明距離(Hamming distance,即不同位的個數)。 + +### 輸入輸出範例 + +输入是两个十进制整数,输出是一个十进制整数,表示两个输入数字的汉明距离。 + +``` +Input: x = 1, y = 4 +Output: 2 +``` + +在這個範例中,1 的二進制是 0001,4 的二進制是 0100,一共有兩位不同。 + +### 題解 + +對兩個數進行按位異或操作,統計結果中有多少個 1 即可。 + + + + +```cpp +int hammingDistance(int x, int y) { + int diff = x ^ y, dist = 0; + while (diff != 0) { + dist += diff & 1; + diff >>= 1; + } + return dist; +} +``` + + + + +```py +def hammingDistance(x: int, y: int) -> int: + diff = x ^ y + dist = 0 + while diff != 0: + dist += diff & 1 + diff = diff >> 1 + return dist +``` + + + + + +## [190. Reverse Bits](https://leetcode.com/problems/reverse-bits/) + +### 題目描述 + +給定一個十進制正整數,輸出它在二進制下的翻轉結果。 + +### 輸入輸出範例 + +輸入和輸出都是十進制正整數。 + +``` +Input: 43261596 (00000010100101000001111010011100) +Output: 964176192 (00111001011110000010100101000000) +``` + +使用算術左移和右移,可以很輕易地實現二進制的翻轉。 + +### 題解 + + + + +```cpp +uint32_t reverseBits(uint32_t n) { + uint32_t m = 0; + for (int i = 0; i < 32; ++i) { + m <<= 1; + m += n & 1; + n >>= 1; + } + return m; +} +``` + + + + +```py +def reverseBits(n: int) -> int: + m = 0 + for _ in range(32): + m = m << 1 + m += n & 1 + n = n >> 1 + return m +``` + + + + + +## [136. Single Number](https://leetcode.com/problems/single-number/) + +### 題目描述 + +給定一個整數陣列,這個陣列裡只有一個數字只出現了一次,其餘數字出現了兩次,求這個只出現一次的數字。 + +### 輸入輸出範例 + +輸入是一個一維整數陣列,輸出是該陣列內的一個整數。 + +``` +Input: [4,1,2,1,2] +Output: 4 +``` + +### 題解 + +我們可以利用 x ∧ x = 0 和 x ∧ 0 = x 的特點,將陣列內所有的數字進行按位異或。出現兩次的所有數字按位異或的結果是 0,0 與出現一次的數字異或可以得到這個數字本身。 + + + + +```cpp +int singleNumber(vector& nums) { + int single = 0; + for (int num : nums) { + single ^= num; + } + return single; +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + single = 0 + for num in nums: + single = single ^ num + return single +``` + + + + + +這裡我們也可以直接使用 `reduce` 函數: + + + + +```cpp +int singleNumber(vector& nums) { + return reduce(nums.begin(), nums.end(), 0, + [](int x, int y) { return x ^ y; }); +} +``` + + + + +```py +def singleNumber(nums: List[int]) -> int: + return functools.reduce(lambda x, y: x ^ y, nums) +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx new file mode 100644 index 00000000..6afe5ac9 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-3-binary-properties.mdx @@ -0,0 +1,125 @@ +--- +sidebar_position: 46 +--- + +# 9.3 二進制特性 + +利用二進制的一些特性,我們可以把位運算使用到更多問題上。 + +例如,我們可以利用二進制和位運算輸出一個陣列的所有子集。假設我們有一個長度為 $n$ 的陣列,我們可以生成長度為 $n$ 的所有二進制,1 表示選取該數字,0 表示不選取。這樣我們就獲得了 $2^n$ 個子集。 + +## [318. Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/) + +### 題目描述 + +給定多個字母串,求其中任意兩個字母串的長度乘積的最大值,且這兩個字母串不能含有相同字母。 + +### 輸入輸出範例 + +輸入一個包含多個字母串的一維陣列,輸出一個整數,表示長度乘積的最大值。 + +``` +Input: ["a","ab","abc","d","cd","bcd","abcd"] +Output: 4 +``` + +在這個範例中,一種最優的選擇是“ab”和“cd”。 + +### 題解 + +怎樣快速判斷兩個字母串是否含有重複字母呢?可以為每個字母串建立一個長度為 26 的二進制數字,每個位置表示是否存在該字母。如果兩個字母串含有重複字母,那它們的二進制表示的按位與不為 0。同時,我們可以建立一個雜湊表來儲存二進制數字到最長子母串長度的映射關係,比如 ab 和 aab 的二進制數字相同,但是 aab 更長。 + + + + +```cpp +int maxProduct(vector& words) { + unordered_map cache; + int max_prod = 0; + for (const string& word : words) { + int mask = 0, w_len = word.length(); + for (char c : word) { + mask |= 1 << (c - ’a’); + } + cache[mask] = max(cache[mask], w_len); + for (auto [h_mask, h_len] : cache) { + if ((mask & h_mask) == 0) { + max_prod = max(max_prod, w_len * h_len); + } + } + } + return max_prod; +} +``` + + + + +```py +def maxProduct(words: List[str]) -> int: + cache = dict() + max_prod = 0 + for word in words: + mask, w_len = 0, len(word) + for c in word: + mask = mask | (1 << (ord(c) - ord("a"))) + cache[mask] = max(cache.get(mask, 0), w_len) + for h_mask, h_len in cache.items(): + if (mask & h_mask) == 0: + max_prod = max(max_prod, w_len * h_len) + return max_prod +``` + + + + + +## [338. Counting Bits](https://leetcode.com/problems/counting-bits/) + +### 題目描述 + +給定一個非負整數 n,求從 0 到 n 的所有數字的二進制表示中,各自有多少個 1。 + +### 輸入輸出範例 + +輸入是一個非負整數 n,輸出是一個長度為 n + 1 的非負整數陣列,每個位置 m 表示 m 的二進制中有多少個 1。 + +``` +Input: 5 +Output: [0,1,1,2,1,2] +``` + +### 題解 + +本題可以利用動態規劃和位運算進行快速求解。定義一個陣列 dp,其中 dp[i] 表示數字 i 的二進制中含有 1 的個數。對於第 i 個數字: +- 如果它二進制的最後一位為 1,那麼它含有 1 的個數為 dp[i-1] + 1; +- 如果它二進制的最後一位為 0,那麼它含有 1 的個數和其算術右移結果相同,即 dp[i>>1]。 + + + + +```cpp +vector countBits(int n) { + vector dp(n + 1, 0); + for (int i = 1; i <= n; ++i) + // 等價於:dp[i] = dp[i & (i - 1)] + 1; + dp[i] = i & 1 ? dp[i - 1] + 1 : dp[i >> 1]; + return dp; +} +``` + + + + +```py +def countBits(n: int) -> List[int]: + dp = [0] * (n + 1) + for i in range(1, n + 1): + # 等價於:dp[i] = dp[i & (i - 1)] + 1 + dp[i] = dp[i - 1] + 1 if i & 1 else dp[i >> 1] + return dp +``` + + + + \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md new file mode 100644 index 00000000..2d2923b4 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/9-4-exercises.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 47 +--- + +# 9.4 練習 + +## 基礎難度 + +### [268. Missing Number](https://leetcode.com/problems/missing-number/) + +Single Number 的變種題。除了利用二進位,也可以使用高斯求和公式解決。 + +--- + +### [693. Binary Number with Alternating Bits](https://leetcode.com/problems/binary-number-with-alternating-bits/) + +利用位運算判斷一個數的二進位表示是否會出現連續的 `0` 和 `1`。 + +--- + +### [476. Number Complement](https://leetcode.com/problems/number-complement/) + +二進位翻轉的變種題。 + +--- + +## 進階難度 + +### [260. Single Number III](https://leetcode.com/problems/single-number-iii/) + +Single Number 的進階版本。需要仔細思考如何利用位運算求解。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json new file mode 100644 index 00000000..c58b167a --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/9-bitwise-operations/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "9. 神奇的位元運算", + "position": 9, + "link": { + "type": "generated-index", + "description": "第 9 章 神奇的位元運算" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/acknowledgments.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/acknowledgments.md new file mode 100644 index 00000000..72f6ca66 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/acknowledgments.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 79 +--- + +# 鳴謝名單 + +## 官方唯一指定最強王者贊助 +Yudi Zhang + +## 友情贊助 + +排名不分先後:Yujia Chen、Chaoyu Wang、Chunyan Bai、Haoshuo Huang、Wenting Ye、Yuting Wang、Bill Liu、Zhiyu Min、Xuyang Cheng、Keyi Xian、Yihan Zhang、Rui Yan、Mao Cheng、Michael +Wang 等。 + +## GitHub 用戶 + +排名不分先後:quweikoala、szlghl1、mag1cianag、woodpenker、yangCoder96、cluckl、shaoshuai-luo、KivenGood、alicegong、hitYunhongXu、shengchen1998、jihchi、hapoyige、hitYunhongXu、h82258652、conan81412B、Mirrorigin、Light-young、XiangYG、xnervwang、sabaizzz、PhoenixChen98、zhang-wang997、corbg118、tracyqwerty、yorhaha、DeckardZ46、Ricardo-609、namu-guwal、hkulyc、jacklanda、View0、HelloYJohn、Corezcy、MoyuST、lutengda、fengshansi 等。 \ No newline at end of file diff --git a/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/index.md b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/index.md new file mode 100644 index 00000000..80e636a8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-plugin-content-docs/current/index.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 0 +--- + +# LeetCode 101: LeetCode 刷題指南 (第二版) + +![](https://github.com/changgyhub/leetcode_101/blob/master/misc/cover.jpg?raw=true) + +作者:高畅 Chang Gao + +語言:C++ & Python + +版本:正式版 2.0c,最新版見 GitHub [changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +:::info +一本面向有一定程式基礎,但缺乏刷題經驗的讀者的教科書和工具書。 +::: + +## 序 + +2019 年底,本書第一版在 GitHub 上正式發佈,反響非常熱烈。過去五年,作者累積了許多工作經驗,也愈發覺得本書存在許多錯誤與不完善之處。因此在 2024 年底,作者重新整理內容,發佈了第二版。 + +本書分為算法、數學和資料結構三大部分,共計十五個章節,詳細介紹了解 LeetCode 時常用的技巧。在第一版中,為了強行呼應 "101"(在英文中意為入門),作者將題目精簡至 101 道。但隨著面試題型愈加多樣化,第二版新增了一些重點題目,幫助讀者查漏補缺。在選題時,作者兼顧題目在面試中的出現頻率、學習難易度及泛用性。每章節後附有練習題,推薦讀者學習完後使用這些題目進行鞏固。 + +本書中的所有常規題目均附有 C++ 和 Python3 的解法。由於本書的目的並非教學 C++ 和 Python 語言,作者在行文時不會過多解釋語法細節,並會適當使用一些新 C++ 標準語法和 Pythonic 寫法。至 2024 年底,所有代碼均能在 LeetCode 正常運行,並且在易讀性的基礎上幾乎都是最快或最省空間的解法。 + +請謹記,解題只是提升面試和工作能力的一部分。在電腦科學的海洋中,值得探索的領域甚多,不建議將過多時間耗在解題上。成為優秀的電腦科學家,除了把解題作為入職的敲門磚,更應打好專業基礎、提升技能並了解最新技術動向。 + +本書由作者閒暇時間完成,可能存在錯誤或不完善之處。部分題目解釋可能不夠詳細或清楚,歡迎讀者至 GitHub 提 issue 修正,作者將加入您於鳴謝名單(見後記)。若有建議或疑問,請至作者個人網站聯繫,亦可通過郵件或 LinkedIn 傳訊,作者會儘快回復。 + +感謝 GitHub 用戶 CyC2018 的 LeetCode 題解,為作者早期整理內容提供了幫助。感謝 ElegantBook 提供的精美 LATEX 模板,使得作者能輕鬆將筆記變為專業的電子書。另外,第二版封面圖片為作者於 2024 年 7 月在舊金山金門大橋北方的 Sausalito 小鎮海邊拍攝,當時還買了一份超大杯冰淇淋,可惜太甜吃不下,只能作罷。 + +若本書對您有幫助,不妨支持作者! + + + +## 重要聲明 + +本書 GitHub 地址:[github.com/changgyhub/leetcode_101](https://github.com/changgyhub/leetcode_101) + +由於本書目的是分享與教學,本書永久免費,禁止任何營利性用途。歡迎以學術為目的的分享與傳閱。本書所有題目版權歸 LeetCode 官方所有,本書不展示任何付費會員專享題目內容或相關代碼。 + +## 簡介 + +打開 LeetCode 網站,若按題目類型分類,出現次數最多的包括數組、動態規劃、數學、字串、樹、雜湊表、深度優先搜索、二分搜尋、貪心算法、廣度優先搜索、雙指針等。本書涵蓋上述題型以及大多數流行題型,並依照類型分類與難易程度進行逐步講解。 + +第一大類為算法。本書從最簡單的貪心算法開始,逐漸進階至雙指針、二分搜尋、排序算法與搜索算法,最終講解難度較高的動態規劃與分治算法。 + +第二大類為數學,涵蓋純數學問題與計算機知識相關的位運算問題。這類問題多用於測試思維靈敏度,實際工作中較少使用,建議優先處理其他類型問題。 + +第三大類為資料結構,包括 C++ STL、Python3 自帶的資料結構、字串處理、鏈結串列、樹與圖。其中,鏈結串列為樹與圖的子集。最後亦介紹一些更複雜的資料結構,如經典的並查集與 LRU。 diff --git a/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/footer.json b/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/footer.json new file mode 100644 index 00000000..a3c09ca8 --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/footer.json @@ -0,0 +1,6 @@ +{ + "copyright": { + "message": "Copyright © 2024 Chang Gao. Built with Docusaurus.", + "description": "The footer copyright" + } +} diff --git a/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/navbar.json b/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/navbar.json new file mode 100644 index 00000000..6e59d8ef --- /dev/null +++ b/leetcode_101/i18n/zh-TW/docusaurus-theme-classic/navbar.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "LeetCode 101 - A Grinding Guide", + "description": "The title in the navbar" + }, + "logo.alt": { + "message": "My Site Logo", + "description": "The alt text of navbar logo" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + } +} diff --git a/leetcode_101/package-lock.json b/leetcode_101/package-lock.json new file mode 100644 index 00000000..c72e57fe --- /dev/null +++ b/leetcode_101/package-lock.json @@ -0,0 +1,18963 @@ +{ + "name": "leetcode-101", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "leetcode-101", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "^3.6.3", + "@docusaurus/preset-classic": "^3.6.3", + "@easyops-cn/docusaurus-search-local": "^0.46.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "rehype-katex": "^7.0.1", + "remark-math": "^6.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.6.3", + "@docusaurus/tsconfig": "^3.6.3", + "@docusaurus/types": "^3.6.3", + "typescript": "~5.6.2" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", + "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", + "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==", + "license": "MIT" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", + "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.15.0.tgz", + "integrity": "sha512-FaEM40iuiv1mAipYyiptP4EyxkJ8qHfowCpEeusdHUC4C7spATJYArD2rX3AxkVeREkDIgYEOuXcwKUbDCr7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", + "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", + "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.15.0.tgz", + "integrity": "sha512-IofrVh213VLsDkPoSKMeM9Dshrv28jhDlBDLRcVJQvlL8pzue7PEB1EZ4UoJFYS3NSn7JOcJ/V+olRQzXlJj1w==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.15.0.tgz", + "integrity": "sha512-bDDEQGfFidDi0UQUCbxXOCdphbVAgbVmxvaV75cypBTQkJ+ABx/Npw7LkFGw1FsoVrttlrrQbwjvUB6mLVKs/w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", + "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.15.0.tgz", + "integrity": "sha512-wu8GVluiZ5+il8WIRsGKu8VxMK9dAlr225h878GGtpTL6VBvwyJvAyLdZsfFIpY0iN++jiNb31q2C1PlPL+n/A==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.15.0.tgz", + "integrity": "sha512-Z32gEMrRRpEta5UqVQA612sLdoqY3AovvUPClDfMxYrbdDAebmGDVPtSogUba1FZ4pP5dx20D3OV3reogLKsRA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" + }, + "node_modules/@algolia/ingestion": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.15.0.tgz", + "integrity": "sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/logger-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", + "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==", + "license": "MIT" + }, + "node_modules/@algolia/logger-console": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", + "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", + "license": "MIT", + "dependencies": { + "@algolia/logger-common": "4.24.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.15.0.tgz", + "integrity": "sha512-QPrFnnGLMMdRa8t/4bs7XilPYnoUXDY8PMQJ1sf9ZFwhUysYYhQNX34/enoO0LBjpoOY6rLpha39YQEFbzgKyQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", + "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", + "license": "MIT", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.15.0.tgz", + "integrity": "sha512-Po/GNib6QKruC3XE+WKP1HwVSfCDaZcXu48kD+gwmtDlqHWKc7Bq9lrS0sNZ456rfCKhXksOmMfUs4wRM/Y96w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", + "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==", + "license": "MIT" + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.15.0.tgz", + "integrity": "sha512-rOZ+c0P7ajmccAvpeeNrUmEKoliYFL8aOR5qGW5pFq3oj3Iept7Y5mEtEsOBYsRt6qLnaXn4zUKf+N8nvJpcIw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.15.0.tgz", + "integrity": "sha512-b1jTpbFf9LnQHEJP5ddDJKE2sAlhYd7EVSOWgzo/27n/SfCoHfqD0VWntnWYD83PnOKvfe8auZ2+xCb0TXotrQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", + "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz", + "integrity": "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", + "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", + "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz", + "integrity": "sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.0.tgz", + "integrity": "sha512-X69PmFOrjTZfN5ijxtI8hZ9kRADFSLrmmQ6hgDJ272Il049WGKpDY64KhrFm/7rbWve0z81QepawzjkKlqkNGw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.6.tgz", + "integrity": "sha512-S/IjXqTHdpI4EtzGoNCHfqraXF37x12ZZHA1Lk7zoT5pm2lMjFuqhX/89L7dqX4CcMacKK+6ZCs5TmEGb/+wKw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz", + "integrity": "sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.6.tgz", + "integrity": "sha512-EcvXfC60cTIumzpsxWuvVjb7rsJEHPvqn3jeMEBUaE3JSc4FRuP7mEQ+1eicxWmIrs3FtzMH9gR3sgA5TH+ebQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.6.tgz", + "integrity": "sha512-jVKdJn4+JkASYGhyPO+Wa5WXSx1+oUgaXb3JsjJn/BlrtFh5zjocCY7pwWi0nuP24V1fY7glQsxEYcYNy0dMFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", + "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.5.tgz", + "integrity": "sha512-mi8R6dVfA2nDoKM3wcEi64I8vOYEgQVtVKCfmLHXupeLpACfGAided5ddMt5f+CnEodNu4DifuVwb0I6fQDGGQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.6.tgz", + "integrity": "sha512-0ke7fmXfc8H+kysZz246yjirAH6JFhyX9GTlyRnM0exHO80XcA9zeJpy5pOp5zo/AZiC/q5Pf+Hw7Pd6/uAoYA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.6.tgz", + "integrity": "sha512-Itrbx6SLUzsZ6Mz3VuOlxhbfuyLTogG5DwEF1V8dAi24iMuvQPIHd7Ti+pNDp7j6WixndJGZaoNR0f9VSzwuTg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.6.tgz", + "integrity": "sha512-927Pqy3a1uBP7U8sTfaNdZVB0mNXzIrJO/GZ8us9219q9n06gOqCdfZ0E6d1P66Fm0fYHvxfDbfcUuwAn5UwhQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", + "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", + "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz", + "integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", + "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz", + "integrity": "sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.5.tgz", + "integrity": "sha512-sdh5i5GToZOIAiwhdntRWv77QDtsxP2r2gXW/WbLSCoLr00KTq/yiF1qlQ5XX2+lmiFa8rATKMcbwl3oXDMNew==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz", + "integrity": "sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz", + "integrity": "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.6.tgz", + "integrity": "sha512-Hptoa0uX+XsNacFBCIQKTUBrFKDiplHan42X73EklG6XmQLG7/aIvxoNhvZ7PvOWMt67Pw3bIlUY2nD6p5vL8A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", + "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.1.tgz", + "integrity": "sha512-Ab/tF8/RXktQlFwVhiC70UNfpFQRhtE5fQQoP2pO+KCPGLsLdWFiOuHgSRtBOqEshCVAzR4H6o38nhvRZq8deA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.6.tgz", + "integrity": "sha512-yxP618Xb+ji1I624jILaYM62uEmZcmbdmFoZHoaThw896sq0vU39kqTTF+ZNic9XyPtPMvq0vyvbgmHaszq8xg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.0.tgz", + "integrity": "sha512-SLcc20Nujx/kqbSwDmj6oaXgpy3UjFhBy1sfcqPgDkHfOIfUtUVH7OXO+j7BU4v/At5s61N5ZX6shvgPwluhsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.5.tgz", + "integrity": "sha512-G6SJ6hZJkhxo6UZojVlLo14MohH4J5J7z8CRBrxxUYy9JuZiIqUo5TBYyDGcE0PLdzpg63a7mHSJz3VD+gMwqw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", + "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.5.tgz", + "integrity": "sha512-/YQThYkt5MLvAmVu7zxjhceCYlKrYddK6LEmK5I4ojlS6BmO9u2yO4+xjXzu2+NPYmHSTtP4NFSamBCMmJ1NJA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.0.tgz", + "integrity": "sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.0.tgz", + "integrity": "sha512-WnFK720+iwTVt94CxY3u+FgX6exb3BfN5kE9xUY6uuAH/9W/UFboBZFLlrw/zxFRHoHZCOXRtOylsXF+6LHI+Q==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.0", + "algoliasearch": "^5.12.0" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-analytics": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.15.0.tgz", + "integrity": "sha512-lho0gTFsQDIdCwyUKTtMuf9nCLwq9jOGlLGIeQGKDxXF7HbiAysFIu5QW/iQr1LzMgDyM9NH7K98KY+BiIFriQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-personalization": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.15.0.tgz", + "integrity": "sha512-LfaZqLUWxdYFq44QrasCDED5bSYOswpQjSiIL7Q5fYlefAAUO95PzBPKCfUhSwhb4rKxigHfDkd81AvEicIEoA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/recommend": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.15.0.tgz", + "integrity": "sha512-5eupMwSqMLDObgSMF0XG958zR6GJP3f7jHDQ3/WlzCM9/YIJiWIUoJFGsko9GYsA5xbLDHE/PhWtq4chcCdaGQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/algoliasearch": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.15.0.tgz", + "integrity": "sha512-Yf3Swz1s63hjvBVZ/9f2P1Uu48GjmjCN+Esxb6MAONMGtZB1fRX8/S1AhUTtsuTlcGovbYLxpHgc7wEzstDZBw==", + "license": "MIT", + "dependencies": { + "@algolia/client-abtesting": "5.15.0", + "@algolia/client-analytics": "5.15.0", + "@algolia/client-common": "5.15.0", + "@algolia/client-insights": "5.15.0", + "@algolia/client-personalization": "5.15.0", + "@algolia/client-query-suggestions": "5.15.0", + "@algolia/client-search": "5.15.0", + "@algolia/ingestion": "1.15.0", + "@algolia/monitoring": "1.15.0", + "@algolia/recommend": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.6.3.tgz", + "integrity": "sha512-7dW9Hat9EHYCVicFXYA4hjxBY38+hPuCURL8oRF9fySRm7vzNWuEOghA1TXcykuXZp0HLG2td4RhDxCvGG7tNw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/runtime-corejs3": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.6.3.tgz", + "integrity": "sha512-47JLuc8D4wA+6VOvmMd5fUC9rFppBQpQOnxDYiVXffm/DeV/wmm3sbpNd5Y+O+G2+nevLTRnvCm/qyancv0Y3A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.6.3", + "@docusaurus/cssnano-preset": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.2", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.1", + "null-loader": "^4.0.1", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "postcss-preset-env": "^10.1.0", + "react-dev-utils": "^12.0.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^6.0.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.6.3.tgz", + "integrity": "sha512-xL7FRY9Jr5DWqB6pEnqgKqcMPJOX5V0pgWXi5lCiih11sUBmcFKM7c3+GyxcVeeWFxyYSDP3grLTWqJoP4P9Vw==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.6.3", + "@docusaurus/bundler": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.6", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^4.15.2", + "webpack-merge": "^6.0.1" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.3.tgz", + "integrity": "sha512-qP7SXrwZ+23GFJdPN4aIHQrZW+oH/7tzwEuc/RNL0+BdZdmIjYQqUxdXsjE4lFxLNZjj0eUrSNYIS6xwfij+5Q==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.4.38", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.6.3.tgz", + "integrity": "sha512-xSubJixcNyMV9wMV4q0s47CBz3Rlc5jbcCCuij8pfQP8qn/DIpt0ks8W6hQWzHAedg/J/EwxxUOUrnEoKzJo8g==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.6.3.tgz", + "integrity": "sha512-3iJdiDz9540ppBseeI93tWTDtUGVkxzh59nMq4ignylxMuXBLK8dFqVeaEor23v1vx6TrGKZ2FuLaTB+U7C0QQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.3.tgz", + "integrity": "sha512-MjaXX9PN/k5ugNvfRZdWyKWq4FsrhN4LEXaj0pEmMebJuBNlFeGyKQUa9DRhJHpadNaiMLrbo9m3U7Ig5YlsZg==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.6.3", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.3.tgz", + "integrity": "sha512-k0ogWwwJU3pFRFfvW1kRVHxzf2DutLGaaLjAnHVEU6ju+aRP0Z5ap/13DHyPOfHeE4WKpn/M0TqjdwZAcY3kAw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "cheerio": "1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.3.tgz", + "integrity": "sha512-r2wS8y/fsaDcxkm20W5bbYJFPzdWdEaTWVYjNxlHlcmX086eqQR1Fomlg9BHTJ0dLXPzAlbC8EN4XqMr3QzNCQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.3.tgz", + "integrity": "sha512-eHrmTgjgLZsuqfsYr5X2xEwyIcck0wseSofWrjTwT9FLOWp+KDmMAuVK+wRo7sFImWXZk3oV/xX/g9aZrhD7OA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.6.3.tgz", + "integrity": "sha512-zB9GXfIZNPRfzKnNjU6xGVrqn9bPXuGhpjgsuc/YtcTDjnjhasg38NdYd5LEqXex5G/zIorQgWB3n6x/Ut62vQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^1.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.3.tgz", + "integrity": "sha512-rCDNy1QW8Dag7nZq67pcum0bpFLrwvxJhYuVprhFh8BMBDxV0bY+bAkGHbSf68P3Bk9C3hNOAXX1srGLIDvcTA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.3.tgz", + "integrity": "sha512-+OyDvhM6rqVkQOmLVkQWVJAizEEfkPzVWtIHXlWPOCFGK9X4/AWeBSrU0WG4iMg9Z4zD4YDRrU+lvI4s6DSC+w==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.3.tgz", + "integrity": "sha512-1M6UPB13gWUtN2UHX083/beTn85PlRI9ABItTl/JL1FJ5dJTWWFXXsHf9WW/6hrVwthwTeV/AGbGKvLKV+IlCA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.3.tgz", + "integrity": "sha512-94qOO4M9Fwv9KfVQJsgbe91k+fPJ4byf1L3Ez8TUa6TAFPo/BrLwQ80zclHkENlL1824TuxkcMKv33u6eydQCg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.6.3.tgz", + "integrity": "sha512-VHSYWROT3flvNNI1SrnMOtW1EsjeHNK9dhU6s9eY5hryZe79lUqnZJyze/ymDe2LXAqzyj6y5oYvyBoZZk6ErA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/plugin-content-blog": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/plugin-content-pages": "3.6.3", + "@docusaurus/plugin-debug": "3.6.3", + "@docusaurus/plugin-google-analytics": "3.6.3", + "@docusaurus/plugin-google-gtag": "3.6.3", + "@docusaurus/plugin-google-tag-manager": "3.6.3", + "@docusaurus/plugin-sitemap": "3.6.3", + "@docusaurus/theme-classic": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-search-algolia": "3.6.3", + "@docusaurus/types": "3.6.3" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.6.3.tgz", + "integrity": "sha512-1RRLK1tSArI2c00qugWYO3jRocjOZwGF1mBzPPylDVRwWCS/rnWWR91ChdbbaxIupRJ+hX8ZBYrwr5bbU0oztQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/plugin-content-blog": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/plugin-content-pages": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-translations": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.6.3.tgz", + "integrity": "sha512-b8ZkhczXHDxWWyvz+YJy4t/PlPbEogTTbgnHoflYnH7rmRtyoodTsu8WVM12la5LmlMJBclBXFl29OH8kPE7gg==", + "license": "MIT", + "dependencies": { + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.3.tgz", + "integrity": "sha512-rt+MGCCpYgPyWCGXtbxlwFbTSobu15jWBTPI2LHsHNa5B0zSmOISX6FWYAPt5X1rNDOqMGM0FATnh7TBHRohVA==", + "license": "MIT", + "dependencies": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-translations": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.6.3.tgz", + "integrity": "sha512-Gb0regclToVlngSIIwUCtBMQBq48qVUaN1XQNKW4XwlsgUyk0vP01LULdqbem7czSwIeBAFXFoORJ0RPX7ht/w==", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/tsconfig": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.6.3.tgz", + "integrity": "sha512-1pT/rTrRpMV15E4tJH95W5PrjboMn5JkKF+Ys8cTjMegetiXjs0gPFOSDA5hdTlberKQLDO50xPjMJHondLuzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docusaurus/types": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.6.3.tgz", + "integrity": "sha512-xD9oTGDrouWzefkhe9ogB2fDV96/82cRpNGx2HIvI5L87JHNhQVIWimQ/3JIiiX/TEd5S9s+VO6FFguwKNRVow==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.6.3.tgz", + "integrity": "sha512-0R/FR3bKVl4yl8QwbL4TYFfR+OXBRpVUaTJdENapBGR3YMwfM6/JnhGilWQO8AOwPJGtGoDK7ib8+8UF9f3OZQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@svgr/webpack": "^8.1.0", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.6.3.tgz", + "integrity": "sha512-v4nKDaANLgT3pMBewHYEMAl/ufY0LkXao1QkFWzI5huWFOmNQ2UFzv2BiKeHX5Ownis0/w6cAyoxPhVdDonlSQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.6.3.tgz", + "integrity": "sha512-bhEGGiN5BE38h21vjqD70Gxg++j+PfYVddDUE5UFvLDup68QOcpD33CLr+2knPorlxRbEaNfz6HQDUMQ3HuqKw==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@easyops-cn/autocomplete.js": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", + "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "immediate": "^3.2.3" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.46.1.tgz", + "integrity": "sha512-kgenn5+pctVlJg8s1FOAm9KuZLRZvkBTMMGJvTTcvNTmnFIHVVYzYfA2Eg+yVefzsC8/cSZGKKJ0kLf8I+mQyw==", + "license": "MIT", + "dependencies": { + "@docusaurus/plugin-content-docs": "^2 || ^3", + "@docusaurus/theme-translations": "^2 || ^3", + "@docusaurus/utils": "^2 || ^3", + "@docusaurus/utils-common": "^2 || ^3", + "@docusaurus/utils-validation": "^2 || ^3", + "@easyops-cn/autocomplete.js": "^0.38.1", + "@node-rs/jieba": "^1.6.0", + "cheerio": "^1.0.0", + "clsx": "^1.1.1", + "comlink": "^4.4.2", + "debug": "^4.2.0", + "fs-extra": "^10.0.0", + "klaw-sync": "^6.0.0", + "lunr": "^2.3.9", + "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@docusaurus/theme-common": "^2 || ^3", + "react": "^16.14.0 || ^17 || ^18", + "react-dom": "^16.14.0 || 17 || ^18" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/cheerio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18.17" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", + "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", + "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", + "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.5.tgz", + "integrity": "sha512-kwUxR7J9WLutBbulqg1dfOrMTwhMdXLdcGUhcbCcGwnPLt3gz19uHVdwH1syKVDbE022ZS2vZxOWflFLS0YTjw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@node-rs/jieba": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.10.4.tgz", + "integrity": "sha512-GvDgi8MnBiyWd6tksojej8anIx18244NmIOc1ovEw8WKNUejcccLfyu8vj66LWSuoZuKILVtNsOy4jvg3aoxIw==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/jieba-android-arm-eabi": "1.10.4", + "@node-rs/jieba-android-arm64": "1.10.4", + "@node-rs/jieba-darwin-arm64": "1.10.4", + "@node-rs/jieba-darwin-x64": "1.10.4", + "@node-rs/jieba-freebsd-x64": "1.10.4", + "@node-rs/jieba-linux-arm-gnueabihf": "1.10.4", + "@node-rs/jieba-linux-arm64-gnu": "1.10.4", + "@node-rs/jieba-linux-arm64-musl": "1.10.4", + "@node-rs/jieba-linux-x64-gnu": "1.10.4", + "@node-rs/jieba-linux-x64-musl": "1.10.4", + "@node-rs/jieba-wasm32-wasi": "1.10.4", + "@node-rs/jieba-win32-arm64-msvc": "1.10.4", + "@node-rs/jieba-win32-ia32-msvc": "1.10.4", + "@node-rs/jieba-win32-x64-msvc": "1.10.4" + } + }, + "node_modules/@node-rs/jieba-android-arm-eabi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.10.4.tgz", + "integrity": "sha512-MhyvW5N3Fwcp385d0rxbCWH42kqDBatQTyP8XbnYbju2+0BO/eTeCCLYj7Agws4pwxn2LtdldXRSKavT7WdzNA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-android-arm64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.10.4.tgz", + "integrity": "sha512-XyDwq5+rQ+Tk55A+FGi6PtJbzf974oqnpyCcCPzwU3QVXJCa2Rr4Lci+fx8oOpU4plT3GuD+chXMYLsXipMgJA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-arm64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.10.4.tgz", + "integrity": "sha512-G++RYEJ2jo0rxF9626KUy90wp06TRUjAsvY/BrIzEOX/ingQYV/HjwQzNPRR1P1o32a6/U8RGo7zEBhfdybL6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-x64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.10.4.tgz", + "integrity": "sha512-MmDNeOb2TXIZCPyWCi2upQnZpPjAxw5ZGEj6R8kNsPXVFALHIKMa6ZZ15LCOkSTsKXVC17j2t4h+hSuyYb6qfQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-freebsd-x64": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.10.4.tgz", + "integrity": "sha512-/x7aVQ8nqUWhpXU92RZqd333cq639i/olNpd9Z5hdlyyV5/B65LLy+Je2B2bfs62PVVm5QXRpeBcZqaHelp/bg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm-gnueabihf": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.10.4.tgz", + "integrity": "sha512-crd2M35oJBRLkoESs0O6QO3BBbhpv+tqXuKsqhIG94B1d02RVxtRIvSDwO33QurxqSdvN9IeSnVpHbDGkuXm3g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-gnu": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.10.4.tgz", + "integrity": "sha512-omIzNX1psUzPcsdnUhGU6oHeOaTCuCjUgOA/v/DGkvWC1jLcnfXe4vdYbtXMh4XOCuIgS1UCcvZEc8vQLXFbXQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-musl": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.10.4.tgz", + "integrity": "sha512-Y/tiJ1+HeS5nnmLbZOE+66LbsPOHZ/PUckAYVeLlQfpygLEpLYdlh0aPpS5uiaWMjAXYZYdFkpZHhxDmSLpwpw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-gnu": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.10.4.tgz", + "integrity": "sha512-WZO8ykRJpWGE9MHuZpy1lu3nJluPoeB+fIJJn5CWZ9YTVhNDWoCF4i/7nxz1ntulINYGQ8VVuCU9LD86Mek97g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-musl": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.10.4.tgz", + "integrity": "sha512-uBBD4S1rGKcgCyAk6VCKatEVQb6EDD5I40v/DxODi5CuZVCANi9m5oee/MQbAoaX7RydA2f0OSCE9/tcwXEwUg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-wasm32-wasi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-wasm32-wasi/-/jieba-wasm32-wasi-1.10.4.tgz", + "integrity": "sha512-Y2umiKHjuIJy0uulNDz9SDYHdfq5Hmy7jY5nORO99B4pySKkcrMjpeVrmWXJLIsEKLJwcCXHxz8tjwU5/uhz0A==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@node-rs/jieba-win32-arm64-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.10.4.tgz", + "integrity": "sha512-nwMtViFm4hjqhz1it/juQnxpXgqlGltCuWJ02bw70YUDMDlbyTy3grCJPpQQpueeETcALUnTxda8pZuVrLRcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-ia32-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.10.4.tgz", + "integrity": "sha512-DCAvLx7Z+W4z5oKS+7vUowAJr0uw9JBw8x1Y23Xs/xMA4Em+OOSiaF5/tCJqZUCJ8uC4QeImmgDFiBqGNwxlyA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-x64-msvc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.10.4.tgz", + "integrity": "sha512-+sqemSfS1jjb+Tt7InNbNzrRh1Ua3vProVvC4BZRPg010/leCbGFFiQHpzcPRfpxAXZrzG5Y0YBTsPzN/I4yHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "license": "MIT" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", + "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", + "license": "MIT", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-account": "4.24.0", + "@algolia/client-analytics": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-personalization": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/recommend": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.22.5.tgz", + "integrity": "sha512-lWvhdnc+aKOKx8jyA3bsdEgHzm/sglC4cYdMG4xSQyRiPLJVJtH/IVYZG3Hp6PkTEhQqhyVYkeP9z2IlcHJsWw==", + "license": "MIT", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "license": "MIT" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/comlink": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz", + "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==", + "license": "Apache-2.0" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.1.tgz", + "integrity": "sha512-EOcoyJt+OsuKfCADgLT7gADZI5jMzIe/AeI6MeAYKiFBDmNmM7kk46DtSfMj5AohUJisqVzopBpnQTlvbyaBWg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.1.tgz", + "integrity": "sha512-KwEPys7lNsC8OjASI8RrmwOYYDcm0JOW9zQhcV83ejYcQkirTEyeAGui8aO2F5PiS6SLpxuTzl6qlMElIdsgIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.55", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz", + "integrity": "sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "license": "MIT" + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.2.1.tgz", + "integrity": "sha512-Vt2UOjyPbNQQgT5eJh+K5aATti0OjCIAGc9SgMdOFYbohuifsWclR74l0iZTJwePMgWYdX1hlVS+dedH9XV8kw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-dom": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.0.tgz", + "integrity": "sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg==", + "license": "ISC", + "dependencies": { + "@types/hast": "^3.0.0", + "hastscript": "^8.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree/node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, + "node_modules/hast-util-to-estree/node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", + "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "license": "MIT" + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.45", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", + "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "license": "MIT" + }, + "node_modules/lunr-languages": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.14.0.tgz", + "integrity": "sha512-hWUAb2KqM3L7J5bcrngszzISY4BxrXn/Xhbb9TTCJYEGqlR1nG67/M14sp09+PTIRklobrn57IAxcdcO/ZFyNA==", + "license": "MPL-1.1" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "license": "MIT" + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-math/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-math/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/null-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/null-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.6.tgz", + "integrity": "sha512-wLXvm8RmLs14Z2nVpB4CWlnvaWPRcOZFltJSlcbYwSJ1EDZKsKDhPKIMecCnuU054KSmlmubkqczmm6qBPCBhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz", + "integrity": "sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz", + "integrity": "sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz", + "integrity": "sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", + "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.6.tgz", + "integrity": "sha512-HPwvsoK7C949vBZ+eMyvH2cQeMr3UREoHvbtra76/UhDuiViZH6pir+z71UaJQohd7VDSVUdR6TkWYKExEc9aQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", + "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", + "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", + "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", + "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.1.tgz", + "integrity": "sha512-wqqsnBFD6VIwcHHRbhjTOcOi4qRVlB26RwSr0ordPj7OubRRxdWebv/aLjKLRR8zkZrbxZyuus03nOIgC5elMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-cascade-layers": "^5.0.1", + "@csstools/postcss-color-function": "^4.0.6", + "@csstools/postcss-color-mix-function": "^3.0.6", + "@csstools/postcss-content-alt-text": "^2.0.4", + "@csstools/postcss-exponential-functions": "^2.0.5", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.6", + "@csstools/postcss-gradients-interpolation-method": "^5.0.6", + "@csstools/postcss-hwb-function": "^4.0.6", + "@csstools/postcss-ic-unit": "^4.0.0", + "@csstools/postcss-initial": "^2.0.0", + "@csstools/postcss-is-pseudo-class": "^5.0.1", + "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.3", + "@csstools/postcss-media-minmax": "^2.0.5", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.0", + "@csstools/postcss-oklab-function": "^4.0.6", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-random-function": "^1.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.6", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.0", + "@csstools/postcss-stepped-value-functions": "^4.0.5", + "@csstools/postcss-text-decoration-shorthand": "^4.0.1", + "@csstools/postcss-trigonometric-functions": "^4.0.5", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.1", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.2.1", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.6", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.5", + "postcss-custom-properties": "^14.0.4", + "postcss-custom-selectors": "^8.0.4", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.0", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.6", + "postcss-logical": "^8.0.0", + "postcss-nesting": "^13.0.1", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "license": "MIT", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.0.tgz", + "integrity": "sha512-327BsVCD/unU4CNLZTWVHyUHKnsqcvj2qbPlQ8MiBE2eq2rgctjigPA1Gp9HLF83kZ20zNN6jgizHJeEsyFYOw==", + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", + "license": "MIT" + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-json-view-lite": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz", + "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "license": "MIT" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz", + "integrity": "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtl-detect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", + "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==", + "license": "BSD-3-Clause" + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "license": "BSD-3-Clause", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/sitemap": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz", + "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "license": "MIT", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "license": "MIT" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", + "integrity": "sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "consola": "^3.2.3", + "figures": "^3.2.0", + "markdown-table": "^2.0.0", + "pretty-time": "^1.1.0", + "std-env": "^3.7.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/webpackbar/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/webpackbar/node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpackbar/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpackbar/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/leetcode_101/package.json b/leetcode_101/package.json new file mode 100644 index 00000000..669ca3ca --- /dev/null +++ b/leetcode_101/package.json @@ -0,0 +1,50 @@ +{ + "name": "leetcode-101", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "typecheck": "tsc" + }, + "dependencies": { + "@docusaurus/core": "^3.6.3", + "@docusaurus/preset-classic": "^3.6.3", + "@easyops-cn/docusaurus-search-local": "^0.46.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "rehype-katex": "^7.0.1", + "remark-math": "^6.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.6.3", + "@docusaurus/tsconfig": "^3.6.3", + "@docusaurus/types": "^3.6.3", + "typescript": "~5.6.2" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/leetcode_101/sidebars.ts b/leetcode_101/sidebars.ts new file mode 100644 index 00000000..574ed394 --- /dev/null +++ b/leetcode_101/sidebars.ts @@ -0,0 +1,33 @@ +import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"; + +// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) + +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +const sidebars: SidebarsConfig = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{ type: "autogenerated", dirName: "." }], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +export default sidebars; diff --git a/leetcode_101/src/components/HomepageFeatures/index.tsx b/leetcode_101/src/components/HomepageFeatures/index.tsx new file mode 100644 index 00000000..50a9e6f4 --- /dev/null +++ b/leetcode_101/src/components/HomepageFeatures/index.tsx @@ -0,0 +1,70 @@ +import clsx from 'clsx'; +import Heading from '@theme/Heading'; +import styles from './styles.module.css'; + +type FeatureItem = { + title: string; + Svg: React.ComponentType>; + description: JSX.Element; +}; + +const FeatureList: FeatureItem[] = [ + { + title: 'Easy to Use', + Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + description: ( + <> + Docusaurus was designed from the ground up to be easily installed and + used to get your website up and running quickly. + + ), + }, + { + title: 'Focus on What Matters', + Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + description: ( + <> + Docusaurus lets you focus on your docs, and we'll do the chores. Go + ahead and move your docs into the docs directory. + + ), + }, + { + title: 'Powered by React', + Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + description: ( + <> + Extend or customize your website layout by reusing React. Docusaurus can + be extended while reusing the same header and footer. + + ), + }, +]; + +function Feature({title, Svg, description}: FeatureItem) { + return ( +
+
+ +
+
+ {title} +

{description}

+
+
+ ); +} + +export default function HomepageFeatures(): JSX.Element { + return ( +
+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/leetcode_101/src/components/HomepageFeatures/styles.module.css b/leetcode_101/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 00000000..b248eb2e --- /dev/null +++ b/leetcode_101/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 200px; + width: 200px; +} diff --git a/leetcode_101/src/components/MDXProviderWrapper.tsx b/leetcode_101/src/components/MDXProviderWrapper.tsx new file mode 100644 index 00000000..7091c43b --- /dev/null +++ b/leetcode_101/src/components/MDXProviderWrapper.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { MDXProvider } from "@mdx-js/react"; + +const components = { + Tabs, + TabItem, +}; + +const MDXProviderWrapper: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + return {children}; +}; + +export default MDXProviderWrapper; diff --git a/leetcode_101/src/css/custom.css b/leetcode_101/src/css/custom.css new file mode 100644 index 00000000..2bc6a4cf --- /dev/null +++ b/leetcode_101/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #2e8555; + --ifm-color-primary-dark: #29784c; + --ifm-color-primary-darker: #277148; + --ifm-color-primary-darkest: #205d3b; + --ifm-color-primary-light: #33925d; + --ifm-color-primary-lighter: #359962; + --ifm-color-primary-lightest: #3cad6e; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/leetcode_101/src/pages/index.module.css b/leetcode_101/src/pages/index.module.css new file mode 100644 index 00000000..9f71a5da --- /dev/null +++ b/leetcode_101/src/pages/index.module.css @@ -0,0 +1,23 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/leetcode_101/src/pages/markdown-page.md b/leetcode_101/src/pages/markdown-page.md new file mode 100644 index 00000000..9756c5b6 --- /dev/null +++ b/leetcode_101/src/pages/markdown-page.md @@ -0,0 +1,7 @@ +--- +title: Markdown page example +--- + +# Markdown page example + +You don't need React to write simple standalone pages. diff --git a/leetcode_101/src/theme/Root.tsx b/leetcode_101/src/theme/Root.tsx new file mode 100644 index 00000000..771fa55a --- /dev/null +++ b/leetcode_101/src/theme/Root.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import MDXProviderWrapper from "../components/MDXProviderWrapper"; + +function Root({ children }: { children: React.ReactNode }) { + return {children}; +} + +export default Root; diff --git a/leetcode_101/static/.nojekyll b/leetcode_101/static/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/leetcode_101/static/img/docusaurus-social-card.jpg b/leetcode_101/static/img/docusaurus-social-card.jpg new file mode 100644 index 00000000..ffcb4482 Binary files /dev/null and b/leetcode_101/static/img/docusaurus-social-card.jpg differ diff --git a/leetcode_101/static/img/docusaurus.png b/leetcode_101/static/img/docusaurus.png new file mode 100644 index 00000000..f458149e Binary files /dev/null and b/leetcode_101/static/img/docusaurus.png differ diff --git a/leetcode_101/static/img/favicon.ico b/leetcode_101/static/img/favicon.ico new file mode 100644 index 00000000..c01d54bc Binary files /dev/null and b/leetcode_101/static/img/favicon.ico differ diff --git a/leetcode_101/static/img/logo.png b/leetcode_101/static/img/logo.png new file mode 100644 index 00000000..4743e5fb Binary files /dev/null and b/leetcode_101/static/img/logo.png differ diff --git a/leetcode_101/static/img/logo.svg b/leetcode_101/static/img/logo.svg new file mode 100644 index 00000000..9db6d0d0 --- /dev/null +++ b/leetcode_101/static/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/leetcode_101/static/img/undraw_docusaurus_mountain.svg b/leetcode_101/static/img/undraw_docusaurus_mountain.svg new file mode 100644 index 00000000..af961c49 --- /dev/null +++ b/leetcode_101/static/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/leetcode_101/static/img/undraw_docusaurus_react.svg b/leetcode_101/static/img/undraw_docusaurus_react.svg new file mode 100644 index 00000000..94b5cf08 --- /dev/null +++ b/leetcode_101/static/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/leetcode_101/static/img/undraw_docusaurus_tree.svg b/leetcode_101/static/img/undraw_docusaurus_tree.svg new file mode 100644 index 00000000..d9161d33 --- /dev/null +++ b/leetcode_101/static/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/leetcode_101/tsconfig.json b/leetcode_101/tsconfig.json new file mode 100644 index 00000000..314eab8a --- /dev/null +++ b/leetcode_101/tsconfig.json @@ -0,0 +1,7 @@ +{ + // This file is not used in compilation. It is here just for a nice editor experience. + "extends": "@docusaurus/tsconfig", + "compilerOptions": { + "baseUrl": "." + } +}