Skip to content

Commit

Permalink
Merge pull request #800 from YanceyOfficial/feat/quarter-1
Browse files Browse the repository at this point in the history
Feat/quarter 1
  • Loading branch information
YanceyOfficial committed Nov 23, 2023
2 parents db20b75 + bee3eb5 commit 09720e2
Show file tree
Hide file tree
Showing 42 changed files with 686 additions and 373 deletions.
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

0 comments on commit 09720e2

Please sign in to comment.