Skip to content

Commit 2bc6f94

Browse files
committed
简化方法一代码
1 parent 71a9897 commit 2bc6f94

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

leetcode/biweekly/143/d/README.md

+17-15
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
## 方法一:从左到右爆搜
22

3-
**阅读提示**:需要至少做过一道数位 DP 题。
4-
53
首先,由于数位乘积中的质因子只有 $2,3,5,7$,如果 $t$ 包含其他质因子,那么直接返回 $-1$。如果 $t$ 只包含质因子 $2,3,5,7$,那么答案一定存在。
64

75
下文把 $\textit{num}$ 简记为 $s$。其长度为 $n$。
86

97
例如 $s=123$,并假设答案的长度也为 $3$。
108

11-
仿照 [数位 DP](https://www.bilibili.com/video/BV1rS4y1s721/?t=20m05s) 的思路,写一个爆搜(回溯)
9+
仿照 [数位 DP](https://www.bilibili.com/video/BV1rS4y1s721/?t=20m05s) 的思路,写一个爆搜:
1210

1311
- 最高位如果填 $1$,那么第二位不能填 $1$(不然小于 $s$ 了),至少要填 $2$。
1412
- 最高位如果填的数大于 $1$,那么第二位,以及第三位,填的数字不受到 $s$ 的约束,可以填 $[1,9]$ 中的任意数字。
1513

16-
这启发我们也像数位 DP 那样,在回溯的过程中,用一个参数 $\textit{isLimit}$ 表示「是否受到 $s$ 的约束」。
14+
这启发我们也像数位 DP 那样,在递归的过程中,用一个参数 $\textit{isLimit}$ 表示「是否受到 $s$ 的约束」。
1715

1816
如何判断所填数位之积是 $t$ 的倍数呢?
1917

@@ -25,7 +23,7 @@
2523

2624
一般地,如果填的数字是 $d$,那么余下的数位,需要满足乘积是 $\dfrac{t}{\text{GCD}(t,d)}$ 的倍数。
2725

28-
综上所述,写一个带 $\textit{vis}$ 的爆搜(回溯),参数有:
26+
综上所述,写一个带 $\textit{vis}$ 的爆搜,参数有:
2927

3028
- $i$:表示当前填到 $s$ 的第 $i$ 个数位了。
3129
- $t$:表示 $[i,n-1]$ 所填数位,需要满足乘积是 $t$ 的倍数。
@@ -51,7 +49,7 @@ $$
5149

5250
注意至少要添加 $1$ 个前导零,因为可能有 $s=999$ 这种情况,即使 $t=2$,答案($1112$)长度也比 $s$ 要长。
5351

54-
注意添加前导零会影响可以填入的数字,当 $\textit{isLimit}=\texttt{true}$ 且 $i < \textit{cnt}$ 时,我们可以填入 $0$。
52+
注意添加前导零会影响可以填入的数字,当 $\textit{isLimit}=\texttt{true}$ 且 $i < \textit{cnt}$ 时,我们可以填入 $0$。这和数位 DP 的「跳过不填数字」是一样的。
5553

5654
具体请看 [视频讲解](https://www.bilibili.com/video/BV1cgmBYqEhu/?t=28m31s),欢迎点赞关注~
5755

@@ -72,7 +70,7 @@ class Solution:
7270
s = '0' * cnt + s
7371

7472
n = len(s)
75-
ans = [0] * n
73+
ans = ['0'] * n
7674

7775
@cache # 仅仅作为 vis 标记使用
7876
def dfs(i: int, t: int, is_limit: bool) -> bool:
@@ -84,14 +82,14 @@ class Solution:
8482

8583
low = int(s[i]) if is_limit else 0
8684
for d in range(max(low, 1), 10):
87-
ans[i] = d # 直接覆盖,无需恢复现场
8885
if dfs(i + 1, t // gcd(t, d), is_limit and d == low):
86+
ans[i] = str(d)
8987
return True
9088
return False
9189

9290
dfs(0, t, True)
9391
dfs.cache_clear() # 防止爆内存
94-
return ''.join(map(str, ans)).lstrip('0') # 去掉前导零
92+
return ''.join(ans).lstrip('0') # 去掉前导零
9593
```
9694

9795
```py [sol-Python3 写法二]
@@ -111,7 +109,7 @@ class Solution:
111109
s = '0' * cnt + s
112110

113111
n = len(s)
114-
ans = [0] * n
112+
ans = ['0'] * n
115113
vis = [set() for _ in range(n)]
116114

117115
def dfs(i: int, t: int, is_limit: bool) -> bool:
@@ -128,13 +126,13 @@ class Solution:
128126

129127
low = int(s[i]) if is_limit else 0
130128
for d in range(max(low, 1), 10):
131-
ans[i] = d # 直接覆盖,无需恢复现场
132129
if dfs(i + 1, t // gcd(t, d), is_limit and d == low):
130+
ans[i] = str(d)
133131
return True
134132
return False
135133

136134
dfs(0, t, True)
137-
return ''.join(map(str, ans)).lstrip('0') # 去掉前导零
135+
return ''.join(ans).lstrip('0') # 去掉前导零
138136
```
139137

140138
```java [sol-Java]
@@ -185,8 +183,8 @@ class Solution {
185183

186184
int low = isLimit ? s[i] - '0' : 0;
187185
for (int d = Math.max(low, 1); d <= 9; d++) {
188-
ans[i] = (char) ('0' + d); // 直接覆盖,无需恢复现场
189186
if (dfs(i + 1, t / gcd(t, d), isLimit && d == low, cnt, s, ans, vis)) {
187+
ans[i] = (char) ('0' + d);
190188
return true;
191189
}
192190
}
@@ -241,8 +239,8 @@ public:
241239

242240
int low = is_limit ? s[i] - '0' : 0;
243241
for (int d = max(low, 1); d <= 9; d++) {
244-
ans[i] = '0' + d; // 直接覆盖,无需恢复现场
245242
if (dfs(dfs, i + 1, t / gcd(t, d), is_limit && d == low)) {
243+
ans[i] = '0' + d;
246244
return true;
247245
}
248246
}
@@ -300,8 +298,8 @@ func smallestNumber(s string, t int64) string {
300298
low = int(s[i] - '0')
301299
}
302300
for d := max(low, 1); d <= 9; d++ {
303-
ans[i] = '0' + byte(d) // 直接覆盖,无需恢复现场
304301
if dfs(i+1, t/gcd(t, d), isLimit && d == low) {
302+
ans[i] = '0' + byte(d)
305303
return true
306304
}
307305
}
@@ -611,6 +609,10 @@ func gcd(a, b int) int {
611609
- 时间复杂度:$\mathcal{O}(n + D\log^2 t)$,其中 $n$ 是 $s$ 的长度,$D=9$。分析四重循环的循环次数,如果从 $i=n-1$ 开始循环,$i$ 至多减少 $\mathcal{O}(\log t)$ 次,就一定能在右边填入 $\mathcal{O}(\log t)$ 个数字,所以 $j$ 的循环次数是 $\mathcal{O}(\log t)$。而如果 $i$ 远小于 $n-1$,则一定能填入数字,$j$ 的循环次数是 $\mathcal{O}(n)$。
612610
- 空间复杂度:$\mathcal{O}(n)$。
613611

612+
## 相似题目
613+
614+
- [3260. 找出最大的 N 位 K 回文数](https://leetcode.cn/problems/find-the-largest-palindrome-divisible-by-k/) 2370
615+
614616
## 分类题单
615617

616618
[如何科学刷题?](https://leetcode.cn/circle/discuss/RvFUtj/)

leetcode/biweekly/143/d/d.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ func smallestNumber2(s string, t int64) string {
117117
low = int(s[i] - '0')
118118
}
119119
for d := max(low, 1); d <= 9; d++ {
120-
ans[i] = '0' + byte(d) // 直接覆盖,无需恢复现场
121120
if dfs(i+1, t/gcd(t, d), isLimit && d == low) {
121+
ans[i] = '0' + byte(d)
122122
return true
123123
}
124124
}

0 commit comments

Comments
 (0)