首页 > 其他分享 >力扣刷题——3007.价值和小于等于 K 的最大数字

力扣刷题——3007.价值和小于等于 K 的最大数字

时间:2024-09-01 10:15:18浏览次数:15  
标签:tem 周期 long 力扣 3007 num 14 价值 刷题

根据题意,不难想到该题的暴力解法,从数字1开始,逐个累加。每次检查由当前数字num所构成的累加价值是否大于k,假如为真,那么可以输出上一个数字,即num-1

class Solution {
public:
    long long findMaximumNumber(long long k, int x) {
        long long subSum = 0;
        for(long long num = 1; ; num++)
        {
            int tem = num;
            while(tem)
            {
                tem = tem >> (x - 1);
                subSum += tem & 1;
                tem = tem >> 1;
            }
            if(subSum > k)
                return num - 1;
        }
    }
};

但是会超时,重新思考问题,由于本质上是一个查找问题,并且在暴力搜索的过程中,累加价值一直在增加。因此可知累加价值是一个单调增加的数列,可以通过二分查找的方式减少搜索的次数。若使用二分查找,需要考虑两个问题:第一,二分的初始左右边界如何界定;第二,如何快速的求得当前所查找数值的累加价值。
对于第一个问题,左边界比较好确定,应当为1。设定右边界可以这样思考:假定一个极限情况,k的价值为0,那么num = (k + 1) << x时,num的价值为1,在这种情况下,num的第x位为1(num的价值至少为1)的数字组合一共有((k + 1) << x) - (1 << x) + 1种,那么该数值的累加价值一定大于k

对于第二个问题,观察下表,之后经过归纳可以发现,一个数值的价值有周期性规律,当x = 2时,第一种周期为4,第一种周期的前半周期提供的价值为0,而后半周期提供的价值为1;第二种周期则为16。可以计算一个数字满足几个周期,然后再分别计算每个周期分别能提供多少价值,将它们累加起来就得到了累加价值。
x=2num=14为例子,第一种周期,每4个数提供两个价值;第二种周期,每16个数提供8个价值:
首先计算第一种周期能够提供多少价值,对于完整的提供一个周期的价值,计算公式为((14 + 1) / pow(2,2)) * pow(2,1) = 6 ,乘号左边代表数字中存在多少个完整的第一周期,右边则代表每满足一个第一种周期会提供多少价值。此外,注意到14在不完整的第一种周期内,有部分在第一周期的下半周期内(12,13位于上半周期,14则位于下半周期),因此还需把这部分提供的价值加上,计算公式为((14 + 1) % pow(2,2)) - pow(2,1) = 1。相加后,得到了第一周期提供给14的累加价值7
因为14不存在完整的第二种周期,所以14从第二种周期的部分下半周期获得价值,计算公式为((14 + 1) % pow(2,4)) - pow(2,3) = 7,则第二种周期提供给14的累加价值为7

x num 二进制表示 价值 累加价值
2 0 0000 0 0
2 1 0001 0 0
2 2 0010 1 1
2 3 0011 1 2
2 4 0100 0 2
2 5 0101 0 2
2 6 0110 1 3
2 7 0111 1 4
2 8 1000 1 5
2 9 1001 1 6
2 10 1010 2 8
2 11 1011 2 10
2 12 1100 1 11
2 13 1101 1 12
2 14 1110 2 14
2 15 1111 2 16

实现代码如下:

    long long getPeriodPrice(long long num, int x)
    {
        long long period = 1LL << x;
        //计算完整的周期提供的价值
        long long res = (num + 1) / period * pow(2, x - 1);
        //计算不完整的周期提供的价值
        if((num + 1) % period >= (period >> 1))
            res += (num + 1) % period - (period >> 1);   
        return res;
    }

    long long getAccuPrice(long long num, int x)
    {
        int bitNum = 0;
        long long tem = num;
        while(tem)
        {
            tem = tem >> 1;
            bitNum++;
        }

        long long res = 0;
        for(int i = x; i <= bitNum; i += x)
        {
            res += getPeriodPrice(num, i);
        }
        return res;
    }

    long long findMaximumNumber(long long k, int x) {
        long long left = 1, right = (k + 1) << x;

        while(left < right)
        {
            long long mid = (left + right + 1) / 2;
            long long a = getAccuPrice(mid, x);
            if(a > k)
            {
                right = mid - 1;
            }
            else
            {
                left = mid;
            }
        }
        return left;
    }

