Skip to content

Commit fc4c9cf

Browse files
committed
Add: Add 2025/9/15
1 parent ff51190 commit fc4c9cf

File tree

3 files changed

+181
-1
lines changed

3 files changed

+181
-1
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# 1935. Maximum Number of Words You Can Type
2+
3+
There is a malfunctioning keyboard where some letter keys do not work.
4+
All other keys on the keyboard work properly.
5+
6+
Given a string `text` of words separated by a single space (no leading or trailing spaces) and a string `brokenLetters` of all distinct letter keys that are broken,
7+
return the number of words in `text` you can fully type using this keyboard.
8+
9+
**Constraints:**
10+
11+
- `1 <= text.length <= 10^4`
12+
- `0 <= brokenLetters.length <= 26`
13+
- `text` consists of words separated by a single space without any leading or trailing spaces.
14+
- Each word only consists of lowercase English letters.
15+
- `brokenLetters` consists of distinct lowercase English letters.
16+
17+
## 基礎思路
18+
19+
題目要求計算在一個字串中,有多少單字可以完整輸入,而限制在於部分字母鍵已經壞掉。
20+
21+
我們可以從以下幾點出發:
22+
23+
- 一個單字若包含任何壞掉的字母,就不能被完整輸入;反之,若不包含壞字母,則可輸入。
24+
- 字串以空白分隔單字,因此只要逐一檢查每個單字是否含有壞字母,就能決定該單字是否有效。
25+
- 為了避免多次重複比對,可以事先把壞字母整理好,使得每次檢查單字時都能快速判斷。
26+
- 在檢查過程中,逐一累計可以完整輸入的單字數量。
27+
- 最後別忘了處理字串末尾的單字,因為最後一個單字後面不會再有空白。
28+
29+
透過這樣的策略,我們能在線性時間內完成計算,並且僅需固定額外空間。
30+
31+
## 解題步驟
32+
33+
### Step 1:特判沒有壞鍵的情況(全部單字都可輸入)
34+
35+
`brokenLetters` 為空,代表所有字母鍵可用;此時答案就是「單字數量」,也就是**空白數 + 1**
36+
37+
```typescript
38+
// 情況 1:沒有壞鍵,所有單字皆可輸入
39+
if (brokenLetters.length === 0) {
40+
let spaceCount = 0;
41+
for (let i = 0; i < text.length; i++) {
42+
if (text.charCodeAt(i) === 32) {
43+
// 發現空白(ASCII 32)
44+
spaceCount++;
45+
}
46+
}
47+
return spaceCount + 1; // 單字數 = 空白數 + 1
48+
}
49+
```
50+
51+
### Step 2:建立壞字母查表(`brokenMap`
52+
53+
`brokenLetters` 轉成 `Uint8Array(26)` 的查表,`brokenMap[c - 'a']` 為 1 表示該字母壞掉。
54+
55+
```typescript
56+
// 建立壞鍵查表
57+
const brokenMap = new Uint8Array(26);
58+
for (let i = 0; i < brokenLetters.length; i++) {
59+
const index = brokenLetters.charCodeAt(i) - 97; // 將 'a' 到 'z' 映射為 0 到 25
60+
brokenMap[index] = 1;
61+
}
62+
```
63+
64+
### Step 3:單趟掃描 `text`,逐字判定單字有效性
65+
66+
用兩個變數:
67+
68+
- `typableWords`:可輸入單字數量
69+
- `currentWordIsValid`:目前掃描中的單字是否仍有效(尚未遇到壞字母)
70+
71+
掃描每個字元:
72+
73+
- 遇到空白:一個單字結束,若 `currentWordIsValid` 為真就累計,並重置為真以準備下一個單字。
74+
- 遇到字母:若尚未失效,檢查是否壞字母;若是則把 `currentWordIsValid` 設為假。
75+
76+
```typescript
77+
let typableWords = 0;
78+
let currentWordIsValid = true;
79+
80+
// 單趟掃描:逐字檢查並標記單字是否有效
81+
for (let i = 0; i < text.length; i++) {
82+
const code = text.charCodeAt(i);
83+
84+
if (code === 32) {
85+
// 單字結束
86+
if (currentWordIsValid) {
87+
typableWords++;
88+
}
89+
currentWordIsValid = true; // 重置,準備下一個單字
90+
} else {
91+
if (currentWordIsValid) {
92+
const index = code - 97;
93+
if (brokenMap[index] === 1) {
94+
// 此單字包含壞鍵字母
95+
currentWordIsValid = false;
96+
}
97+
}
98+
}
99+
}
100+
```
101+
102+
### Step 4:處理結尾最後一個單字(沒有尾隨空白)
103+
104+
字串結尾不會有空白,因此最後一個單字需要在掃描完成後補判一次。
105+
106+
```typescript
107+
// 處理最後一個單字(結尾沒有空白)
108+
if (currentWordIsValid) {
109+
typableWords++;
110+
}
111+
112+
return typableWords;
113+
```
114+
115+
## 時間複雜度
116+
117+
- 建立壞字母查表最多處理 26 個字元,為常數時間。
118+
- 單趟掃描 `text` 的長度為 $n$,每步檢查與更新為常數操作。
119+
- 總時間複雜度為 $O(n)$。
120+
121+
> $O(n)$
122+
123+
## 空間複雜度
124+
125+
- 使用一個固定大小的陣列 `Uint8Array(26)` 作為查表,以及少量計數與旗標變數。
126+
- 不隨輸入長度成長的額外空間。
127+
- 總空間複雜度為 $O(1)$。
128+
129+
> $O(1)$
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
function canBeTypedWords(text: string, brokenLetters: string): number {
2+
// Case 1: No broken letters -> every word is valid
3+
if (brokenLetters.length === 0) {
4+
let spaceCount = 0;
5+
for (let i = 0; i < text.length; i++) {
6+
if (text.charCodeAt(i) === 32) {
7+
// Found a space (ASCII 32)
8+
spaceCount++;
9+
}
10+
}
11+
return spaceCount + 1; // Total words = spaces + 1
12+
}
13+
14+
// Build lookup table for broken letters
15+
const brokenMap = new Uint8Array(26);
16+
for (let i = 0; i < brokenLetters.length; i++) {
17+
const index = brokenLetters.charCodeAt(i) - 97; // Map 'a'...'z' to 0...25
18+
brokenMap[index] = 1;
19+
}
20+
21+
let typableWords = 0;
22+
let currentWordIsValid = true;
23+
24+
// Single pass: scan characters and mark words as valid/invalid
25+
for (let i = 0; i < text.length; i++) {
26+
const code = text.charCodeAt(i);
27+
28+
if (code === 32) {
29+
// End of a word
30+
if (currentWordIsValid) {
31+
typableWords++;
32+
}
33+
currentWordIsValid = true; // Reset for next word
34+
} else {
35+
if (currentWordIsValid) {
36+
const index = code - 97;
37+
if (brokenMap[index] === 1) {
38+
// This word contains a broken letter
39+
currentWordIsValid = false;
40+
}
41+
}
42+
}
43+
}
44+
45+
// Handle last word (string ends without space)
46+
if (currentWordIsValid) {
47+
typableWords++;
48+
}
49+
50+
return typableWords;
51+
}

2749-Minimum Operations to Make the Integer Zero/Note.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function popcount64(x: number): number {
102102

103103
- 初始化 `currentX = num1 - num2`,表示執行 1 次操作後的剩餘值
104104
- 每一輪:
105-
- 檢查剩餘值是否大於等於操作次數(每次至少要湊出一個 \$2^i\$
105+
- 檢查剩餘值是否大於等於操作次數(每次至少要湊出一個 $2^i$)
106106
- 檢查 `currentX` 中位元 1 的個數是否小於等於操作次數(表示夠湊)
107107
- 若皆成立,回傳該操作次數
108108
-`num2 > 0` 且剩餘值已小於操作次數,代表不可能成功,提早回傳 `-1`

0 commit comments

Comments
 (0)