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: add solutions to lc problems #2030

Merged
merged 2 commits into from
Nov 28, 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
2 changes: 1 addition & 1 deletion solution/0000-0099/0002.Add Two Numbers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

最后我们返回答案链表的头节点即可。

时间复杂度 $O(max(m, n))$,其中 $m$ 和 $n$ 分别为两个链表的长度。我们需要遍历两个链表的全部位置,而处理每个位置只需要 $O(1)$ 的时间。忽略答案的空间消耗,空间复杂度 $O(1)$。
时间复杂度 $O(\max(m, n))$,其中 $m$ 和 $n$ 分别为两个链表的长度。我们需要遍历两个链表的全部位置,而处理每个位置只需要 $O(1)$ 的时间。忽略答案的空间消耗,空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down
2 changes: 1 addition & 1 deletion solution/0000-0099/0002.Add Two Numbers/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Each time we traverse, we take out the current bit of the corresponding linked l

Finally, we return the head node of the answer linked list.

The time complexity is $O(max (m, n))$, where $m$ and $n$ are the lengths of the two linked lists. We need to traverse the entire position of the two linked lists, and each position only needs $O(1)$ time. Ignoring the space consumption of the answer, the space complexity is $O(1)$.
The time complexity is $O(\max (m, n))$, where $m$ and $n$ are the lengths of the two linked lists. We need to traverse the entire position of the two linked lists, and each position only needs $O(1)$ time. Ignoring the space consumption of the answer, the space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down
19 changes: 18 additions & 1 deletion solution/0000-0099/0004.Median of Two Sorted Arrays/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,24 @@

## Solutions

Binary search.
**Solution 1: Divide and Conquer**

The problem requires the time complexity of the algorithm to be $O(\log (m + n))$, so we cannot directly traverse the two arrays, but need to use the binary search method.

If $m + n$ is odd, then the median is the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th number; if $m + n$ is even, then the median is the average of the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th and the $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$-th numbers. In fact, we can unify it as the average of the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th and the $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$-th numbers.

Therefore, we can design a function $f(i, j, k)$, which represents the $k$-th smallest number in the interval $[i, m)$ of array $nums1$ and the interval $[j, n)$ of array $nums2$. The median is the average of $f(0, 0, \left\lfloor\frac{m + n + 1}{2}\right\rfloor)$ and $f(0, 0, \left\lfloor\frac{m + n + 2}{2}\right\rfloor)$.

The implementation idea of the function $f(i, j, k)$ is as follows:

- If $i \geq m$, it means that the interval $[i, m)$ of array $nums1$ is empty, so directly return $nums2[j + k - 1]$;
- If $j \geq n$, it means that the interval $[j, n)$ of array $nums2$ is empty, so directly return $nums1[i + k - 1]$;
- If $k = 1$, it means to find the first number, so just return the minimum of $nums1[i]$ and $nums2[j]$;
- Otherwise, we find the $\left\lfloor\frac{k}{2}\right\rfloor$-th number in the two arrays, denoted as $x$ and $y$. (Note, if a certain array does not have the $\left\lfloor\frac{k}{2}\right\rfloor$-th number, then we regard the $\left\lfloor\frac{k}{2}\right\rfloor$-th number as $+\infty$.) Compare the size of $x$ and $y$:
- If $x \leq y$, it means that the $\left\lfloor\frac{k}{2}\right\rfloor$-th number of array $nums1$ cannot be the $k$-th smallest number, so we can exclude the interval $[i, i + \left\lfloor\frac{k}{2}\right\rfloor)$ of array $nums1$, and recursively call $f(i + \left\lfloor\frac{k}{2}\right\rfloor, j, k - \left\lfloor\frac{k}{2}\right\rfloor)$.
- If $x > y$, it means that the $\left\lfloor\frac{k}{2}\right\rfloor$-th number of array $nums2$ cannot be the $k$-th smallest number, so we can exclude the interval $[j, j + \left\lfloor\frac{k}{2}\right\rfloor)$ of array $nums2$, and recursively call $f(i, j + \left\lfloor\frac{k}{2}\right\rfloor, k - \left\lfloor\frac{k}{2}\right\rfloor)$.

