1. 题目描述
给定一个正整数 n
,找出小于或等于 n
的非负整数中,其二进制表示不包含 连续的1
的个数。
示例 1:
输入: 5
输出: 5
解释:
下面是带有相应二进制表示的非负整数<= 5:
0 : 0
1 : 1
2 : 10
3 : 11
4 : 100
5 : 101
其中,只有整数3违反规则(有两个连续的1),其他5个满足规则。
说明: 1 <= n <= 109
来源:力扣(LeetCode
)
链接:https://leetcode-cn.com/problems/non-negative-integers-without-consecutive-ones
2. 解答
题目要求是求小于等于中的满足非连续,非负的个数。所以这里想想就知道会有很多重复的计算,比如:
输入:5或者6
输出:5
解释:6=>110,不满足,故而为5.
那么我们如果需要求一个很大的数的时候,如果采用朴素的做法,就需要从 0 0 0到这个数进行判断,重复很多已经计算过的操作。
2.1 朴素解
一定会通不过,因为范围为 1 0 9 10^9 109,比较大,而暴力判断从 0 0 0到 1 0 9 10^9 109肯定不现实。比如下面的代码:
class Solution {
public int findIntegers(int n) {
if(n <= 2) return n + 1;
return verify(n) ? 1 + findIntegers(n - 1): findIntegers(n - 1);
}
private boolean verify(int n) {
if(n < 0) return false;
int base = 3;
while(n > 0){
if((base & n) == 3) return false;
n = n >>> 1;
}
return true;
}
}
甚至会导致栈溢出错误:
2.2 dp求解
参考解题区域【宫水三叶】的解答,地址。
使用dp[n]
表示有效二进制数目为n
的时候,满足题意的数目统计。
class Solution {
public int findIntegers(int n) {
int[] dp = new int[32]; // int类型的二进制位数最多为32位
dp[0] = 1;
dp[1] = 2;
for (int i = 2; i < 32 ; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
String str = getBinary(n);
int res = 0, len = str.length();
for (int i = 0; i < len; i++) {
if(str.charAt(i) == '0')
continue;
res += dp[len - i - 1];
if(i != 0 && str.charAt(i - 1) == '1'){
// 本身不满足,直接返回
return res;
}
}
return res + 1; // n本身满足,需要加1
}
private String getBinary(int num){
StringBuilder sb = new StringBuilder();
while(num > 0){
sb.append(num & 1);
num >>= 1;
}
return sb.reverse().toString();
}
}
Thanks