动态规划-数位dp-600. 不含连续1的非负整数

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];
    }

  

扫描二维码关注公众号,回复: 11213131 查看本文章

猜你喜欢

转载自www.cnblogs.com/hyserendipity/p/12905712.html