The time complexity is $O(\log(m + n))$, and the space complexity is $O(\log(m + n))$. Here, $m$ and $n$ are the lengths of arrays $nums1$ and $nums2$ respectively.

<!-- tabs:start -->

Expand Down
17 changes: 10 additions & 7 deletions solution/0000-0099/0005.Longest Palindromic Substring/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@

**Solution 1: Dynamic Programming**

Set $dp[i][j]$ to indicate whether the string $s[i..j]$ is a palindrome.
We define $f[i][j]$ to represent whether the string $s[i..j]$ is a palindrome, initially $f[i][j] = true$.

- When $j - i \lt 2$, that is, the string length is `2`, as long as $s[i] == s[j]$, then $dp[i][j]$ is `true`.
- When $j - i \ge 2$, there is $dp[i][j] = dp[i + 1][j - 1] \cap s[i] == s[j]$.
Next, we define variables $k$ and $mx$, where $k$ represents the starting position of the longest palindrome, and $mx$ represents the length of the longest palindrome. Initially, $k = 0$, $mx = 1$.

The time complexity is $O(n^2)$ and the space complexity is $O(n^2)$. Where $n$ is the length of the string $s$.
Considering $f[i][j]$, if $s[i] = s[j]$, then $f[i][j] = f[i + 1][j - 1]$; otherwise, $f[i][j] = false$. If $f[i][j] = true$ and $mx < j - i + 1$, then we update $k = i$, $mx = j - i + 1$.

**Solution 2: Enumerate the Palindrome Center**
Since $f[i][j]$ depends on $f[i + 1][j - 1]$, we need to ensure that $i + 1$ is before $j - 1$, so we need to enumerate $i$ from large to small, and enumerate $j$ from small to large.

We can enumerate the palindrome center, spread to both sides, and find the longest palindrome.
The time complexity is $O(n^2)$, and the space complexity is $O(n^2)$. Here, $n$ is the length of the string $s$.

The time complexity is $O(n^2)$ and the space complexity is $O(1)$. Where $n$ is the length of the string $s$.
**Solution 2: Enumerate Palindrome Midpoint**

We can enumerate the midpoint of the palindrome, spread to both sides, and find the longest palindrome.

The time complexity is $O(n^2)$, and the space complexity is $O(1)$. Here, $n$ is the length of the string $s$.

<!-- tabs:start -->

Expand Down
6 changes: 3 additions & 3 deletions solution/0000-0099/0006.Zigzag Conversion/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ P I

**Solution 1: Simulation**

We use a 2D array $g$ to simulate the process of the $Z$-shaped arrangement, where $g[i][j]$ represents the character in the $i$th row and the $j$th column. Initially, $i=0$, and we also define a direction variable $k$, initially $k=-1$, which means up.
We use a two-dimensional array $g$ to simulate the process of the $Z$-shape arrangement, where $g[i][j]$ represents the character at the $i$-th row and the $j$-th column. Initially, $i=0$, and we define a direction variable $k$, initially $k=-1$, indicating moving upwards.

We traverse the string $s$ from left to right. Each time we traverse a character $c$, we append it to $g[i]$. If at this time $i=0$ or $i=numRows-1$, it means that the current character is at the turning point of the $Z$-shaped arrangement. We reverse the value of $k$, that is, $k=-k$. Next, we update the value of $i$ to $i+k$, that is, move up or down one row. Continue to traverse the next character until the string $s$ is traversed. We return the string that all rows in $g$ are concatenated.
We traverse the string $s$ from left to right. Each time we traverse to a character $c$, we append it to $g[i]$. If $i=0$ or $i=numRows-1$ at this time, it means that the current character is at the turning point of the $Z$-shape arrangement, and we reverse the value of $k$, i.e., $k=-k$. Next, we update the value of $i$ to $i+k$, i.e., move up or down one row. Continue to traverse the next character until we have traversed the string $s$, and we return the string concatenated by all rows in $g$.

Time complexity $O(n)$, space complexity $O(n)$, where $n$ is the length of the string $s$.
The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$.

