Skip to content

Commit 15d1609

Browse files
authored
feat: add solutions to lc problem: No.0091 (doocs#1531)
No.0091.Decode Ways
1 parent 67b1526 commit 15d1609

File tree

8 files changed

+369
-239
lines changed

8 files changed

+369
-239
lines changed

solution/0000-0099/0091.Decode Ways/README.md

Lines changed: 151 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,18 @@
6666

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

69-
动态规划法。
69+
**方法一:动态规划**
7070

71-
假设 `dp[i]` 表示字符串 s 的前 i 个字符 `s[1..i]` 的解码方法数
71+
我们定义 $f[i]$ 表示字符串的前 $i$ 个字符的解码方法数,初始时 $f[0]=1$,其余 $f[i]=0$
7272

73-
考虑最后一次解码中使用了 s 中的哪些字符:
73+
考虑 $f[i]$ 如何进行状态转移。
7474

75-
- 第一种情况是我们使用了一个字符,即 `s[i]` 进行解码,那么只要 `s[i]≠0`,它就可以被解码成 `A∼I` 中的某个字母。由于剩余的前 `i-1` 个字符的解码方法数为 `dp[i-1]`,所以 `dp[i] = dp[i-1]`
76-
- 第二种情况是我们使用了两个字符,即 `s[i-1]``s[i]` 进行编码。与第一种情况类似,`s[i-1]` 不能等于 0,并且 `s[i-1]``s[i]` 组成的整数必须小于等于 26,这样它们就可以被解码成 `J∼Z` 中的某个字母。由于剩余的前 `i-2` 个字符的解码方法数为 `dp[i-2]`,所以 `dp[i] = dp[i-2]`
75+
- 如果第 $i$ 个字符(即 $s[i-1]$)单独形成编码,那么它对应一种解码方式,即 $f[i]=f[i-1]$。前提是 $s[i-1] \neq 0$
76+
- 如果第 $i-1$ 个字符和第 $i$ 个字符组成的字符串在 $[1,26]$ 范围内,那么它们可以作为一个整体,对应一种解码方式,即 $f[i] = f[i] + f[i-2]$。前提是 $s[i-2] \neq 0$,且 $s[i-2]s[i-1]$ 在 $[1,26]$ 范围内
7777

78-
将上面的两种状态转移方程在对应的条件满足时进行累加,即可得到 `dp[i]`的值。在动态规划完成后,最终的答案即为 `dp[n]`
78+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是字符串的长度
7979

80-
由于 `dp[i]` 的值仅与 `dp[i-1]``dp[i-2]` 有关,因此可以不定义 dp 数组,可以仅使用三个变量进行状态转移
80+
我们注意到,状态 $f[i]$ 仅与状态 $f[i-1]$ 和状态 $f[i-2]$ 有关,而与其他状态无关,因此我们可以使用两个变量代替这两个状态,使得原来的空间复杂度 $O(n)$ 降低至 $O(1)$
8181

8282
<!-- tabs:start -->
8383

@@ -89,31 +89,25 @@
8989
class Solution:
9090
def numDecodings(self, s: str) -> int:
9191
n = len(s)
92-
dp = [0] * (n + 1)
93-
dp[0] = 1
94-
for i in range(1, n + 1):
95-
if s[i - 1] != '0':
96-
dp[i] += dp[i - 1]
97-
if i > 1 and s[i - 2] != '0' and (int(s[i - 2]) * 10 + int(s[i - 1]) <= 26):
98-
dp[i] += dp[i - 2]
99-
return dp[n]
92+
f = [1] + [0] * n
93+
for i, c in enumerate(s, 1):
94+
if c != "0":
95+
f[i] = f[i - 1]
96+
if i > 1 and s[i - 2] != "0" and int(s[i - 2 : i]) <= 26:
97+
f[i] += f[i - 2]
98+
return f[n]
10099
```
101100

102-
优化空间:
103-
104101
```python
105102
class Solution:
106103
def numDecodings(self, s: str) -> int:
107-
n = len(s)
108-
a, b, c = 0, 1, 0
109-
for i in range(1, n + 1):
110-
c = 0
111-
if s[i - 1] != '0':
112-
c += b
113-
if i > 1 and s[i - 2] != '0' and (int(s[i - 2]) * 10 + int(s[i - 1]) <= 26):
114-
c += a
115-
a, b = b, c
116-
return c
104+
f, g = 0, 1
105+
for i, c in enumerate(s, 1):
106+
h = g if c != "0" else 0
107+
if i > 1 and s[i - 2] != "0" and int(s[i - 2 : i]) <= 26:
108+
h += f
109+
f, g = g, h
110+
return g
117111
```
118112

119113
### **Java**
@@ -124,42 +118,35 @@ class Solution:
124118
class Solution {
125119
public int numDecodings(String s) {
126120
int n = s.length();
127-
int[] dp = new int[n + 1];
128-
dp[0] = 1;
121+
int[] f = new int[n + 1];
122+
f[0] = 1;
129123
for (int i = 1; i <= n; ++i) {
130124
if (s.charAt(i - 1) != '0') {
131-
dp[i] += dp[i - 1];
125+
f[i] = f[i - 1];
132126
}
133-
if (i > 1 && s.charAt(i - 2) != '0'
134-
&& ((s.charAt(i - 2) - '0') * 10 + s.charAt(i - 1) - '0') <= 26) {
135-
dp[i] += dp[i - 2];
127+
if (i > 1 && s.charAt(i - 2) != '0' && Integer.valueOf(s.substring(i - 2, i)) <= 26) {
128+
f[i] += f[i - 2];
136129
}
137130
}
138-
return dp[n];
131+
return f[n];
139132
}
140133
}
141134
```
142135

143-
优化空间:
144-
145136
```java
146137
class Solution {
147138
public int numDecodings(String s) {
148139
int n = s.length();
149-
int a = 0, b = 1, c = 0;
140+
int f = 0, g = 1;
150141
for (int i = 1; i <= n; ++i) {
151-
c = 0;
152-
if (s.charAt(i - 1) != '0') {
153-
c += b;
142+
int h = s.charAt(i - 1) != '0' ? g : 0;
143+
if (i > 1 && s.charAt(i - 2) != '0' && Integer.valueOf(s.substring(i - 2, i)) <= 26) {
144+
h += f;
154145
}
155-
if (i > 1 && s.charAt(i - 2) != '0'
156-
&& ((s.charAt(i - 2) - '0') * 10 + s.charAt(i - 1) - '0') <= 26) {
157-
c += a;
158-
}
159-
a = b;
160-
b = c;
146+
f = g;
147+
g = h;
161148
}
162-
return c;
149+
return g;
163150
}
164151
}
165152
```
@@ -171,19 +158,37 @@ class Solution {
171158
public:
172159
int numDecodings(string s) {
173160
int n = s.size();
174-
vector<int> dp(n + 1);
175-
dp[0] = 1;
161+
int f[n + 1];
162+
memset(f, 0, sizeof(f));
163+
f[0] = 1;
176164
for (int i = 1; i <= n; ++i) {
177165
if (s[i - 1] != '0') {
178-
dp[i] += dp[i - 1];
166+
f[i] = f[i - 1];
167+
}
168+
if (i > 1 && (s[i - 2] == '1' || s[i - 2] == '2' && s[i - 1] <= '6')) {
169+
f[i] += f[i - 2];
179170
}
180-
if (i > 1 && s[i - 2] != '0') {
181-
if ((s[i - 2] - '0') * 10 + s[i - 1] - '0' <= 26) {
182-
dp[i] += dp[i - 2];
183-
}
171+
}
172+
return f[n];
173+
}
174+
};
175+
```
176+
177+
```cpp
178+
class Solution {
179+
public:
180+
int numDecodings(string s) {
181+
int n = s.size();
182+
int f = 0, g = 1;
183+
for (int i = 1; i <= n; ++i) {
184+
int h = s[i - 1] != '0' ? g : 0;
185+
if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
186+
h += f;
184187
}
188+
f = g;
189+
g = h;
185190
}
186-
return dp[n];
191+
return g;
187192
}
188193
};
189194
```
@@ -193,19 +198,75 @@ public:
193198
```go
194199
func numDecodings(s string) int {
195200
n := len(s)
196-
dp := make([]int, n+1)
197-
dp[0] = 1
201+
f := make([]int, n+1)
202+
f[0] = 1
203+
for i := 1; i <= n; i++ {
204+
if s[i-1] != '0' {
205+
f[i] = f[i-1]
206+
}
207+
if i > 1 && (s[i-2] == '1' || (s[i-2] == '2' && s[i-1] <= '6')) {
208+
f[i] += f[i-2]
209+
}
210+
}
211+
return f[n]
212+
}
213+
```
214+
215+
```go
216+
func numDecodings(s string) int {
217+
n := len(s)
218+
f, g := 0, 1
198219
for i := 1; i <= n; i++ {
220+
h := 0
199221
if s[i-1] != '0' {
200-
dp[i] += dp[i-1]
222+
h = g
201223
}
202-
if i > 1 && s[i-2] != '0' {
203-
if (s[i-2]-'0')*10+(s[i-1]-'0') <= 26 {
204-
dp[i] += dp[i-2]
205-
}
224+
if i > 1 && (s[i-2] == '1' || (s[i-2] == '2' && s[i-1] <= '6')) {
225+
h += f
206226
}
227+
f, g = g, h
207228
}
208-
return dp[n]
229+
return g
230+
}
231+
```
232+
233+
### **TypeScript**
234+
235+
```ts
236+
function numDecodings(s: string): number {
237+
const n = s.length;
238+
const f: number[] = new Array(n + 1).fill(0);
239+
f[0] = 1;
240+
for (let i = 1; i <= n; ++i) {
241+
if (s[i - 1] !== '0') {
242+
f[i] = f[i - 1];
243+
}
244+
if (
245+
i > 1 &&
246+
(s[i - 2] === '1' || (s[i - 2] === '2' && s[i - 1] <= '6'))
247+
) {
248+
f[i] += f[i - 2];
249+
}
250+
}
251+
return f[n];
252+
}
253+
```
254+
255+
```ts
256+
function numDecodings(s: string): number {
257+
const n = s.length;
258+
let [f, g] = [0, 1];
259+
for (let i = 1; i <= n; ++i) {
260+
let h = s[i - 1] !== '0' ? g : 0;
261+
if (
262+
i > 1 &&
263+
(s[i - 2] === '1' || (s[i - 2] === '2' && s[i - 1] <= '6'))
264+
) {
265+
h += f;
266+
}
267+
[f, g] = [g, h];
268+
}
269+
return g;
209270
}
210271
```
211272

@@ -214,27 +275,36 @@ func numDecodings(s string) int {
214275
```cs
215276
public class Solution {
216277
public int NumDecodings(string s) {
217-
if (s.Length == 0) return 0;
218-
219-
var f0 = 1;
220-
var f1 = 1;
221-
var f2 = 1;
222-
for (var i = 0; i < s.Length; ++i)
223-
{
224-
f0 = f1;
225-
f1 = f2;
226-
f2 = 0;
227-
var two = i > 0 ? int.Parse(string.Format("{0}{1}", s[i - 1], s[i])) : 0;
228-
if (two >= 10 && two <= 26)
229-
{
230-
f2 += f0;
278+
int n = s.Length;
279+
int[] f = new int[n + 1];
280+
f[0] = 1;
281+
for (int i = 1; i <= n; ++i) {
282+
if (s[i - 1] != '0') {
283+
f[i] = f[i - 1];
284+
}
285+
if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
286+
f[i] += f[i - 2];
231287
}
232-
if (s[i] != '0')
233-
{
234-
f2 += f1;
288+
}
289+
return f[n];
290+
}
291+
}
292+
```
293+
294+
```cs
295+
public class Solution {
296+
public int NumDecodings(string s) {
297+
int n = s.Length;
298+
int f = 0, g = 1;
299+
for (int i = 1; i <= n; ++i) {
300+
int h = s[i - 1] != '0' ? g : 0;
301+
if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
302+
h += f;
235303
}
304+
f = g;
305+
g = h;
236306
}
237-
return f2;
307+
return g;
238308
}
239309
}
240310
```

0 commit comments

Comments
 (0)