LeetCode 3007.价值和小于等于K的最大数字

题目描述

原题链接:LeetCode 3007.价值和小于等于K的最大数字

解题思路

由于 1 ≤ k ≤ 1 0 15 1 \le k \le 10^{15} 1k1015,所以要控制时间复杂度在 o ( l o g n ) o(logn) o(logn)。因此考虑利用二分进行查找,而且要控制每一次验证的时间复杂度在常数范围内。

计算 [ 1 , n u m ] [1,num] [1,num]的每个数的价值和

考虑用一个函数来计算 [ 1 , n u m ] [1,num] [1,num]的每个数的第 k x kx kx位的1的个数的和。再将所有的 k x kx kx位都加起来得到 [ 1 , n u m ] [1,num] [1,num]的每个数的价值和。

计算 [ 1 , n u m ] [1,num] [1,num]的每个数的第 i i i位的1个数的和

这里以6为例子,0-6的所有二进制数有:

000
001
010
011
100
101
110

最低位: [ 1 , n u m ] [1,num] [1,num]的所有奇数的个数= n u m / 2 + n u m & 1 num/2+num \& 1 num/2+num&1
次低位:我们可以将每个数都右移1位,得到:

00
01
10
11
00
01
10

可以看出有2个01,2个10,以及2个00和1个11。

最高位:同样的方法,将每个数都右移2位,得到:

0
0
1
1
0
0
1

可以看出有3个1和4个0。
我们可以发现,当最高位为1也就是6这个数的最高位时,后面两位最高只能到10也就是6的后两位,也就是2,这时一共有2+1=3种可能。而当前面两位为11时,最后一位最多也只能跟6的最后一位相同,也就是0。除开这两种跟6相同的情况,其他情况例如前面两位为10时,最后一位可以是1或0;当最高位为0时,后面两位可以是00,01,10,11四种情况。这时我们观察到当第 i i i位及之前的数构成的二进制数比相同位置的 n u m num num数小。
综合上面的结论,我们就可以令 n = n u m / 2 i n=num/2^{i} n=num/2i,统计 [ 1 , n − 1 ] [1,n-1] [1,n1]的奇数个数,再将这些个数乘以 2 i 2^{i} 2i得到初步的result。再计算 n n n是否为奇数,如果是,则再将 n n n后面能填的数的个数加上。

long long count_bitsum(long long num, int i) {
        long long res = 0;
        long long period = 1ll << i;
        long long n = num >> i;
        res += (n / 2) * period; //计算[1,n-1]的奇数个数并乘以可以以这些奇数为开头后面能填的数的个数
        res += (num % period + 1) * (n & 1); //计算跟num前i位相同的时候后面能填的数的个数以及num的前i位是否是一个奇数
        return res;
    }

完整代码

class Solution {
public:
    long long count_bitsum(long long num, int i) {
        long long res = 0;
        long long period = 1ll << i;
        long long n = num >> i;
        res += (n / 2) * period;
        res += (num % period + 1) * (n & 1);
        return res;
    }
    long long count_sum(long long num, int x) {
        long long res = 0;
        int length = 64 - __builtin_clzll(num);
        for(int i = x-1; i <= length; i += x) {
            res += count_bitsum(num, i);
        }
        return res;
    }
    long long findMaximumNumber(long long k, int x) {
        long long l = 1, r = (k+1) << x;
        while(l <= r) {
            long long mid = (l+r) >> 1;
            if(count_sum(mid, x) <= k) {
                l = mid+1;
            } else {
                r = mid-1;
            }
        }
        return r;
    }
};

参考文献

https://leetcode.cn/problems/maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k/solutions/2603673/er-fen-da-an-shu-wei-dpwei-yun-suan-pyth-tkir/

https://leetcode.cn/problems/maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k/solutions/2885442/jie-zhi-he-xiao-yu-deng-yu-k-de-zui-da-s-70ed/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值