【位运算】【二分查找】【C++算法】100160价值和小于等于 K 的最大数字

简介: 【位运算】【二分查找】【C++算法】100160价值和小于等于 K 的最大数字

作者推荐

【动态规划】【字符串】扰乱字符串

本文涉及的基础知识点

二分查找算法合集

位运算

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

给你一个整数 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 <= 1015

1 <= x <= 8

二分查找

随着num的增加,价值和单调增加。这是二分查找的基础。寻找最后一个符合条件的nums,用左闭右开空间。

如何求1到num第i位的价值和。 由于0不包括1,所以本问题等效与0到num的价值和。

i==0 0 1 周期长度2
i==1 00 01 10 11… 周期长度4
i==2 000 001 010 011 100 101 110 111… 周期长度8

周期长度 1<<i 。前半个周期,全部是0,后半个周期全部是1。

[0,num]共num+1个数。

  • 完整周期数:(num+1)/(1 << i ) 每个周期有半数1
  • 不足一个周期的数有iCnt2= (num+1)%(1<<i) 1的数量为:iCnt2-- (i <<i )/2 iCnt如果小于0,取0.

代码

核心代码

这周的LeetCode C++可能有问题,总溢出,所以加了不少判断。

class Solution {
public:
  long long findMaximumNumber(long long k, int x) {
    long long left = 0, r = 5e17;
    while (r - left > 1)
    {
      const auto mid = left + (r - left) / 2;
      if (Cnt(mid, k,x) <= k)
      {
        left = mid;
      }
      else
      {
        r = mid;
      }
    }
    return left;
  }
  long long Cnt(long long mid,int k,int x )
  {
    long long llCnt = 0;
    for (int ii = x; ii <= 60; ii += x)
    {
      const long long tmp = 1LL << ii;//周期
      const long long cur1 = (mid + 1) / tmp * (tmp / 2); 
      const long long cur2 = max(0LL, (mid + 1) % tmp - tmp / 2);
      if (LLONG_MAX - llCnt < cur1)
      {
        return k + 1;
      }
      llCnt += cur1;
      
      if (LLONG_MAX - llCnt < cur2)
      {
        return k + 1;
      }
      llCnt += cur2;
    }
    return llCnt;
  }
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  
  long long k;
  int x;
  {
    Solution sln;
    k = 19, x = 6;
    auto res = sln.findMaximumNumber(k, x);
    Assert(50LL, res);
  }
  {
    Solution sln;
    k = 9, x = 1;
    auto res = sln.findMaximumNumber(k, x);
    Assert(6LL, res);
  }
  {
    Solution sln;
    k = 7, x = 2;
    auto res = sln.findMaximumNumber(k, x);
    Assert(9LL, res);
  }
  {
    Solution sln;
    k = 343883588590415, x = 1;
    auto res = sln.findMaximumNumber(k, x);
    //Assert(9LL, res);
  } 
}


相关文章
|
23天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
34 1
|
2月前
|
算法 C# 索引
C#二分查找算法
C#二分查找算法
|
2月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
671 0
高精度算法(加、减、乘、除,使用c++实现)
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
45 0
|
2月前
|
存储 算法 C语言
【C语言】二分查找算法
【C语言】二分查找算法
|
2月前
|
消息中间件 存储 算法
一文搞懂二分查找算法!
一文搞懂二分查找算法!
121 0
|
2月前
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
32 0
|
2月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
2月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
2月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)