Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/quarter 1 #800

Merged
merged 8 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions leetcode-docs/easy/108-sorted-array-to-bst.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ keywords:

:::info 示例

输入: nums = [-10, -3, 0, 5, 9]
输入: `nums = [-10, -3, 0, 5, 9]`

输出:

Expand Down Expand Up @@ -49,15 +49,15 @@ var sortedArrayToBST = function (nums) {
return buildBST(nums, 0, nums.length - 1)
}

var buildBST = (nums, start, end) => {
// 不可能出现 start > end
if (start > end) return null
var buildBST = (nums, startIdx, endIdx) => {
// 不可能出现 startIdx > endIdx
if (startIdx > endIdx) return null

const midIndex = (start + end) >>> 1 // 求中间索引
const root = new TreeNode(nums[midIndex]) // 构建当前节点
const midIdx = (startIdx + endIdx) >>> 1 // 求中间索引
const root = new TreeNode(nums[midIdx]) // 构建当前节点

root.left = buildBST(nums, start, midIndex - 1) // 构建左子树
root.right = buildBST(nums, midIndex + 1, end) // 构建右子树
root.left = buildBST(nums, startIdx, midIdx - 1) // 构建左子树
root.right = buildBST(nums, midIdx + 1, endIdx) // 构建右子树

return root
}
Expand Down
32 changes: 19 additions & 13 deletions leetcode-docs/easy/111-min-depth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ sidebar_label: 111. 二叉树的最小深度
15 7
```

输入: root = [3, 9, 20, null, null, 15, 7]
输入: `root = [3, 9, 20, null, null, 15, 7]`

输出: 2
:::

## 题解

### 深度优先遍历
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

1. 如果 root 都没有, 直接返回 0
2. 如果有 root, 但 root 没有叶子节点, 返回 1
3. 对于其他情况: 如果存在左叶子节点, 就一直往左递归, 并计算最小深度; 如果存在右叶子节点, 就一直往右递归, 并计算最小深度.

时间复杂度: O(n)
<Tabs>
<TabItem value="深度优先遍历" label="深度优先遍历" default>

空间复杂度: O(logn)
1. 如果 `root` 都没有, 直接返回 `0`
2. 如果有 `root`, 但 `root` 没有叶子节点, 返回 `1`
3. 对于其他情况: 如果存在左叶子节点, 就一直往左递归, 并计算最小深度; 如果存在右叶子节点, 就一直往右递归, 并计算最小深度.

```ts
/**
Expand Down Expand Up @@ -70,13 +70,13 @@ var minDepth = function (root) {
}
```

### 广度优先遍历

广度优先遍历的核心思想是**队列**, 具体思想可以看 [深度/广度优先遍历](/algorithm-design/dfs-bfs), 该题的关键在于**当某个节点没有子节点了, 那它就是最小的深度**, 其余的就是广度优先遍历的基本套路了, 这里不再赘述.
- 时间复杂度: `O(n)`
- 空间复杂度: `O(logn)`

时间复杂度: O(n)
</TabItem>
<TabItem value="广度优先遍历" label="广度优先遍历">

空间复杂度: O(n)
广度优先遍历的核心思想是**队列**, 具体思想可以看 [深度/广度优先遍历](/algorithm-design/dfs-bfs), 该题的关键在于**当某个节点没有子节点了, 那它就是最小的深度**, 其余的就是广度优先遍历的基本套路了, 这里不再赘述.

```ts
var minDepth = function (root) {
Expand Down Expand Up @@ -111,3 +111,9 @@ var minDepth = function (root) {
return depth
}
```

- 时间复杂度: `O(n)`
- 空间复杂度: `O(n)`

</TabItem>
</Tabs>
2 changes: 1 addition & 1 deletion leetcode-docs/easy/112-has-path-sum.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ keywords:
* @return {boolean}
*/
var hasPathSum = function (root, targetSum) {
if (root === null) return
if (root === null) return false

// 到了叶子结点了, 且值等于 targetSum
if (!root.left && !root.right && root.val === targetSum) {
Expand Down
1 change: 0 additions & 1 deletion leetcode-docs/easy/13-roman-to-int.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ pub fn roman_to_int(s: String) -> i32 {
})
.0
}

```

</TabItem>
Expand Down
14 changes: 8 additions & 6 deletions leetcode-docs/easy/14-longest-common-prefix.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ sidebar_label: 14. 最长公共前缀

## 题解

先假设第一个单词为 `prefix`, 如果 `strs` 里所有单词的前缀都是 `prefix`, 那就返回之;
否则将 `prefix` 的最后一位删掉继续循环, 直到找出前缀.
先假设第一个单词为 `prefix`, 如果 `strs` 里所有单词的前缀都是 `prefix`, 那就返回之; 否则将 `prefix` 的最后一位删掉继续循环, 直到找出前缀.

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Expand All @@ -40,13 +39,14 @@ import TabItem from '@theme/TabItem'
* @return {string}
*/
var longestCommonPrefix = function (strs) {
strs.sort((a, b) => a.length - b.length)
let prefix = strs[0]
let hasFound = false
let flag = false

while (!hasFound) {
hasFound = strs.every((str) => str.startsWith(prefix))
while (!flag) {
flag = strs.every((str) => str.startsWith(prefix))

if (!hasFound) {
if (!flag) {
prefix = prefix.slice(0, -1)
}
}
Expand All @@ -60,6 +60,8 @@ var longestCommonPrefix = function (strs) {

```rust
pub fn longest_common_prefix(strs: Vec<String>) -> String {
let mut strs = strs;
strs.sort();
let mut prefix: &str = &strs[0];
let mut has_found = false;

Expand Down
2 changes: 1 addition & 1 deletion leetcode-docs/easy/20-is-valid.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var isValid = function (s) {
const n = s.length

// 如果是奇数, 一定不是合法的括号
if (n % 2 == 1) return false
if (n % 2 === 1) return false

const stack = []

Expand Down
3 changes: 2 additions & 1 deletion leetcode-docs/hard/10-is-match.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ keywords:
- [44. 通配符匹配](/leetcode/hard/44-is-match)
- [72. 编辑距离](/leetcode/hard/72-min-distance)
- [115. 不同的子序列](/leetcode/hard/115-num-distinct)
- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq)
- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance)
- [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence)

Expand Down Expand Up @@ -111,7 +112,7 @@ var isMatch = function (s, p) {
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
// 字母匹配上了, 或者 p 此时为 . 可能任意匹配, 状态从前一个转移过来即可
if (p[j - 1] === s[i - 1] || p[j - 1] === '.') {
if (s[i - 1] === p[j - 1] || p[j - 1] === '.') {
dp[i][j] = dp[i - 1][j - 1]
// 如果遇到 *, 需要关注 * 前面那个
} else if (p[j - 1] === '*') {
Expand Down
1 change: 1 addition & 0 deletions leetcode-docs/hard/115-num-distinct.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ keywords:
- [10. 正则表达式匹配](/leetcode/hard/10-is-match)
- [44. 通配符匹配](/leetcode/hard/44-is-match)
- [72. 编辑距离](/leetcode/hard/72-min-distance)
- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq)
- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance)
- [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence)

Expand Down
1 change: 1 addition & 0 deletions leetcode-docs/hard/23-merge-k-lists.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ var mergeKLists = function (lists) {
* @param {ListNode} l2
* @return {ListNode}
*/
// 这个就是 21 题原题
var mergeTwoLists = function (l1, l2) {
const dummy = new ListNode(-1)
let curr = dummy
Expand Down
13 changes: 6 additions & 7 deletions leetcode-docs/hard/25-reverse-k-group.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,14 @@ var reverseKGroup = function (head, k) {
* @return {ListNode}
*/
var reverse = function (a, b) {
let prev = null,
head = a
let prev = null

// 在 a, b 区间翻转
while (head !== b) {
const temp = head.next
head.next = prev
prev = head
head = temp
while (a !== b) {
const tmp = a.next
a.next = prev
prev = a
a = tmp
}

return prev
Expand Down
4 changes: 2 additions & 2 deletions leetcode-docs/hard/30-find-substring.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ sidebar_label: 30. 串联所有单词的子串

:::note 提示:

- `1 <= s.length <= 104`
- `1 <= s.length <= 10⁴`
- `1 <= words.length <= 5000`
- `1 <= words[i].length <= 30`
- `words[i]` 和 `s` 由小写英文字母组成
Expand Down Expand Up @@ -94,7 +94,7 @@ var findSubstring = function (s, words) {

// 声明一个新的哈希表 subMap, 记录 subStr 中每 w 个小字符串
const subMap = new Map()
for (let j = 0; j < n * w; i += w) {
for (let j = 0; j < n * w; j += w) {
const sub = subStr.slice(j, j + w)

// 如果 words 中都没有子字符串, 可以提前终止
Expand Down
1 change: 1 addition & 0 deletions leetcode-docs/hard/44-is-match.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ keywords:
- [10. 正则表达式匹配](/leetcode/hard/10-is-match)
- [72. 编辑距离](/leetcode/hard/72-min-distance)
- [115. 不同的子序列](/leetcode/hard/115-num-distinct)
- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq)
- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance)
- [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence)

Expand Down
1 change: 1 addition & 0 deletions leetcode-docs/hard/72-min-distance.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ keywords:
- [10. 正则表达式匹配](/leetcode/hard/10-is-match)
- [44. 通配符匹配](/leetcode/hard/44-is-match)
- [115. 不同的子序列](/leetcode/hard/115-num-distinct)
- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq)
- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance)
- [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence)

Expand Down
59 changes: 21 additions & 38 deletions leetcode-docs/hard/76-min-window.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,59 +65,42 @@ import TabItem from '@theme/TabItem'
* @return {string}
*/
var minWindow = function (s, t) {
let res = ''
let minStr = ''

const needMap = new Map()
for (const letter of t) {
if (needMap.has(letter)) {
needMap.set(letter, needMap.get(letter) + 1)
} else {
needMap.set(letter, 1)
}
for (const ch of t) {
needMap.set(ch, needMap.has(ch) ? needMap.get(ch) + 1 : 1)
}

const windowMap = new Map()
let start = 0
let end = 0
let count = 0

while (end < sLen) {
const endLetter = s[end]
end++

if (needMap.has(endLetter)) {
if (windowMap.has(endLetter)) {
windowMap.set(endLetter, windowMap.get(endLetter) + 1)
} else {
windowMap.set(endLetter, 1)
}
while (end < s.length) {
const endCh = s[end++]

if (needMap.get(endLetter) === windowMap.get(endLetter)) {
count++
}
if (needMap.has(endCh)) {
windowMap.set(endCh, windowMap.has(endCh) ? windowMap.get(endCh) + 1 : 1)
if (needMap.get(endCh) === windowMap.get(endCh)) count++
}

// 当 count === needMap.size, 说明找到了一个覆盖子串
// 这个时候就可以收缩窗口了
while (count === needMap.size) {
const window = s.slice(start, end)
if (res.length === 0 || window.length < res.length) {
res = window
}

const startLetter = s[start]
start++
const subStr = s.slice(start, end)
if (minStr.length === 0 || subStr.length < minStr.length) minStr = subStr

if (needMap.has(startLetter)) {
if (needMap.get(startLetter) === windowMap.get(startLetter)) {
count--
}
const startCh = s[start++]

windowMap.set(startLetter, windowMap.get(startLetter) - 1)
if (needMap.has(startCh)) {
if (needMap.get(startCh) === windowMap.get(startCh)) count--
windowMap.set(startCh, windowMap.get(startCh) - 1)
}
}
}

return res
return minStr
}
```

Expand All @@ -128,7 +111,7 @@ var minWindow = function (s, t) {
use std::collections::HashMap;

pub fn min_window(s: String, t: String) -> String {
let mut res = "";
let mut min_str = "";

let mut need_map = HashMap::new();
for letter in t.as_bytes() {
Expand All @@ -152,9 +135,9 @@ pub fn min_window(s: String, t: String) -> String {
}

while count == need_map.len() {
let window = &s[start..end];
if res.len() == 0 || window.len() < res.len() {
res = window;
let sub_str = &s[start..end];
if min_str.len() == 0 || sub_str.len() < min_str.len() {
min_str = sub_str;
}

let start_letter = s.as_bytes()[start];
Expand All @@ -170,7 +153,7 @@ pub fn min_window(s: String, t: String) -> String {
}
}

res.to_string()
min_str.to_string()
}
```

Expand Down
7 changes: 4 additions & 3 deletions leetcode-docs/medium/1143-longest-common-subsequence.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ keywords:
- [44. 通配符匹配](/leetcode/hard/44-is-match)
- [72. 编辑距离](/leetcode/hard/72-min-distance)
- [115. 不同的子序列](/leetcode/hard/115-num-distinct)
- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq)
- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance)

:::
Expand Down Expand Up @@ -66,7 +67,7 @@ keywords:

一般要构造如下 `dp` 二维数组, 即让 `dp[0][0]` 为 `0`. 那么从索引 `1` 开始, `dp[i][j]` 的含义就是: `s1[1..i]` 和 `s2[1..j]`, 它们的最长公共子序列是 `dp[i][j]`.

对于下面这个例子, `dp[2][4]` 的含义就是对于 `ac` 和 `babc` 这两个子字符串, 它们的最长公共子序列是 `2`, 当然我们求这个题的结果即是求 `dp[3][6]`.
对于下面这个例子, `dp[2][4]` 的含义就是对于 `ac` 和 `babc` 这两个子字符串, 它们的最长公共子序列是 `2`.

![1143-longest-common-subsequence](../../static/img/1143-longest-common-subsequence.png)

Expand All @@ -77,8 +78,8 @@ keywords:

### 找状态转移方程

对于这个问题, 状态转移就是在做选择, 即求 `s1` 和 `s2` 的最长公共子序列 `lcs`. 那么对于 `s1` 和 `s2` 中的每个字符, 要么在 `lcs` 中, 要么不在.
因此, 如果某个字符应该在 `lcs` 中, 那么这个字符肯定同时存在于 `s1` 和 `s2` 中; 否则, 至少有一个不在 `lcs` 中, 此时取最大的那个. 因此状态转移方程为:
对于这个问题, 状态转移就是在做选择, 即求 `s1` 和 `s2` 的最长公共子序列. 那么对于 `s1` 和 `s2` 中的每个字符, 要么在最长公共子序列中, 要么不在.
因此, 如果某个字符应该在最长公共子序列中, 那么这个字符肯定同时存在于 `s1` 和 `s2` 中; 否则, 至少有一个不在最长公共子序列中, 此时取最大的那个. 因此状态转移方程为:

- 如果 `s[i - 1] === s[j - 1]`, 那么有 `dp[i][j] = dp[i - 1][j - 1] + 1`
- 否则, `dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])`
Expand Down
Loading
Loading