LeetCode 869 重新排序得到 2 的幂
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reordered-power-of-2/
博主Github:https://github.com/GDUT-Rp/LeetCode
题目:
给定正整数 N
,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。
如果我们可以通过上述方式得到 2 的幂,返回 true
;否则,返回 false
。
示例 1:
输入:1
输出:true
示例 2:
输入:10
输出:false
示例 3:
输入:16
输出:true
示例 4:
输入:24
输出:false
示例 5:
输入:46
输出:true
提示:
1 <= N <= 1 0 9 10^9 109
解题思路:
方法一:map统计个数然后计算判断
直观想法
将 n 的十进制表示视作一个字符数组,我们可以枚举该数组的所有排列,对每个不含前导零的排列判断其对应的整数是否为 2 的幂。
这可以拆分成两个子问题:
1、枚举可能包含重复字符的数组的全排列;
2、判断一个整数是否为 2 的幂(通过位运算 n&(n-1) == 0)。
C++
class Solution {
vector<int> vis;
bool isPowerOfTwo(int n) {
return (n & (n - 1)) == 0;
}
bool backtrack(string &nums, int idx, int num) {
if (idx == nums.length()) {
return isPowerOfTwo(num);
}
for (int i = 0; i < nums.length(); ++i) {
// 不能有前导零
if ((num == 0 && nums[i] == '0') || vis[i] || (i > 0 && !vis[i - 1] && nums[i] == nums[i - 1])) {
continue;
}
vis[i] = 1;
if (backtrack(nums, idx + 1, num * 10 + nums[i] - '0')) {
return true;
}
vis[i] = 0;
}
return false;
}
public:
bool reorderedPowerOf2(int n) {
string nums = to_string(n);
sort(nums.begin(), nums.end());
vis.resize(nums.length());
return backtrack(nums, 0, 0);
}
};
Golang
func reorderedPowerOf2(n int) bool {
nums := []byte(strconv.Itoa(n))
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})
isVisiteds := make([]bool, len(nums))
var backtrack func(int, int) bool
backtrack = func(idx, num int) bool {
if idx == len(nums) {
return isPowerOfTwo(num)
}
for i, ch := range nums {
if num == 0 && ch == '0' || isVisiteds[i] {
continue
}
if i > 0 && !isVisiteds[i-1] && ch == nums[i-1] {
continue
}
isVisiteds[i] = true
if backtrack(idx+1, num*10+int(ch-'0')) {
return true
}
isVisiteds[i] = false
}
return false
}
return backtrack(0, 0)
}
func isPowerOfTwo(n int) bool {
return n&(n-1) == 0
}
Python
class Solution:
def isTwoPower(self, n: int) -> bool:
return n & (n - 1) == 0
def reorderedPowerOf2(self, n: int) -> bool:
nums = sorted(list(str(n)))
length = len(nums)
vis = [False] * length
def backTrack(self, idx: int, num: int) -> bool:
if idx == length:
return self.isTwoPower(num)
for i, ch in enumerate(nums):
# 当前数字是0,新的字符串是0就跳过避免前导数字为0
if num == 0 and ch == '0' or vis[i]:
continue
# i > 0 避免数组越界,如果前一位没被访问 && 连续两位数字相同
if i > 0 and not vis[i-1] and ch == nums[i - 1]:
continue
vis[i] = True
if backTrack(self, idx + 1, num * 10 + ord(ch) - ord('0')):
return True
vis[i] = False
return False
return backTrack(self, 0, 0)
复杂度分析
时间复杂度:
O
(
m
!
)
O(m!)
O(m!)其中
m
=
⌊
log
10
n
⌋
+
1
m=\lfloor\log_{10}n\rfloor+1
m=⌊log10n⌋+1,即
n
n
n 的十进制表示的长度。
空间复杂度:
O
(
m
)
O(m)
O(m)
方法二:预处理 + 哈希表
对于不同的整数a、b,例如a = 64, b = 46,既然 a 可以是 2 的幂,那么 b 的字符数组进行排序调整后也可以成为 2 的幂,而恰好 2 的幂的整数是有限的。
我们只需要将2的幂的数都先进行了预处理,判断十进制上每个数有多少个数,例如 256 即2、5、6的位上各为1,因此只需要对这些数进行提前预处理好存好,每一个数进行进行判断是否对应的位上有这样相等的数则知道结果。
C++
string countDigits(int n) {
string cnt(10, 0);
while (n) {
++cnt[n % 10];
n /= 10;
}
return cnt;
}
unordered_set<string> powerOf2Digits;
int init = []() {
for (int n = 1; n <= 1e9; n <<= 1) {
powerOf2Digits.insert(countDigits(n));
}
return 0;
}();
class Solution {
public:
bool reorderedPowerOf2(int n) {
return powerOf2Digits.count(countDigits(n));
}
};
Go
func reorderedPowerOf2(n int) bool {
return powerOf2Digits[countDigits(n)]
}
var powerOf2Digits = map[[10]int]bool{}
func init() {
for n := 1; n <= 1e9; n <<= 1 {
powerOf2Digits[countDigits(n)] = true
}
}
func countDigits(n int) [10]int {
var cnt [10]int
for n > 0 {
cnt[n%10]++
n /= 10
}
return cnt
}
Python
def countDigits(n: int) -> Tuple[int]:
cnt = [0] * 10
while n:
cnt[n % 10] += 1
n //= 10
return tuple(cnt)
powerOf2Digits = {countDigits(1 << i) for i in range(30)}
class Solution:
def reorderedPowerOf2(self, n: int) -> bool:
return countDigits(n) in powerOf2Digits
时间复杂度:
O
(
n
)
O(n)
O(n),统计 n 的每个数字的出现次数需要
O
(
log
n
)
O(\log n)
O(logn) 的时间。
空间复杂度:
O
(
1
)
O(1)
O(1)