力扣 2601. 质数减法运算

读研读麻了,刷刷题恢复心情。该找工作了,还在接老师画的饼,组会被喷,无限循环。搞了一年多课题,可能连水刊都发不了。以后会更一些力扣和图学习相关论文或者比赛方面的内容。

题目链接: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)。

你可能感兴趣的:(leetcode,算法)