2020-05-17 16:31:41
问题描述:
给定一个正整数 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
问题求解:
解法一:计算至少有一次出现连续1的个数
int[] digits = new int[32]; int[][][][] dp = new int[32][2][2][2]; public int findIntegers(int num) { int total = num + 1; int pos = 0; while (num > 0) { digits[pos++] = num % 2; num /= 2; } for (int i = 0; i < 32; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { Arrays.fill(dp[i][j][k], -1); } } } return total - dfs(pos - 1, 1, 0, 0); } private int dfs(int pos, int limit, int prev, int f) { if (pos == -1) return f == 1 ? 1 : 0; if (dp[pos][limit][prev][f] != -1) return dp[pos][limit][prev][f]; dp[pos][limit][prev][f] = 0; int up = limit == 1 ? digits[pos] : 1; for (int i = 0; i <= up; i++) { int flag = 0; if (prev == 1 && i == 1) flag = 1; dp[pos][limit][prev][f] += dfs(pos - 1, limit == 1 && i == up ? 1 : 0, i, f == 1 || flag == 1 ? 1 : 0); } return dp[pos][limit][prev][f]; }
解法二:直接计算不含连续1的个数
int[] digits = new int[32]; int[][][] dp = new int[32][2][2]; public int findIntegers(int num) { int pos = 0; while (num > 0) { digits[pos++] = num % 2; num /= 2; } for (int i = 0; i < 32; i++) { for (int j = 0; j < 2; j++) { Arrays.fill(dp[i][j], -1); } } return dfs(pos - 1, 1, 0); } private int dfs(int pos, int limit, int prev) { if (pos == -1) return 1; if (dp[pos][limit][prev] != -1) return dp[pos][limit][prev]; dp[pos][limit][prev] = 0; int up = limit == 1 ? digits[pos] : 1; for (int i = 0; i <= up; i++) { if (i == 1 && prev == 1) continue; dp[pos][limit][prev] += dfs(pos - 1, limit == 1 && i == up ? 1 : 0, i); } return dp[pos][limit][prev]; }