不含连续1的非负整数
给定一个正整数 n ,请你统计在 [0, n] 范围的非负整数中,有多少个整数的二进制表示中不存在连续的 1 。
1. 数位dp
class Solution {
public:
int findIntegers(int n) {
int m= __lg(n); //转字符串逐位递归分析
int memo[m+1][2];
memset(memo,-1,sizeof(memo));
function<int(int, bool, bool)> f = [&](int i,bool pre, bool is_limit) -> int {
if (i < 0) return 1;//边界直接返回
if (!is_limit&&memo[i][pre]!= -1) //已经存储过,直接剪枝返回
return memo[i][pre];
int res = 0; //计算
int up = is_limit ? n>>i&1 : 1; // 受限取对应位值
//做选择
res += f(i - 1, 0, is_limit && 0 == up);//取0
if(up==1&&pre==0) res+= f(i - 1, 1, is_limit && 1 == up);//取1
if (!is_limit) //记录非限制数
memo[i][pre] = res;
return res;
};
return f(m,0,true); //从下标m开始,方便位运算
}
};
2. 套用模板
class Solution {
public:
int findIntegers(int n) {
string s = bitset<32>(n).to_string();//这里直接转化为字符串
int m = s.size();
int dp[m][2];
memset(dp, -1, sizeof(dp));
function<int(int, bool, bool)>f = [&](int i, bool is_pre1, bool is_limit)->int {
if(i==m) return 1;
if(!is_limit && dp[i][is_pre1] > 0) return dp[i][is_pre1];
int res = 0;
for(int d=0, up = is_limit ? s[i]-'0': 1; d <= up; ++d){
if( d== 1 && is_pre1) continue;
res += f(i+1, d == 1, is_limit && d==up);
}
if(!is_limit) dp[i][is_pre1] = res;
return res;
};
return f(0, false, true);//从下标0开始
}
};