- 数字在升序数组中出现的次数
class Solution
{
public:
int GetNumberOfK(vector<int>& nums, int k)
{
size_t left = 0;
size_t right = nums.size();
size_t mid1 = -1;
/*
* 用二分法的思想寻找 k 的边界
*/
// 寻找 k 的左边界下标
while(left < right)
{
mid1 = left + (right - left) / 2;
if(nums[mid1] > k)
{
right = mid1;
}
else if(nums[mid1] < k)
{
left = mid1 + 1;
}
else
{
// mid1 == left 防止越界访问
if(mid1 == left || nums[mid1 - 1] != k)
{
break;
}
else
{
right = mid1;
}
}
}
// 说明 k 不存在
if(left >= right)
{
return 0;
}
left = 0;
right = nums.size();
size_t mid2 = -1;
while(left < right)
{
mid2 = left + (right - left) / 2;
if(nums[mid2] > k)
{
right = mid2;
}
else if(nums[mid2] < k)
{
left = mid2 + 1;
}
else
{
if(mid2 == right ||nums[mid2 + 1] != k)
{
break;
}
else
{
left = mid2 + 1;
}
}
}
return mid2 - mid1 + 1;
}
};
- 整数转换
class Solution
{
public:
int convertInteger(int A, int B)
{
// ^异或 相同为0,相异为1
int C = A ^ B;
int ret = 0;
for(size_t i = 0; i < 32; ++i)
{
// 有多少个1,就有多少位不同
if(C & (1 << i))
{
++ret;
}
}
return ret;
}
};
- 至少是其他数字两倍的最大数
class Solution
{
public:
int dominantIndex(vector<int>& nums)
{
if(nums.size() < 2)
{
return 0;
}
// max 记录最大
// sec 记录次大
int ret = 0;
int max = nums[0];
int sec = nums[1];
if(sec > max)
{
swap(sec, max);
ret = 1;
}
for(size_t i = 2; i < nums.size(); ++i)
{
if(nums[i] > max)
{
sec = max;
max = nums[i];
ret = i;
}
else if(nums[i] > sec)
{
sec = nums[i];
}
}
if(max >= 2 * sec)
{
return ret;
}
return -1;
}
};
- 寻找数组的中心下标
class Solution
{
public:
int pivotIndex(vector<int>& nums)
{
int total = 0;
for(int n : nums)
{
total += n;
}
int sum = 0;
for(size_t i = 0; i < nums.size(); ++i)
{
// 假设 i 是中心下标, sum 是一边的和
if(2 * sum + nums[i] == total)
{
return i;
}
sum += nums[i];
}
return -1;
}
};
- 多数元素
// 投票算法
class A
{
public:
int _val;
int _count = 0;
};
class Solution
{
public:
int majorityElement(vector<int>& nums)
{
A a;
for(int n : nums)
{
if(a._count == 0)
{
a._val = n;
a._count = 1;
}
else if(n == a._val)
{
++a._count;
}
else
{
--a._count;
}
}
return a._val;
}
};
- 除自身以外数组的乘积
class Solution
{
public:
vector<int> productExceptSelf(vector<int>& nums)
{
vector<int> v;
v.resize(nums.size());
v[0] = 1;
// 将累乘分两次进行
// 第一次将每个位置的前缀元素累乘放进数组中
for(size_t i = 1; i < nums.size(); ++i)
{
v[i] = v[i-1] * nums[i-1];
}
// 第二次将每个位置的后缀元素累乘 与数组中对应位置的前缀积相乘 放进数组中
int result = 1;
for(size_t i = nums.size() - 2; i != -1; --i)
{
result *= nums[i+1];
v[i] *= result;
}
return v;
}
};
- 不用加减乘除做加法
class Solution
{
public:
int Add(int num1, int num2)
{
// num1 保存不进位的数据
// num2 保存进位的数据
while(num2)
{
int tmp = num1 ^ num2;
num2 = (num1 & num2) << 1;
num1 = tmp;
}
return num1;
}
};
- 找到所有数组中消失的数字
class Solution
{
public:
vector<int> findDisappearedNumbers(vector<int>& nums)
{
vector<int> v;
size_t n = nums.size();
// 数据存在,将相应下标位置的数据+=n
for (size_t i = 0; i < n; ++i)
{
nums[(nums[i] - 1) % n] += n;
}
// 只要数据不大于n,其相应的下标就是消失的数字
for (size_t i = 0; i < n; ++i)
{
if (nums[i] <= n)
{
v.push_back(i + 1);
}
}
return v;
}
};
- 单词倒排
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
string s;
getline(cin, s);
int i = s.size() - 1;
int start = 0;
int end = 0;
while(i >= 0)
{
// 逆序遍历,遇到单词就记录单词起始下标[start, end]
if(isalpha(s[i]))
{
end = i;
}
while(i >= 0 && isalpha(s[i]))
{
--i;
}
start = i + 1;
for(int j = start; j <= end; ++j)
{
cout << s[j];
}
// 单词之后紧跟空格
while(i >= 0 && !isalpha(s[i]))
{
--i;
}
cout << " ";
}
}
- 珠玑妙算
class Solution
{
// 四种颜色的枚举
enum
{
BLUE,
GREEN,
RED,
YELLOW
};
public:
vector<int> masterMind(string solution, string guess)
{
vector<int> v = {0, 0};
vector<int> vs = {0,0,0,0};
vector<int> vg = {0,0,0,0};
for(int i = 0; i < 4; ++i)
{
if(guess[i] == solution[i])
{
// "猜中"
++v[0];
}
else // 伪猜中“”
{
switch (guess[i])
{
case 'B':
++vg[BLUE];
break;
case 'G':
++vg[GREEN];
break;
case 'R':
++vg[RED];
break;
case 'Y':
++vg[YELLOW];
break;
default:
break;
}
switch (solution[i])
{
case 'B':
++vs[BLUE];
break;
case 'G':
++vs[GREEN];
break;
case 'R':
++vs[RED];
break;
case 'Y':
++vs[YELLOW];
break;
default:
break;
}
}
}
for(int i = 0; i < 4; ++i)
{
// 各个颜色“伪猜中”的次数相加
v[1] += (vs[i] < vg[i] ? vs[i] : vg[i]);
}
return v;
}
};
- 寻找峰值
class Solution
{
public:
int findPeakElement(vector<int>& nums)
{
int left = 0;
int right = nums.size() - 1;
// 对首尾元素进行排查
if(nums.size() == 1 || nums[left] > nums[left + 1])
{
return 0;
}
if(nums[right] > nums[right - 1])
{
return right;
}
// 因为是任意一个峰值元素,可以用二分法
int mid = 0;
while(left < right)
{
mid = left + (right - left) / 2;
if(nums[mid] < nums[mid + 1])
{
left = mid + 1;
}
else
{
right = mid;
}
}
return left;
}
};
- 数对
int main()
{
long long n, k;
cin >> n >> k;
if(k == 0)
{
printf("%lld", n*n);
return 0;
}
long long count = 0;
for(long long y = k + 1; y <= n; ++y)
{
count += (n / y) * (y - k) + ((n % y < k) ? 0 : (n % y - k + 1));
}
printf("%lld", count);
return 0;
}
解析:
由于需要满足条件x % y >= k
,所以y
的取值范围必须是[k+1, n]
(如果y <= k
,x % y
的结果一定在会小于k
)。
所以可以通过对y
的每一个取值,来统计满足x % y >= k
条件的x
的个数。
对于每一个特定的y
值,x
的取值区间都在[1, n]
。
可以根据y
的大小为单位,对x
的取值划分区间如下:
一个可以划分t = n / y
个完整的区间,每个区间满足条件x % y >= k
的x
值有y - k
个,所以t
个区间一共有(n / y) * (y - k)
个。
最后剩余一个不完整的区间的个数是n % y
,如果n % y < k
,那么剩余区间里x % y >= k
的个数为0,否则个数为n % y - k + 1
个。
上面的计算前提是k != 0
,如果k == 0
,直接返回n * n
。