美文网首页
【教3妹学编程-算法题】价值和小于等于 K 的最大数字

【教3妹学编程-算法题】价值和小于等于 K 的最大数字

作者: 程序员小2 | 来源:发表于2024-02-10 21:37 被阅读0次
瑟瑟发抖

3妹:2哥,新年好鸭~
2哥 : 新年好,3妹这么早啊
3妹:是啊,新年第一天要起早,这样就可以起早一整年
2哥 :得,我还不了解你,每天晒到日上三竿
3妹:嘿嘿嘿嘿,一年是有300多天起的比较晚~
2哥:3妹,过完年什么时候回来啊
3妹:最少也要初七吧,好不容易回家一趟多陪陪父母。
2哥:好吧,回家也也要记得每天刷题啊,今天有一道“最大”的题目, 让我们先做一下吧~

吃瓜

题目:

给你一个整数 k 和一个整数 x 。

令 s 为整数 num 的下标从 1 开始的二进制表示。我们说一个整数 num 的 价值 是满足 i % x == 0 且 s[i] 是 设置位 的 i 的数目。

请你返回 最大 整数 num ,满足从 1 到 num 的所有整数的 价值 和小于等于 k 。

注意:

一个整数二进制表示下 设置位 是值为 1 的数位。
一个整数的二进制表示下标从右到左编号,比方说如果 s == 11100 ,那么 s[4] == 1 且 s[2] == 0 。

示例 1:

输入:k = 9, x = 1
输出:6
解释:数字 1 ,2 ,3 ,4 ,5 和 6 二进制表示分别为 "1" ,"10" ,"11" ,"100" ,"101" 和 "110" 。
由于 x 等于 1 ,每个数字的价值分别为所有设置位的数目。
这些数字的所有设置位数目总数是 9 ,所以前 6 个数字的价值和为 9 。
所以答案为 6 。
示例 2:

输入:k = 7, x = 2
输出:9
解释:由于 x 等于 2 ,我们检查每个数字的偶数位。
2 和 3 在二进制表示下的第二个数位为设置位,所以它们的价值和为 2 。
6 和 7 在二进制表示下的第二个数位为设置位,所以它们的价值和为 2 。
8 和 9 在二进制表示下的第四个数位为设置位但第二个数位不是设置位,所以它们的价值和为 2 。
数字 1 ,4 和 5 在二进制下偶数位都不是设置位,所以它们的价值和为 0 。
10 在二进制表示下的第二个数位和第四个数位都是设置位,所以它的价值为 2 。
前 9 个数字的价值和为 6 。
前 10 个数字的价值和为 8,超过了 k = 7 ,所以答案为 9 。

提示:

1 <= k <= 10^15
1 <= x <= 8

思路:

思考

设 nums\textit{nums}nums 的异或和为 sss。

二分+DP,
由于 num 越大,价值和也越大,有单调性,可以二分答案。

于是问题转换成:计算从 1到 num的价值和,判断其是否 ≤k。

java代码:

class Solution {
    public long findMaximumNumber(long k, int x) {
        this.x = x;
        // 开区间二分,原理见 https://www.bilibili.com/video/BV1AP41137w7/
        long left = 0;
        long right = (k + 1) << x;
        while (left + 1 < right) {
            long mid = (left + right) >>> 1;
            if (countDigitOne(mid) <= k) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return left;
    }

    private int x;
    private long num;
    private long memo[][];

    private long countDigitOne(long num) {
        this.num = num;
        int m = 64 - Long.numberOfLeadingZeros(num);
        memo = new long[m][m + 1];
        for (long[] row : memo) {
            Arrays.fill(row, -1);
        }
        return dfs(m - 1, 0, true);
    }

    private long dfs(int i, int cnt1, boolean isLimit) {
        if (i < 0) return cnt1;
        if (!isLimit && memo[i][cnt1] != -1) return memo[i][cnt1];
        int up = isLimit ? (int) (num >> i & 1) : 1;
        long res = 0;
        for (int d = 0; d <= up; d++) { // 枚举要填入的数字 d
            res += dfs(i - 1, cnt1 + (d == 1 && (i + 1) % x == 0 ? 1 : 0), isLimit && d == up);
        }
        if (!isLimit) memo[i][cnt1] = res;
        return res;
    }
}

相关文章

网友评论

      本文标题:【教3妹学编程-算法题】价值和小于等于 K 的最大数字

      本文链接:https://www.haomeiwen.com/subject/lxpradtx.html