<!-- tabs:start -->

Expand Down
20 changes: 10 additions & 10 deletions solution/0000-0099/0007.Reverse Integer/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,27 @@

## Solutions

**Solution 1: Mathematical**
**Solution 1: Mathematics**

Let $mi$ and $mx$ be $-2^{31}$ and $2^{31} - 1$ respectively. The reversed result $ans$ needs to satisfy $mi \le ans \le mx$.
Let's denote $mi$ and $mx$ as $-2^{31}$ and $2^{31} - 1$ respectively, then the reverse result of $x$, $ans$, needs to satisfy $mi \le ans \le mx$.

We can get the last digit $y$ of $x$ by repeatedly taking the remainder of $x$ by $10$, and then add $y$ to the end of $ans$. Before adding $y$, we need to determine whether $ans$ will overflow. That is, whether $ans \times 10 + y$ is within the range $[mi, mx]$.
We can continuously take the remainder of $x$ to get the last digit $y$ of $x$, and add $y$ to the end of $ans$. Before adding $y$, we need to check if $ans$ overflows. That is, check whether $ans \times 10 + y$ is within the range $[mi, mx]$.

If $x \gt 0$, then $ans \times 10 + y \leq mx$ should be satisfied. That is, $ans \times 10 + y \leq \left \lfloor \frac{mx}{10} \right \rfloor \times 10 + 7$. Rearrange to get $(ans - \left \lfloor \frac{mx}{10} \right \rfloor) \times 10 \leq 7 - y$.
If $x \gt 0$, it needs to satisfy $ans \times 10 + y \leq mx$, that is, $ans \times 10 + y \leq \left \lfloor \frac{mx}{10} \right \rfloor \times 10 + 7$. Rearranging gives $(ans - \left \lfloor \frac{mx}{10} \right \rfloor) \times 10 \leq 7 - y$.

The following conditions need to be satisfied for the above inequality to hold:
Next, we discuss the conditions for the inequality to hold:

- When $ans \lt \left \lfloor \frac{mx}{10} \right \rfloor$, the inequality obviously holds;
- When $ans = \left \lfloor \frac{mx}{10} \right \rfloor$, the necessary and sufficient conditions for the above inequality to hold are $y \leq 7$. If $ans = \left \lfloor \frac{mx}{10} \right \rfloor$ and can still continue to add digits, it means that the current digit is the most significant digit. Therefore, $y$ must be less than or equal to $2$, so the inequality must hold;
- When $ans = \left \lfloor \frac{mx}{10} \right \rfloor$, the necessary and sufficient condition for the inequality to hold is $y \leq 7$. If $ans = \left \lfloor \frac{mx}{10} \right \rfloor$ and we can still add numbers, it means that the number is at the highest digit, that is, $y$ must not exceed $2$, therefore, the inequality must hold;
- When $ans \gt \left \lfloor \frac{mx}{10} \right \rfloor$, the inequality obviously does not hold.

Therefore, when $x \gt 0$, the necessary and sufficient conditions for the inequality to hold are $ans \leq \left \lfloor \frac{mx}{10} \right \rfloor$.
In summary, when $x \gt 0$, the necessary and sufficient condition for the inequality to hold is $ans \leq \left \lfloor \frac{mx}{10} \right \rfloor$.

Similarly, when $x \lt 0$, the necessary and sufficient conditions for the inequality to hold are $ans \geq \left \lfloor \frac{mi}{10} \right \rfloor$.
Similarly, when $x \lt 0$, the necessary and sufficient condition for the inequality to hold is $ans \geq \left \lfloor \frac{mi}{10} \right \rfloor$.

Therefore, we can determine whether $ans$ will overflow by determining whether $ans$ is within the range $[\left \lfloor \frac{mi}{10} \right \rfloor, \left \lfloor \frac{mx}{10} \right \rfloor]$. If so, return $0$. Otherwise, add $y$ to the end of $ans$, and then remove the last digit of $x$, that is, $x \gets \left \lfloor \frac{x}{10} \right \rfloor$.
Therefore, we can check whether $ans$ overflows by checking whether $ans$ is within the range $[\left \lfloor \frac{mi}{10} \right \rfloor, \left \lfloor \frac{mx}{10} \right \rfloor]$. If it overflows, return $0$. Otherwise, add $y$ to the end of $ans$, and then remove the last digit of $x$, that is, $x \gets \left \lfloor \frac{x}{10} \right \rfloor$.

