读研读麻了,刷刷题恢复心情。该找工作了,还在接老师画的饼,组会被喷,无限循环。搞了一年多课题,可能连水刊都发不了。以后会更一些力扣和图学习相关论文或者比赛方面的内容。
题目链接:https://leetcode.cn/problems/prime-subtraction-operation/description/
示例 1:
输入:nums = [4,9,6,10]
输出:true
解释:
在第一次运算中:选择 i = 0 和 p = 3 ,然后从 nums[0] 减去 3 ,nums 变为 [1,9,6,10] 。
在第二次运算中:选择 i = 1 和 p = 7 ,然后从 nums[1] 减去 7 ,nums 变为 [1,2,6,10] 。
第二次运算后,nums 按严格递增顺序排序,因此答案为 true 。
示例 2:
输入:nums = [6,8,11,12]
输出:true
解释:nums 从一开始就按严格递增顺序排序,因此不需要执行任何运算。
思路:先筛质数,然后对每个nums[i]选最大的质数p,并且保证p < nums[i] - nums[i - 1](对第一个数,p < nums[i])
超笨重的原始代码:
class Solution {
public:
int vis[1005];
bool primeSubOperation(vector& nums) {
int n = nums.size();
for(int i = 2; i <= 1000; i++) {
if(!vis[i])
for(int j = i * 2; j <= 1000; j += i) {
vis[j] = 1;
}
}
for(int i = 0; i < n; i++) {
bool flag = 0;
if(i > 0) {
for(int j = nums[i]; j >= 2; j--) {
if(!vis[j] && nums[i] - j > nums[i - 1]) {
nums[i] -= j;
flag = 1;
break;
}
}
if(!flag) {
if(nums[i] > nums[i - 1])continue;
return false;
}
}
else {
for(int j = nums[i]; j >= 2; j--) {
if(!vis[j] && nums[i] - j > 0) {
nums[i] -= j;
break;
}
}
}
}
return true;
}
};
前面找质数使用了直接遍历,其实可以二分。也就是大佬们的解法:
找最大的p 满足: nums[i] - p > num[i - 1], 也就是找小于nums[i] -nums[i-1]的最大值,那么可以用lower_bound()找大于等于nums[i] -nums[i-1]的第一个值,它前一个值就是要找的p,所以是*–lower_bound(primes.begin(), primes.end(), nums[i] - num[i - 1])。 如果lower_bound(primes.begin(), primes.end(), nums[i] - num[i - 1])是第0个数,也就是说没有质数满足条件,那么就令p等于0,不操作了。
以后不知道lower_bound怎么写的时候,应该可以直接列个式子看看。推出p <一个式子,lower_bound里就怎么填。
可以用pre表示前一个数,这里pre是严格小于nums[i]的,所以设置pre=0,那么nums[i] - pre > 0, 表示第一个数的边界值
c++
int vis[1005];
vector primes;
class Solution {
public:
bool primeSubOperation(vector& nums) {
int n = nums.size();
primes.push_back(0);
for(int i = 2; i <= 1000; i++) {
if(!vis[i]) {
primes.push_back(i);
for(int j = i * 2; j <= 1000; j += i) {
vis[j] = 1;
}
}
}
int pre = 0;
for(int x : nums) {
if(x <= pre)return false;
pre = x - *--lower_bound(primes.begin(), primes.end(), x - pre);
}
return true;
}
};
python
class Solution:
def primeSubOperation(self, nums: List[int]) -> bool:
vis = {}
v = [0]
for i in range(2, 1000):
if vis.get(i, 0) == 0:
v.append(i)
for j in range(i * i, 1000, i):
vis[j] = 1
pre = 0
for x in nums:
if x <= pre:
return False
pre = x - v[bisect_left(v, x - pre) - 1]
return True
函数积累:
c++
lower_bound(l,r,x)返回大于等于x的第一个值
upper_bound(l,r,x)返回大于x的第一个值
python
index1 = bisect(ls, x) #第1个参数是列表,第2个参数是要查找的数,返回值为索引
index2 = bisect_left(ls, x)
index3 = bisec_right(ls, x)
bisect.bisect和bisect.bisect_right返回大于x的第一个下标(相当于C++中的upper_bound),bisect.bisect_left返回大于等于x的第一个下标(相当于C++中的lower_bound)。