Medium
题目描述
给定一个整数 n,返回将 1 到 n 的二进制表示按顺序连接形成的二进制字符串对应的十进制值,结果需要对 10^9 + 7 取模。
示例 1:
输入:n = 1
输出:1
解释:"1" 的二进制对应十进制值 1。
示例 2:
输入:n = 3
输出:27
解释:1, 2, 3 的二进制分别为 "1", "10", "11"。
连接后得到 "11011",对应十进制值 27。
示例 3:
输入:n = 12
输出:505379714
解释:连接结果为 "1101110010111011110001001101010111100"。
对应十进制值为 118505380540。
对 10^9 + 7 取模后结果为 505379714。
约束条件:
1 <= n <= 10^5
提示:
- 用递推公式表达第 n 个数的值,并考虑如何快速计算。
解题思路
这道题要求将 1 到 n 的二进制表示串联起来,然后转换为十进制数。
核心思路:
我们可以用递推的方式来解决这个问题。假设我们已经计算出了前 i-1 个数字串联的结果 result,现在要加入第 i 个数字的二进制表示。
关键观察:
- 当我们在已有的二进制串后面添加数字 i 的二进制表示时,相当于将原有结果左移 i 的二进制位数,然后加上 i
- 数字 i 的二进制位数可以通过
bit_length = floor(log2(i)) + 1计算,或者更简单地用位运算判断
算法步骤:
- 从 1 开始遍历到 n
- 对于每个数字 i,计算其二进制位数
- 将当前结果左移相应位数(相当于乘以 2^位数),然后加上 i
- 每步都要对 MOD 取模防止溢出
优化技巧:
- 可以预先计算每个数字的二进制位数,避免重复计算
- 使用位运算来判断位数变化的时机:当 i 是 2 的幂时,位数会增加 1
时间复杂度:O(n),空间复杂度:O(1)。
代码实现
class Solution {
public:
int concatenatedBinary(int n) {
const int MOD = 1e9 + 7;
long long result = 0;
int bitLength = 0;
for (int i = 1; i <= n; i++) {
// 当i是2的幂时,位长度增加1
if ((i & (i - 1)) == 0) {
bitLength++;
}
// 将result左移bitLength位,然后加上i
result = ((result << bitLength) + i) % MOD;
}
return result;
}
};
class Solution:
def concatenatedBinary(self, n: int) -> int:
MOD = 10**9 + 7
result = 0
bit_length = 0
for i in range(1, n + 1):
# 当i是2的幂时,位长度增加1
if i & (i - 1) == 0:
bit_length += 1
# 将result左移bit_length位,然后加上i
result = ((result << bit_length) + i) % MOD
return result
public class Solution {
public int ConcatenatedBinary(int n) {
const int MOD = 1000000007;
long result = 0;
int bitLength = 0;
for (int i = 1; i <= n; i++) {
// 当i是2的幂时,位长度增加1
if ((i & (i - 1)) == 0) {
bitLength++;
}
// 将result左移bitLength位,然后加上i
result = ((result << bitLength) + i) % MOD;
}
return (int)result;
}
}
var concatenatedBinary = function(n) {
const MOD = 1000000007;
let result = 0;
let shift = 0;
for (let i = 1; i <= n; i++) {
if ((i & (i - 1)) === 0) {
shift++;
}
result = ((result << shift) + i) % MOD;
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历从1到n的所有数字 |
| 空间复杂度 | O(1) | 只使用常数级别的额外空间 |