LC 869. 重新排序得到 2 的幂
题目描述
这是 LeetCode 上的 869. 重新排序得到 2 的幂 ,难度为 中等。
给定正整数 N
,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。
如果我们可以通过上述方式得到 $2$ 的幂,返回 true
;否则,返回 false
。
示例 1:1
2
3输入:1
输出:true
示例 2:1
2
3输入:10
输出:false
示例 3:1
2
3输入:16
输出:true
示例 4:1
2
3输入:24
输出:false
示例 5:1
2
3输入:46
输出:true
提示:
$1 <= N <= 10^9$
打表 + DFS
一个朴素的做法是对 $n$ 进行重排,然后检查重排后的数值是否属于 $2$ 的幂。
由于 $2$ 的幂数固定,我们可以先通过「打表」将范围落在 $[1, 1e9]$ 以内的 $2$ 的幂预处理出来,这样我们可以在 $O(1)$ 的复杂度内判断某个数是否为 $2$ 的幂。
重排的过程则是 DFS
实现。
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class Solution {
static Set<Integer> set = new HashSet<>();
static {
for (int i = 1; i < (int)1e9+10; i *= 2) set.add(i);
}
int m;
int[] cnts = new int[10];
public boolean reorderedPowerOf2(int n) {
while (n != 0) {
cnts[n % 10]++;
n /= 10;
m++;
}
return dfs(0, 0);
}
boolean dfs(int u, int cur) {
if (u == m) return set.contains(cur);
for (int i = 0; i < 10; i++) {
if (cnts[i] != 0) {
cnts[i]--;
if ((i != 0 || cur != 0) && dfs(u + 1, cur * 10 + i)) return true;
cnts[i]++;
}
}
return false;
}
}
- 时间复杂度:打表预处理所有 $2$ 的幂放到本地运行为 $O(1)$,放到 $OJ$ 运行则是 $O(C)$,$C$ 为常数,约为 $30$。处理处 $cnts$ 数组的复杂度为 $O(\log{n})$;重排的复杂度为 $O((\log{n})!)$,判断是否为 $2$ 的幂的复杂度为 $O(1)$。整体复杂度为 $O((\log{n})!)$。
- 空间复杂度:$O(C)$,其中 $C$ 为常数,约为 $40$。
打表 + 词频统计
解法一,我们发现复杂度上界取决于对 $n$ 的重排,同时数据范围内的 $2$ 的幂数量很少。
因此有效降低复杂度(避免重排)的做法是,直接枚举所有的 $2$ 的幂 $x$,检查 $x$ 的词频是否与 $n$ 相同。
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class Solution {
static Set<Integer> set = new HashSet<>();
static {
for (int i = 1; i < (int)1e9+10; i *= 2) set.add(i);
}
public boolean reorderedPowerOf2(int n) {
int[] cnts = new int[10];
while (n != 0) {
cnts[n % 10]++;
n /= 10;
}
int[] cur = new int[10];
out:for (int x : set) {
Arrays.fill(cur, 0);
while (x != 0) {
cur[x % 10]++;
x /= 10;
}
for (int i = 0; i < 10; i++) {
if (cur[i] != cnts[i]) continue out;
}
return true;
}
return false;
}
}
- 时间复杂度:打表预处理所有 $2$ 的幂放到本地运行为 $O(1)$,放到 $OJ$ 运行则是 $O(C)$,$C$ 为常数,约为 $30$。检查所有 $2$ 的幂的词频是否与 $n$ 词频相同复杂度为 $O(C \log{n})$。整体复杂度为 $O(C \log{n})$。
- 空间复杂度:$O(C)$,其中 $C$ 为常数,约为 $40$。
最后
这是我们「刷穿 LeetCode」系列文章的第 No.869
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!