数位DP
对于「数位 DP」题,都存在「询问 [a, b](a 和 b 均为正整数,且 a < b)
区间内符合条件的数值个数为多少」的一般形式,通常我们需要实现一个查询 [0, x]有多少合法数值的函数 int dp(int x),
然后应用「容斥原理」求解出 [a, b]的个数:dp(b) - dp(a - 1)。
暴力
采用位运算,如果存在相邻1,那么无符号右移&本身!=0,那么说明不符合题意
class Solution {
public:
int findIntegers(int n) {
int ans = n + 1;
for(int i = n; i >= 0; i--) {
if (i & (i>>>1)) {
ans--;
}
}
return ans;
}
};
树形DP
/**
* 本题解二叉树深度从1开始
* @param n
* @return
*/
public int findIntegers(int n) {
//dp[n]含义:深度为n时, 且顶点为0的满二叉树非连续1个数
int[] dp = new int[31];
dp[0] = dp[1] = 1;
//最高位为0,且为满二叉树,DP规则,dp[n] = dp[n - 1] + dp[n - 2]
for (int i = 2; i < 31; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
//整体思路为如果有右子树,说明相同高度的左子树的非连续1个数符合题意
//pre 上一层节点为0还是1
int pre = 0, res = 0;
for (int i = 29; i >= 0; --i) {
int val = 1 << i;
//如果当前位为1,说明有右子树,左边为满二叉树,则加上相同高度的左子树的dp[n]即可
if ((n & val) != 0) {
res += dp[i + 1];
//说明右子树相同两个1,直接返回
if (pre == 1) {
break;
}
pre = 1;
} else {
pre = 0;
}
//i == 0,因为101没有算上去,case需要注意
if (i == 0) {
++res;
}
}
return res;
}