标签:tem,周期,long,力扣,3007,num,14,价值,刷题
From: https://www.cnblogs.com/yuhixyui/p/18383694

相关文章

  • c语言--力扣简单题目(两数之和)两种方法讲解
    题目如下:给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。你可以按任意顺序返回答案。示例1:输入:nums=[2,7,11,15],ta......
  • leetcode刷题day4|链表部分(24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、
    前言:链表练习的第二天,对链表的理解加深了24.两两交换链表中的节点这个题一开始的思路是用cur和next两个指针来做,但是绕来绕去绕迷糊了,最后超时了。把错误的代码放在下面警醒大家:主要问题出现在这两行代码,next.next发生了更改。next.next=next.next.next;next.next.nex......
  • leetcode刷题day3|链表部分( 203.移除链表元素、707.设计链表、206.反转链表)
    前言:链表部分之前刷过一些题,掌握的还可以,希望可以顺利把这部分题刷完。203.移除链表元素思路:自己创建一个头节点,使新的头节点指向旧的头节点。错误尝试:一开始考虑的比较复杂,设置了指针pre,能够想到直接比较cur.next.val和val的值会使代码更加简洁,但也要注意想清楚如果删除......
  • Mysql基础练习题 596.查询至少有5个学生的所有班级 (力扣)
    596.查询至少有5个学生的所有班级建表插入数据:CreatetableIfNotExistsCourses(studentvarchar(255),classvarchar(255))TruncatetableCoursesinsertintoCourses(student,class)values('A','Math')insertintoCourses(student,class)values(......
  • 【dp力扣】买卖股票的最佳时机III
    目录审题通过动态规划固定套路思考:1、定义状态表示(关键)2、推导状态转移方程(重点)对于buy(可买入股票):回顾状态表示:第一种情况:第二种情况:联立两种情况(取两种情况的最大值):​对于own(持有股票)回顾状态表示:第一种情况:第二种情况:(最终结果)联立两种情况(还是取max):3、初......
  • Mysql基础练习题 595.大的国家 (力扣)
            如果一个国家满足下述两个条件之一,则认为该国是大国:面积至少为300万平方公里(即,3000000km2),或者人口至少为2500万(即25000000)编写解决方案找出大国的国家名称、人口和面积,以任意顺序返回结果表。建表插入数据:CreatetableIfNotExistsWorld......
  • 力扣134.加油站
    classSolution{  //定义一个方法,用于判断是否可以完成环路行驶  publicintcanCompleteCircuit(int[]gas,int[]cost){    //初始化当前累加油量和总油量差值    intcurSum=0;    inttotalSum=0;    //初始化起......
  • 力扣238.除自身以外数组的乘积
    classSolution{publicint[]productExceptSelf(int[]nums){//获取数组长度intlength=nums.length;//创建一个新数组,用于存储结果int[]answer=newint[length];//初始化第一个元素为1,因为乘积不包括自身......
  • 力扣: 环形链表
    文章目录需求MapSet快慢指针结尾需求给你一个链表的头节点head,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。......
  • 力扣热题100_贪心算法_45_跳跃游戏
    文章目录题目链接解题思路解题代码题目链接45.跳跃游戏II给定一个长度为n的0索引整数数组nums。初始位置为nums[0]。每个元素nums[i]表示从索引i向前跳转的最大长度。换句话说,如果你在nums[i]处,你可以跳转到任意nums[i+j]处:0<=j<=nums[i]......