3326. 使数组非递减的最少除法操作次数
题目描述
给你一个整数数组 nums
。
一个正整数 x
的任何一个 严格小于 x
的 正 因子都被称为 x
的 真因数 。比方说 2 是 4 的 真因数,但 6 不是 6 的 真因数。
你可以对 nums
的任何数字做任意次 操作 ,一次 操作 中,你可以选择 nums
中的任意一个元素,将它除以它的 最大真因数 。
你的目标是将数组变为 非递减 的,请你返回达成这一目标需要的 最少操作 次数。
如果 无法 将数组变成非递减的,请你返回 -1
。
示例 1:
输入:nums = [25,7]
输出:1
解释:
通过一次操作,25 除以 5 ,nums
变为 [5, 7]
。
示例 2:
输入:nums = [7,7,6]
输出:-1
示例 3:
输入:nums = [1,1,1,1]
输出:0
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 106
解法
方法一:预处理 + 贪心
根据题目描述,
如果整数 $x$ 是质数,那么它的最大真因数是 $1$,那么 $x / 1 = x$,即 $x$ 不能再被除了;
如果整数 $x$ 不是质数,我们假设 $x$ 的最大真因数为 $y$,那么 $x / y$ 一定是质数,因此,我们寻找最小质数 $\textit{lpf}[x]$,使得 $x \bmod \textit{lpf}[x] = 0$,使得 $x$ 变成 $\textit{lpf}[x]$,此时无法再被除了。
因此,我们可以预处理出 $1$ 到 $10^6$ 的每个整数的最小质因数,然后从右往左遍历数组,如果当前元素大于下一个元素,我们将当前元素变为它的最小质因数,如果当前元素变为它的最小质因数后,仍然大于下一个元素,说明无法将数组变成非递减的,返回 $-1$。否则,操作次数加一。继续遍历,直到遍历完整个数组。
预处理的时间复杂度为 $O(M \times \log \log M)$,其中 $M = 10^6$,遍历数组的时间复杂度为 $O(n)$,其中 $n$ 为数组的长度。空间复杂度为 $O(M)$。
Python3
mx = 10**6 + 1
lpf = [0] * (mx + 1)
for i in range(2, mx + 1):
if lpf[i] == 0:
for j in range(i, mx + 1, i):
if lpf[j] == 0:
lpf[j] = i
class Solution:
def minOperations(self, nums: List[int]) -> int:
ans = 0
for i in range(len(nums) - 2, -1, -1):
if nums[i] > nums[i + 1]:
nums[i] = lpf[nums[i]]
if nums[i] > nums[i + 1]:
return -1
ans += 1
return ans
Java
class Solution {
private static final int MX = (int) 1e6 + 1;
private static final int[] LPF = new int[MX + 1];
static {
for (int i = 2; i <= MX; ++i) {
for (int j = i; j <= MX; j += i) {
if (LPF[j] == 0) {
LPF[j] = i;
}
}
}
}
public int minOperations(int[] nums) {
int ans = 0;
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1]) {
nums[i] = LPF[nums[i]];
if (nums[i] > nums[i + 1]) {
return -1;
}
ans++;
}
}
return ans;
}
}
C++
const int MX = 1e6;
int LPF[MX + 1];
auto init = [] {
for (int i = 2; i <= MX; i++) {
if (LPF[i] == 0) {
for (int j = i; j <= MX; j += i) {
if (LPF[j] == 0) {
LPF[j] = i;
}
}
}
}
return 0;
}();
class Solution {
public:
int minOperations(vector<int>& nums) {
int ans = 0;
for (int i = nums.size() - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1]) {
nums[i] = LPF[nums[i]];
if (nums[i] > nums[i + 1]) {
return -1;
}
ans++;
}
}
return ans;
}
};
Go
const mx int = 1e6
var lpf = [mx + 1]int{}
func init() {
for i := 2; i <= mx; i++ {
if lpf[i] == 0 {
for j := i; j <= mx; j += i {
if lpf[j] == 0 {
lpf[j] = i
}
}
}
}
}
func minOperations(nums []int) (ans int) {
for i := len(nums) - 2; i >= 0; i-- {
if nums[i] > nums[i+1] {
nums[i] = lpf[nums[i]]
if nums[i] > nums[i+1] {
return -1
}
ans++
}
}
return
}
TypeScript
const mx = 10 ** 6;
const lpf = Array(mx + 1).fill(0);
for (let i = 2; i <= mx; ++i) {
for (let j = i; j <= mx; j += i) {
if (lpf[j] === 0) {
lpf[j] = i;
}
}
}
function minOperations(nums: number[]): number {
let ans = 0;
for (let i = nums.length - 2; ~i; --i) {
if (nums[i] > nums[i + 1]) {
nums[i] = lpf[nums[i]];
if (nums[i] > nums[i + 1]) {
return -1;
}
++ans;
}
}
return ans;
}