题目链接
Leetcode.2584 分割数组使乘积互质
rating :2159
题目描述
给你一个长度为 n n n 的整数数组 n u m s nums nums,下标从 0 0 0 开始。
如果在下标 i i i 处 分割 数组,其中 0 ≤ i ≤ n − 2 0 \leq i \leq n - 2 0≤i≤n−2 ,使前 i + 1 i + 1 i+1 个元素的乘积和剩余元素的乘积互质,则认为该分割 有效 。
- 例如,如果 n u m s = [ 2 , 3 , 3 ] nums = [2, 3, 3] nums=[2,3,3] ,那么在下标 i = 0 i = 0 i=0 处的分割有效,因为 2 2 2 和 9 9 9 互质,而在下标 i = 1 i = 1 i=1 处的分割无效,因为 6 6 6 和 3 3 3 不互质。在下标 i = 2 i = 2 i=2 处的分割也无效,因为 i = n − 1 i = n - 1 i=n−1 。
返回可以有效分割数组的最小下标 i i i ,如果不存在有效分割,则返回 − 1 -1 −1 。
当且仅当 g c d ( v a l 1 , v a l 2 ) = 1 gcd(val_1, val_2) = 1 gcd(val1,val2)=1 成立时, v a l 1 val_1 val1 和 v a l 2 val_2 val2 这两个值才是互质的,其中 g c d ( v a l 1 , v a l 2 ) gcd(val_1, val_2) gcd(val1,val2) 表示 v a l 1 val1 val1 和 v a l 2 val2 val2 的最大公约数。
示例 1:
输入:nums = [4,7,8,15,3,5]
输出:2
解释:上表展示了每个下标 i 处的前 i + 1 个元素的乘积、剩余元素的乘积和它们的最大公约数的值。
唯一一个有效分割位于下标 2 。
示例 2:
输入:nums = [4,7,15,8,3,5]
输出:-1
解释:上表展示了每个下标 i 处的前 i + 1 个元素的乘积、剩余元素的乘积和它们的最大公约数的值。
不存在有效分割。
提示:
- n = n u m s . l e n g t h n = nums.length n=nums.length
- 1 ≤ n ≤ 1 0 4 1 \leq n \leq 10^4 1≤n≤104
- 1 ≤ n u m s [ i ] ≤ 1 0 6 1 \leq nums[i] \leq 10^6 1≤nums[i]≤106
解法:质因数分解 + 哈希表
我们要使 v a l 1 和 v a l 2 val_1 和 val_2 val1和val2 互质,就是意味着 v a l 1 和 v a l 2 val_1 和 val_2 val1和val2 分解质因数之后,它们各自的质因数之间没有交集,即没有相同的质因子。
我们先预处理出 1 0 6 10^6 106 范围内的质数,将其存入 p r i m e s primes primes 中,用 m i n _ f a c t o r [ x ] min\_factor[x] min_factor[x] 记录 x x x 的最小质因子;
然后我们用哈希表 s u m sum sum 记录整个数组的质因数的个数,比如质因数 p p p ,它的数量就是 s u m [ p ] sum[p] sum[p]。
接着我们从 0 ≤ i < n − 1 0 \leq i < n - 1 0≤i<n−1开始枚举每一个数组元素 n u m s [ i ] nums[i] nums[i],用哈希表 c n t cnt cnt 记录其质因数。
每当我们将一个元素 n u m s [ i ] nums[i] nums[i] 的质因数记录到 c n t cnt cnt 中,就开始判断( p p p 是 n u m s [ i ] nums[i] nums[i] 的质因子):
- 如果 c n t [ p ] = 0 cnt[p] = 0 cnt[p]=0,说明整个数组的质因子 p p p 都应该在 [ i + 1 , n − 1 ] [i+1,n-1] [i+1,n−1]的范围内,当前 [ 0 , i ] [0,i] [0,i]不存在质因子 p p p,故 i i i 是一个有效分割;
- 如果 c n t [ p ] = s u m [ p ] cnt[p] = sum[p] cnt[p]=sum[p],说明整个数组的质因子 p p p 都应该在 [ 0 , i ] [0,i] [0,i]的范围内, [ i + 1 , n − 1 ] [i+1,n-1] [i+1,n−1]不存在质因子 p p p,故 i i i 是一个有效分割;
- 如果 c n t [ p ] > 0 a n d c n t [ p ] ≠ s u m [ p ] cnt[p] > 0 \ and\ cnt[p] \neq sum[p] cnt[p]>0 and cnt[p]=sum[p],说明整个数组的质因子 p p p 在 i i i 的两侧,即 [ 0 , i ] [0,i] [0,i] 和 [ i + 1 , n − 1 ] [i+1,n-1] [i+1,n−1] 都存在,即当前 i i i 不是一个有效分割;
时间复杂度: O ( U + n l o g U ) O(U + nlogU) O(U+nlogU)
C++代码:
const int N = 1e6 + 10;
vector<int> primes;
int min_factor[N];
auto _ = []()
{
vector<bool> st(N, true);
for(int i = 2;i < N;i++)
{
if(st[i])
{
primes.push_back(i);
min_factor[i] = i;
}
for(auto x:primes)
{
if(x * i >= N) break;
st[i * x] = false;
min_factor[i * x] = x;
if(i % x == 0) break;
}
}
return 0;
}();
class Solution {
public:
int findValidSplit(vector<int>& nums) {
int n = nums.size();
unordered_map<int,int> sum, cnt;
for(auto x:nums)
{
for(int i = x;i > 1;i /= min_factor[i])
{
sum[min_factor[i]]++;
}
}
int mismatch = 0;
auto fun = [&](int x)
{
int& k = cnt[x];
if(k == 0)
{
if(++k != sum[x])
{
mismatch++;
}
}
else
{
if(++k == sum[x])
{
mismatch--;
}
}
return 0;
};
for(int i = 0;i < n - 1;i++)
{
auto x = nums[i];
for(int j = x;j > 1;j /= min_factor[j])
{
fun(min_factor[j]);
}
if(mismatch == 0) return i;
}
return -1;
}
};