class Solution {
public int findIntegers(int n) {
int k = 0;
for (int i = n; i >= 0; i--) {
String binaryString = Integer.toBinaryString(i);
char[] chars = binaryString.toCharArray();
boolean flag = true;
for (int j = 0; j < chars.length - 1; j++) {
char aChar = chars[j];
char aChar1 = chars[j + 1];
//49为char类型1
if (aChar == 49 && aChar1 == 49) {
flag = false;
break;
}
}
if (flag) {
k++;
}
}
return k;
}
}
这么写不是很简单吗…… 达咩!!!会得到以下结果:
因为正整数 n 可以取到
1
0
9
10^9
109,所以显然是不可能通过暴力遍历来计算答案的
思路分析:
高度为t、根结点为0的满二叉树中不包含连续1的从根结点到叶结点的路径数量,等于高度为t−1、根结点为0的满二叉树中的路径数量与高度为t-2,根结点为0的满二叉树中的路径数量之和。因此,这个问题可以通过动态规划解决:
d
p
[
t
]
=
d
p
[
t
−
1
]
+
d
p
[
t
−
2
]
dp[t]=dp[t−1]+dp[t−2]
dp[t]=dp[t−1]+dp[t−2]
贴一个官方题解的注释版
class Solution {
public int findIntegers(int n) {
// 预处理第 i 层满二叉树的路径数量
int[] dp = new int[31];
dp[0] = dp[1] = 1;
for (int i = 2; i < 31; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
// pre 记录上一层的根节点值,res 记录最终路径数
int pre = 0, res = 0;
for (int i = 29; i >= 0; --i) {
int val = 1 << i;
// if 语句判断 当前子树是否有右子树
if ((n & val) != 0) {
// 有右子树
n -= val;
res += dp[i + 1]; // 先将左子树(满二叉树)的路径加到结果中
// 处理右子树
if (pre == 1) {
// 上一层为 1,之后要处理的右子树根节点肯定也为 1
// 此时连续两个 1,不满足题意,直接退出
break;
}
// 标记当前根节点为 1
pre = 1;
} else {
// 无右子树,此时不能保证左子树是否为满二叉树,所以要在下一层再继续判断
pre = 0;
}
if (i == 0) {
++res;
}
}
return res;
}
}