继续二分专题 感觉已经比较熟练了
/**
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is higher than the picked number
* 1 if num is lower than the picked number
* otherwise return 0
* int guess(int num);
*/
class Solution {
public:
int guessNumber(int n) {
int i=1,j=n;
while(i<=j)
{
int mid=(j-i)/2+i;
if(guess(mid)==-1)
{
j=mid-1;
}
else if(guess(mid)==1)
{
i=mid+1;
}
else return mid;
}
return i;
}
};
1539. 第 k 个缺失的正整数 - 力扣(LeetCode)
这题数字量比较小 所以我选择了暴力,需要注意的是brr记得初始化为0,我开始没初始化样例没过
class Solution {
public:
int findKthPositive(vector<int>& arr, int k) {
int j=0;
int len=arr.size();
int brr[100010]={0};
for(int i=0;i<len;i++)
{
brr[arr[i]]=1;
}
for(int i=1;i<=10000;i++)
{
if(brr[i]==0)j++;
if(j==k)return i;
}
return 1;
}
};
理解h指数的含义,用二分法确定mid指向的数字是否等于(n-mid)即满足符合条件的论文数,
大于当前papers即right=mid-1;小于则left=mid+1;
class Solution {
public:
int hIndex(vector<int>& citations) {
int n = citations.size();
int left = 0, right = n - 1;
//利用数组已排序的特性,直接计算papers = n - mid
//比较citations[mid]与papers的关系
while (left <= right) {
int mid = left + (right - left) / 2;
int papers = n - mid; // 引用次数≥citations[mid]的论文数
if (citations[mid] == papers) {
return papers;
} else if (citations[mid] < papers) {
left = mid + 1;
} else {
right = mid - 1;
}
}
//循环结束时,left指向第一个满足citations[i] >= n - i的位置
//h指数即为n - left
return n - left;
}
};
这道hard我看的zerotrac题解,是题解里面第一个,目前还是太菜了,没有养成数学思维
然后deepseek写了一个二分法 要处理溢出问题 对我来说很难想到 感觉自己缺乏处理大数的经验
class Solution {
public:
string smallestGoodBase(string n) {
long long num=stol(n);
long long ans=num-1;//如果没找到则是num-1进制,因为最后一个数字必定是1
//s就是1的个数
for(int s=59;s>=2;s--)
{
//k是进制数
int k= pow(num,1.0/s);
if(k>1)
{
long long sum=1,mul=1;//sum底数为1是因为最小位数为1
//计算k进制数字和,因为底数为1所以mul*=k;
for(int i=1;i<=s;i++)
{
mul*=k;
sum+=mul;
}
//如果找到了返回k
if(sum==num)
{
ans=k;
break;
}
}
}
return to_string(ans);
}
};
//deepseek写的二分法也可参考
class Solution {
public:
string smallestGoodBase(string n) {
long long num = stol(n);
long long ans = num - 1; // 最大可能的进制
// s表示1的个数(从大到小枚举)
for (int s = log2(num) + 1; s >= 2; s--) {
// 对每个s,用二分法找k
//2进制到 num的1/(s-1)进制
long long left = 2, right = pow(num, 1.0/(s-1)) + 1;
while (left <= right) {
long long mid = left + (right - left) / 2;
long long sum = 0;
// 用等比数列求和公式计算
bool overflow = false;
for (int i = 0; i < s; i++) {
if (sum > (num - 1) / mid) { // 防溢出检查
overflow = true;
break;
}
sum = sum * mid + 1;
}
if (overflow || sum > num) {
right = mid - 1;
} else if (sum < num) {
left = mid + 1;
} else {
return to_string(mid);
}
}
}
return to_string(ans);
}
};
先计算个数 在二分法
#include <algorithm>
using namespace std;
class Solution {
public:
// 计算两个数的最小公倍数
long long lcm(long long x, long long y) {
return x * y / gcd(x, y);
}
// 计算在[1, x]区间内,能被a、b、c之一整除的数的个数
long long count(long long x, long long a, long long b, long long c) {
return x / a + x / b + x / c
- x / lcm(a, b) - x / lcm(b, c) - x / lcm(a, c)
+ x / lcm(a, lcm(b, c));
}
int nthUglyNumber(int n, int a, int b, int c) {
long long left = 1, right = 2e9;
while (left < right) {
long long mid = left + (right - left) / 2;
if (count(mid, a, b, c) >= n) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};