Time complexity $O(\log |x|)$, where $|x|$ is the absolute value of $x$. Space complexity $O(1)$.
The time complexity is $O(\log |x|)$, where $|x|$ is the absolute value of $x$. The space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down
12 changes: 11 additions & 1 deletion solution/0000-0099/0008.String to Integer (atoi)/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,17 @@

<!-- 这里可写通用的实现逻辑 -->

遍历字符串,注意做溢出处理。
**方法一:遍历字符串**

我们首先判断字符串是否为空,如果是,直接返回 $0$。

否则,我们需要遍历字符串,跳过前导空格,判断第一个非空格字符是否为正负号。

接着遍历后面的字符,如果是数字,我们判断添加该数字是否会导致整数溢出,如果会,我们根据正负号返回结果。否则我们将数字添加到结果中。继续遍历后面的字符,直到遇到非数字字符或者遍历结束。

遍历结束后,我们根据正负号返回结果。

时间复杂度 $O(n)$,其中 $n$ 为字符串的长度。我们只需要依次处理所有字符。空间复杂度 $O(1)$。

同[面试题 67. 把字符串转换成整数](/lcof/面试题67.%20把字符串转换成整数/README.md)。

Expand Down
12 changes: 12 additions & 0 deletions solution/0000-0099/0008.String to Integer (atoi)/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ Since 4193 is in the range [-2<sup>31</sup>, 2<sup>31</sup> - 1], the final resu

## Solutions

**Solution 1: Traverse the String**

First, we determine whether the string is empty. If it is, we directly return $0$.

Otherwise, we need to traverse the string, skip the leading spaces, and determine whether the first non-space character is a positive or negative sign.

Then we traverse the following characters. If it is a digit, we judge whether adding this digit will cause integer overflow. If it does, we return the result according to the positive or negative sign. Otherwise, we add the digit to the result. We continue to traverse the following characters until we encounter a non-digit character or the traversal ends.

After the traversal ends, we return the result according to the positive or negative sign.

The time complexity is $O(n)$, where $n$ is the length of the string. We only need to process all characters in turn. The space complexity is $O(1)$.

<!-- tabs:start -->

### **Python3**
Expand Down
24 changes: 24 additions & 0 deletions solution/0000-0099/0009.Palindrome Number/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@

## Solutions

**Solution 1: Reverse Half of the Number**

First, we determine special cases:

- If $x < 0$, then $x$ is not a palindrome, directly return `false`;
- If $x > 0$ and the last digit of $x$ is $0$, then $x$ is not a palindrome, directly return `false`;
- If the last digit of $x$ is not $0$, then $x$ might be a palindrome, continue the following steps.

We reverse the second half of $x$ and compare it with the first half. If they are equal, then $x$ is a palindrome, otherwise, $x$ is not a palindrome.

For example, for $x = 1221$, we can reverse the second half from "21" to "12" and compare it with the first half "12". Since they are equal, we know that $x$ is a palindrome.

Let's see how to reverse the second half.

For the number $1221$, if we perform $1221 \bmod 10$, we will get the last digit $1$. To get the second last digit, we can first remove the last digit from $1221$ by dividing by $10$, $1221 / 10 = 122$, then get the remainder of the previous result divided by $10$, $122 \bmod 10 = 2$, to get the second last digit.

If we continue this process, we will get more reversed digits.

By continuously multiplying the last digit to the variable $y$, we can get the number in reverse order.

In the code implementation, we can repeatedly "take out" the last digit of $x$ and "add" it to the end of $y$, loop until $y \ge x$. If at this time $x = y$, or $x = y / 10$, then $x$ is a palindrome.

The time complexity is $O(\log_{10}(n))$, where $n$ is $x$. For each iteration, we will divide the input by $10$, so the time complexity is $O(\log_{10}(n))$. The space complexity is $O(1)$.

