本文涉及的基础知识点
C++二分查找
贪心(决策包容性)
LeetCode2601. 质数减法运算
给你一个下标从 0 开始的整数数组 nums ,数组长度为 n 。
你可以执行无限次下述运算:
选择一个之前未选过的下标 i ,并选择一个 严格小于 nums[i] 的质数 p ,从 nums[i] 中减去 p 。
如果你能通过上述运算使得 nums 成为严格递增数组,则返回 true ;否则返回 false 。
严格递增数组 中的每个元素都严格大于其前面的元素。
示例 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 从一开始就按严格递增顺序排序,因此不需要执行任何运算。
示例 3:
输入:nums = [5,8,3]
输出:false
解释:可以证明,执行运算无法使 nums 按严格递增顺序排序,因此答案是 false 。
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 1000
nums.length == n
二分查找
先修改nums[i1],后修改nums[i2] ⟺ \iff ⟺ 先修改nums[i2],后修改nums[i1]
故可以按下标从小到大修改。
贪心:nums[i]在大于nums[i-1]的情况下尽可能的小。可用决策包容性证明。
prime按升序记录1000以内的质数。令nums[i]减少x,则:x <nums[i]
nums[i]-x > nums[i-1] 即 nums[i]-nums[i-1] > x
两者联合 x < min(nums[i],nums[i]-nums[i-1])
即:x < nums[i] - nums[j-1]
代码
核心代码
class CUniqueFactorization
{
public:
CUniqueFactorization(int iMax) {
int iMaxSqrt = sqrt(iMax) + 2;
m_vPrime = CreatePrime(iMaxSqrt);
}
void Factorization(int x) {
m_a.clear();
m_n.clear();
for (const auto& iPre : m_vPrime) {
int cnt = 0;
while (0 == x % iPre) {
cnt++;
x /= iPre;
}
if (cnt > 0) {
m_a.emplace_back(iPre);
m_n.emplace_back(cnt);
}
}
if (x > 1) {
m_a.emplace_back(x);
m_n.emplace_back(1);
}
}
vector<int> m_a, m_n;
vector<int> CreatePrimeOld(int iMax)
{
vector<int> vNo(iMax + 1);
vector<int> vPrime;
for (int i = 2; i <= iMax; i++)
{
if (!vNo[i])
{
vPrime.emplace_back(i);
}
for (const auto& n : vPrime)
{
if (n * i > iMax)
{
break;
}
vNo[n * i] = true;
}
}
return vPrime;
}
static vector<int> CreatePrime(int iMax)
{
vector<bool> isPrime(iMax + 1, true);
vector<int> vPrime;
for (int i = 2; i <= iMax; i++)
{
if (isPrime[i])
{
vPrime.emplace_back(i);
}
for (const auto& n : vPrime)
{
if (n * i > iMax) { break; }
isPrime[n * i] = false;
if (0 == i % n) { break; }
}
}
return vPrime;
}
vector<int> m_vPrime;
};
class Solution {
public:
bool primeSubOperation(vector<int>& nums) {
auto v = CUniqueFactorization::CreatePrime(1000);
int pre = 0;
for (auto& n : nums) {
auto it = lower_bound(v.begin(), v.end(), n - pre);
if (v.begin() != it)
{//能变小
n -= *(--it);
}
else if( n <= pre ){
return false;
}
pre = n;
}
return true;
}
};
单元测试
vector<int> nums;
TEST_METHOD(TestMethod11)
{
vector<int> nums = { 4,9,6,10 };
auto res = Solution().primeSubOperation(nums);
AssertEx(true, res);
}
TEST_METHOD(TestMethod12)
{
vector<int> nums = { 6,8,11,12 };
auto res = Solution().primeSubOperation(nums);
AssertEx(true, res);
}
TEST_METHOD(TestMethod13)
{
vector<int> nums = { 5,8,3 };
auto res = Solution().primeSubOperation(nums);
AssertEx(false, res);
}