Skip to content

[pull] main from doocs:main #198

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

Merged
merged 2 commits into from
Mar 24, 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/0200-0299/0263.Ugly Number/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<pre>
<strong>输入:</strong>n = 14
<strong>输出:</strong>false
<strong>解释:</strong>14 不是丑数,因为它包含了另外一个质因数 7
<strong>解释:</strong>14 不是丑数,因为它包含了另外一个质因数&nbsp;<code>7 </code>
</pre>

<p>&nbsp;</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class Solution {
return -1;
}
}
```
```

### **...**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class Solution {
return -1;
}
}
```
```

### **...**

Expand Down
2 changes: 1 addition & 1 deletion solution/0600-0699/0605.Can Place Flowers/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<p>You have a long flowerbed in which some of the plots are planted, and some are not. However, flowers cannot be planted in <strong>adjacent</strong> plots.</p>

<p>Given an integer array <code>flowerbed</code> containing <code>0</code>&#39;s and <code>1</code>&#39;s, where <code>0</code> means empty and <code>1</code> means not empty, and an integer <code>n</code>, return <em>if</em> <code>n</code> new flowers can be planted in the <code>flowerbed</code> without violating the no-adjacent-flowers rule.</p>
<p>Given an integer array <code>flowerbed</code> containing <code>0</code>&#39;s and <code>1</code>&#39;s, where <code>0</code> means empty and <code>1</code> means not empty, and an integer <code>n</code>, return <code>true</code>&nbsp;<em>if</em> <code>n</code> <em>new flowers can be planted in the</em> <code>flowerbed</code> <em>without violating the no-adjacent-flowers rule and</em> <code>false</code> <em>otherwise</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
Expand Down
2 changes: 1 addition & 1 deletion solution/0600-0699/0665.Non-decreasing Array/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Solution {
}
return true;
}