<!-- tabs:start -->

### **Python3**
Expand Down
27 changes: 27 additions & 0 deletions solution/0000-0099/0010.Regular Expression Matching/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,33 @@

## Solutions

**Solution 1: Memoization Search**

We design a function $dfs(i, j)$, which indicates whether the $i$-th character of $s$ matches the $j$-th character of $p$. The answer is $dfs(0, 0)$.

The calculation process of the function $dfs(i, j)$ is as follows:

- If $j$ has reached the end of $p$, then if $i$ has also reached the end of $s$, the match is successful, otherwise, the match fails.
- If the next character of $j$ is `'*'`, we can choose to match $0$ $s[i]$ characters, which is $dfs(i, j + 2)$. If $i \lt m$ and $s[i]$ matches $p[j]$, we can choose to match $1$ $s[i]$ character, which is $dfs(i + 1, j)$.
- If the next character of $j$ is not `'*'`, then if $i \lt m$ and $s[i]$ matches $p[j]$, it is $dfs(i + 1, j + 1)$. Otherwise, the match fails.

During the process, we can use memoization search to avoid repeated calculations.

The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the lengths of $s$ and $p$ respectively.

**Solution 2: Dynamic Programming**

We can convert the memoization search in Solution 1 into dynamic programming.

Define $f[i][j]$ to represent whether the first $i$ characters of string $s$ match the first $j$ characters of string $p$. The answer is $f[m][n]$. Initialize $f[0][0] = true$, indicating that the empty string and the empty regular expression match.

Similar to Solution 1, we can discuss different cases.

- If $p[j - 1]$ is `'*'`, we can choose to match $0$ $s[i - 1]$ characters, which is $f[i][j] = f[i][j - 2]$. If $s[i - 1]$ matches $p[j - 2]$, we can choose to match $1$ $s[i - 1]$ character, which is $f[i][j] = f[i][j] \lor f[i - 1][j]$.
- If $p[j - 1]$ is not `'*'`, then if $s[i - 1]$ matches $p[j - 1]$, it is $f[i][j] = f[i - 1][j - 1]$. Otherwise, the match fails.

The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the lengths of $s$ and $p$ respectively.

<!-- tabs:start -->

### **Python3**
Expand Down
10 changes: 10 additions & 0 deletions solution/0000-0099/0011.Container With Most Water/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@

## Solutions

**Solution 1: Two Pointers**

Initially, we consider the capacity of the water that the two farthest pillars can hold. The width of the water is the distance between the two pillars, and the height of the water depends on the shorter one between the two pillars.

The current pillars are the pillars on the farthest sides, so the width of the water is the largest. For other combinations, the width of the water is smaller. Suppose the height of the left pillar is less than or equal to the height of the right pillar, then the height of the water is the height of the left pillar. If we move the right pillar, the width of the water will decrease, but the height of the water will not increase, so the capacity of the water will definitely decrease. Therefore, we move the left pillar and update the maximum capacity.

Repeat this process until the two pillars meet.

The time complexity is $O(n)$, where $n$ is the length of the array `height`. The space complexity is $O(1)$.

<!-- tabs:start -->

### **Python3**
Expand Down
4 changes: 2 additions & 2 deletions solution/0000-0099/0012.Integer to Roman/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ M 1000</pre>

**Solution 1: Greedy**

We can list all possible symbols $cs$ and corresponding values $vs$ first, then enumerate the value $vs[i]$ from large to small, and use the symbol $cs[i]$ as much as possible each time until the number $num$ becomes $0$.
We can first list all possible symbols $cs$ and their corresponding values $vs$, then enumerate each value $vs[i]$ from large to small. Each time, we use as many symbols $cs[i]$ corresponding to this value as possible, until the number $num$ becomes $0$.

The time complexity is $O(m)$ and the space complexity is $O(m)$, where $m$ is the number of symbols.
The time complexity is $O(m)$, and the space complexity is $O(m)$. Here, $m$ is the number of symbols.

<!-- tabs:start -->

Expand Down
Loading