private boolean isSorted(int[] nums) {
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i] > nums[i + 1]) {
Expand Down
41 changes: 26 additions & 15 deletions solution/1000-1099/1032.Stream of Characters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,16 @@ streamChecker.query("l"); // 返回 True ,因为 'kl' 在 words 中

**方法一:前缀树**

构建前缀树,每个节点保存一个字符,从根节点开始,每次遍历到一个字符,就将其加入到当前节点的子节点中,同时将当前节点的 `isEnd` 标记为 `true`。当遍历到字符串的末尾时,将当前节点的 `isEnd` 标记为 `true`。
我们可以根据初始化时的字符串数组 $words$ 构建前缀树,前缀树的每个节点包含两个属性:

查询时,从根节点开始,每次遍历到一个字符,就将其加入到当前节点的子节点中,同时将当前节点的 `isEnd` 标记为 `true`。当遍历到字符串的末尾时,将当前节点的 `isEnd` 标记为 `true`。
- `children`:指向 $26$ 个字母的指针数组,用于存储当前节点的子节点。
- `is_end`:标记当前节点是否为某个字符串的结尾。

对于本题,我们采用**字符串的反序**来构建前缀树,这样在查询时,只需要从根节点开始,遍历到当前字符即可,不需要遍历到字符串的末尾
在构造函数中,我们遍历字符串数组 $words$,对于每个字符串 $w$,我们将其反转后,逐个字符插入到前缀树中,插入结束后,将当前节点的 `is_end` 标记为 `true`

初始化前缀树的时间复杂度为 $O(n)$,其中 $n$ 为 `words` 所有字符总数。单次查询的时间复杂度为 $O(m)$,其中 $m$ 为 `words` 中单词的最大长度。
在 `query` 函数中,我们将当前字符 $c$ 加入到字符流中,然后从后往前遍历字符流,对于每个字符 $c$,我们在前缀树中查找是否存在以 $c$ 为结尾的字符串,如果存在,返回 `true`,否则返回 `false`。注意到 $words$ 中的字符串长度不超过 $200$,因此查询时最多只需要遍历 $200$ 个字符。

时间复杂度方面,构造函数的时间复杂度为 $O(L)$,而 `query` 函数的时间复杂度为 $O(M)$。其中 $L$ 为字符串数组 $words$ 中所有字符串的长度之和,而 $M$ 为字符串数组 $words$ 中字符串的最大长度。空间复杂度 $O(L)$。

<!-- tabs:start -->

Expand All @@ -82,7 +85,7 @@ class Trie:
self.children = [None] * 26
self.is_end = False

def insert(self, w):
def insert(self, w: str):
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -91,7 +94,7 @@ class Trie:
node = node.children[idx]
node.is_end = True

def search(self, w):
def search(self, w: List[str]) -> bool:
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -107,13 +110,14 @@ class StreamChecker:

def __init__(self, words: List[str]):
self.trie = Trie()
self.s = []
self.cs = []
self.limit = 201
for w in words:
self.trie.insert(w)

def query(self, letter: str) -> bool:
self.s.append(letter)
return self.trie.search(self.s[-201:])
self.cs.append(letter)
return self.trie.search(self.cs[-self.limit:])

# Your StreamChecker object will be instantiated and called as such:
# obj = StreamChecker(words)
Expand Down Expand Up @@ -190,14 +194,16 @@ public:

Trie()
: children(26)
, isEnd(false) { }
, isEnd(false) {}

void insert(string& w) {
Trie* node = this;
reverse(w.begin(), w.end());
for (char c : w) {
for (char& c : w) {
int idx = c - 'a';
if (!node->children[idx]) node->children[idx] = new Trie();
if (!node->children[idx]) {
node->children[idx] = new Trie();
}
node = node->children[idx];
}
node->isEnd = true;
Expand All @@ -207,9 +213,13 @@ public:
Trie* node = this;
for (int i = w.size() - 1, j = 0; ~i && j < 201; --i, ++j) {
int idx = w[i] - 'a';
if (!node->children[idx]) return false;
if (!node->children[idx]) {
return false;
}
node = node->children[idx];
if (node->isEnd) return true;
if (node->isEnd) {
return true;
}
}
return false;
}
Expand All @@ -219,8 +229,9 @@ class StreamChecker {
public:
Trie* trie = new Trie();
string s;

StreamChecker(vector<string>& words) {
for (string& w : words) {
for (auto& w : words) {
trie->insert(w);
}
}
Expand Down
30 changes: 19 additions & 11 deletions solution/1000-1099/1032.Stream of Characters/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Trie:
self.children = [None] * 26
self.is_end = False

def insert(self, w):
def insert(self, w: str):
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -73,7 +73,7 @@ class Trie:
node = node.children[idx]
node.is_end = True

def search(self, w):
def search(self, w: List[str]) -> bool:
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -89,13 +89,14 @@ class StreamChecker:

def __init__(self, words: List[str]):
self.trie = Trie()
self.s = []
self.cs = []
self.limit = 201
for w in words:
self.trie.insert(w)

def query(self, letter: str) -> bool:
self.s.append(letter)
return self.trie.search(self.s[-201:])
self.cs.append(letter)
return self.trie.search(self.cs[-self.limit:])

# Your StreamChecker object will be instantiated and called as such:
# obj = StreamChecker(words)
Expand Down Expand Up @@ -170,14 +171,16 @@ public:

Trie()
: children(26)
, isEnd(false) { }
, isEnd(false) {}

void insert(string& w) {
Trie* node = this;
reverse(w.begin(), w.end());
for (char c : w) {
for (char& c : w) {
int idx = c - 'a';
if (!node->children[idx]) node->children[idx] = new Trie();
if (!node->children[idx]) {
node->children[idx] = new Trie();
}
node = node->children[idx];
}
node->isEnd = true;
Expand All @@ -187,9 +190,13 @@ public:
Trie* node = this;
for (int i = w.size() - 1, j = 0; ~i && j < 201; --i, ++j) {
int idx = w[i] - 'a';
if (!node->children[idx]) return false;
if (!node->children[idx]) {
return false;
}
node = node->children[idx];
if (node->isEnd) return true;
if (node->isEnd) {
return true;
}
}
return false;
}
Expand All @@ -199,8 +206,9 @@ class StreamChecker {
public:
Trie* trie = new Trie();
string s;

StreamChecker(vector<string>& words) {
for (string& w : words) {
for (auto& w : words) {
trie->insert(w);
}
}
Expand Down
17 changes: 12 additions & 5 deletions solution/1000-1099/1032.Stream of Characters/Solution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ class Trie {
void insert(string& w) {
Trie* node = this;
reverse(w.begin(), w.end());
for (char c : w) {
for (char& c : w) {
int idx = c - 'a';
if (!node->children[idx]) node->children[idx] = new Trie();
if (!node->children[idx]) {
node->children[idx] = new Trie();
}
node = node->children[idx];
}
node->isEnd = true;
Expand All @@ -22,9 +24,13 @@ class Trie {
Trie* node = this;
for (int i = w.size() - 1, j = 0; ~i && j < 201; --i, ++j) {
int idx = w[i] - 'a';
if (!node->children[idx]) return false;
if (!node->children[idx]) {
return false;
}
node = node->children[idx];
if (node->isEnd) return true;
if (node->isEnd) {
return true;
}
}
return false;
}
Expand All @@ -34,8 +40,9 @@ class StreamChecker {
public:
Trie* trie = new Trie();
string s;

StreamChecker(vector<string>& words) {
for (string& w : words) {
for (auto& w : words) {
trie->insert(w);
}
}
Expand Down
13 changes: 7 additions & 6 deletions solution/1000-1099/1032.Stream of Characters/Solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ def __init__(self):
self.children = [None] * 26
self.is_end = False

def insert(self, w):
def insert(self, w: str):
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -12,7 +12,7 @@ def insert(self, w):
node = node.children[idx]
node.is_end = True

def search(self, w):
def search(self, w: List[str]) -> bool:
node = self
for c in w[::-1]:
idx = ord(c) - ord('a')
Expand All @@ -25,16 +25,17 @@ def search(self, w):


class StreamChecker:

def __init__(self, words: List[str]):
self.trie = Trie()
self.s = []
self.cs = []
self.limit = 201
for w in words:
self.trie.insert(w)

def query(self, letter: str) -> bool:
self.s.append(letter)
return self.trie.search(self.s[-201:])

self.cs.append(letter)
return self.trie.search(self.cs[-self.limit:])

# Your StreamChecker object will be instantiated and called as such:
# obj = StreamChecker(words)
Expand Down
4 changes: 2 additions & 2 deletions solution/1400-1499/1406.Stone Game III/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Solution {
private int n;
private int[] s;
private Integer[] f;

public String stoneGameIII(int[] stoneValue) {
n = stoneValue.length;
s = new int[n + 1];
Expand All @@ -95,7 +95,7 @@ class Solution {
int b = s[n] - a;
return a == b ? "Tie" : a > b ? "Alice" : "Bob";
}

private int dfs(int i) {
if (i >= n) {
return 0;
Expand Down
8 changes: 4 additions & 4 deletions solution/1600-1699/1630.Arithmetic Subarrays/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@

函数 $check(nums, l, r)$ 的实现逻辑如下:

- 首先,我们计算子数组的长度 $n = r - l + 1$,并将子数组中的元素放入集合 $s$ 中,方便后续的查找;
- 然后,我们获取子数组中的最小值 $a_1$ 和最大值 $a_n$,如果 $a_n - a_1$ 不能被 $n - 1$ 整除,那么子数组不可能形成等差数列,直接返回 $false$;否则,我们计算等差数列的公差 $d = \frac{a_n - a_1}{n - 1}$;
- 接下来从 $a_1$ 开始,依次计算等差数列中第 $i$ 项元素,如果第 $i$ 项元素 $a_1 + (i - 1) \times d$ 不在集合 $s$ 中,那么子数组不可能形成等差数列,直接返回 $false$;否则,当我们遍历完所有的元素,说明子数组可以重新排列形成等差数列,返回 $true$。
- 首先,我们计算子数组的长度 $n = r - l + 1$,并将子数组中的元素放入集合 $s$ 中,方便后续的查找;
- 然后,我们获取子数组中的最小值 $a_1$ 和最大值 $a_n$,如果 $a_n - a_1$ 不能被 $n - 1$ 整除,那么子数组不可能形成等差数列,直接返回 $false$;否则,我们计算等差数列的公差 $d = \frac{a_n - a_1}{n - 1}$;
- 接下来从 $a_1$ 开始,依次计算等差数列中第 $i$ 项元素,如果第 $i$ 项元素 $a_1 + (i - 1) \times d$ 不在集合 $s$ 中,那么子数组不可能形成等差数列,直接返回 $false$;否则,当我们遍历完所有的元素,说明子数组可以重新排列形成等差数列,返回 $true$。

在主函数中,我们遍历所有的查询,对于每个查询 $l[i]$ 和 $r[i]$,我们调用函数 $check(nums, l[i], r[i])$ 判断子数组是否可以重新排列形成等差数列,将结果存入答案数组中。

Expand All @@ -86,7 +86,7 @@ class Solution:
a1, an = min(nums[l: l + n]), max(nums[l: l + n])
d, mod = divmod(an - a1, n - 1)
return mod == 0 and all((a1 + (i - 1) * d) in s for i in range(1, n))

return [check(nums, left, right) for left, right in zip(l, r)]
```

Expand Down
2 changes: 1 addition & 1 deletion solution/1600-1699/1630.Arithmetic Subarrays/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Solution:
a1, an = min(nums[l: l + n]), max(nums[l: l + n])
d, mod = divmod(an - a1, n - 1)
return mod == 0 and all((a1 + (i - 1) * d) in s for i in range(1, n))

return [check(nums, left, right) for left, right in zip(l, r)]
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

<!-- 这里写题目描述 -->

<p>给你两个字符串 <code>s</code> 和 <code>t</code> ,请你找出 <code>s</code> 中的非空子串的数目,这些子串满足替换 <strong>一个不同字符</strong> 以后,是 <code>t</code> 串的子串。换言之,请你找到 <code>s</code> 和 <code>t</code> 串中 <strong>恰好</strong> 只有一个字符不同的子字符串对的数目。</p>
<p>给你两个字符串&nbsp;<code>s</code> 和&nbsp;<code>t</code>&nbsp;,请你找出 <code>s</code>&nbsp;中的非空子串的数目,这些子串满足替换 <strong>一个不同字符</strong>&nbsp;以后,是 <code>t</code>&nbsp;串的子串。换言之,请你找到 <code>s</code>&nbsp;和 <code>t</code>&nbsp;串中 <strong>恰好</strong>&nbsp;只有一个字符不同的子字符串对的数目。</p>

<p>比方说, <code>"<strong>compute</strong>r"</code> 和 <code>"<strong>computa</strong>tion"</code> 加粗部分只有一个字符不同: <code>'e'</code>/<code>'a'</code> ,所以这一对子字符串会给答案加 1 。</p>
<p>比方说,&nbsp;<code>"<u>compute</u>r"</code>&nbsp;and&nbsp;<code>"<u>computa</u>tion"&nbsp;</code>只有一个字符不同:&nbsp;<code>'e'</code>/<code>'a'</code>&nbsp;,所以这一对子字符串会给答案加 1 。</p>

<p>请你返回满足上述条件的不同子字符串对数目。</p>

<p>一个 <strong>子字符串</strong> 是一个字符串中连续的字符。</p>
<p>一个 <strong>子字符串</strong>&nbsp;是一个字符串中连续的字符。</p>

<p> </p>
<p>&nbsp;</p>

<p><strong>示例 1:</strong></p>

Expand Down Expand Up @@ -57,13 +57,13 @@
<b>输出:</b>10
</pre>

<p> </p>
<p>&nbsp;</p>

<p><strong>提示:</strong></p>

<ul>
<li><code>1 <= s.length, t.length <= 100</code></li>
<li><code>s</code> 和 <code>t</code> 都只包含小写英文字母。</li>
<li><code>1 &lt;= s.length, t.length &lt;= 100</code></li>
<li><code>s</code> 和&nbsp;<code>t</code>&nbsp;都只包含小写英文字母。</li>
</ul>

## 解法
Expand Down
Loading