= Vain学习(C/C++ acm算法 python Linux Golang)的个人网站 =

Leetcode 切分数组

Posted on

dp + 筛最小素因子 + 枚举最小素因子

切分数组:

给定一个整数数组 nums ,小李想将 nums 切割成若干个非空子数组,使得每个子数组最左边的数和最右边的数的最大公约数大于 1 。为了减少他的工作量,请求出最少可以切成多少个子数组。
示例 1:
输入:nums = [2,3,3,2,3,3]
输出:2
解释:最优切割为 [2,3,3,2] 和 [3,3] 。第一个子数组头尾数字的最大公约数为 2 ,第二个子数组头尾数字的最大公约数为 3 。
示例 2:
输入:nums = [2,3,5,7]
输出:4
解释:只有一种可行的切割:[2], [3], [5], [7]


限制:

  • 1 <= nums.length <= 10^5
  • 2 <= nums[i] <= 10^6

思路:

  • 首先我们先筛出最大数据以内(包括最大数据)所有数对应的最小素因子
  • 推导dp方程

    1:当前i位置所对应的数的组数 = min(当前i位置对应的最小素因子的位置,dp[i]+1)
    2:当前i位置对应的最小素因子的位置= min(min[a[i]],dp[i-1])

  • 枚举每个数的最小的最小素因子所对应的位置

    因为当前数可能有好多素因子,所以我们把他除以他的最小素因子,呢么得到的数就会对应本身的最小素因子

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <set>
using namespace std;
const int inf = (1 << 30);
typedef long long ll;
const int maxn = 1e6 + 5;
int pr[1000005], mpr[1000005], dp[1000005], a[1000005],mpos[1000005];
void solv(int m) //筛x的最小素因子
{
int cnt = 0;
for (int i = 2; i <= m; i++)
{
if (!mpr[i])
pr[++cnt] = i, mpr[i] = i;
for (int j = 1; j <= cnt; j++)
{
if (pr[j] * i > m||pr[j]>mpr[i])
break;
mpr[pr[j] * i] = pr[j];
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n;
m=~0x3f;
for (int i = 1; i <= n; i++)
cin >> a[i],m=max(m,a[i]);
solv(m);
memset(dp,0x3f3f3f,sizeof dp);
memset(mpos,0x3f3f3f3f,sizeof mpos);
dp[0]=0;
for(int i=1;i<=n;i++)
{
int temp=a[i];
while(temp>1)
{
int ans=mpr[temp];
//cout<<ans<<endl;
mpos[ans]=min(mpos[ans],dp[i-1]);//得到当前最小素因子的最近位置
dp[i]=min(dp[i],mpos[ans]+1);//得到当前距离i的最小素因子的距离
temp/=ans;
}
}
cout<<dp[n]<<endl;
}

leecode 版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
int pr[1000005], mpr[1000005], dp[1000005], a[1000005],mpos[1000005];
void solv(int m) //筛m以内所有数的最小素因子
{
int cnt = 0;
for (int i = 2; i <= m; i++)
{
if (!mpr[i])
pr[++cnt] = i, mpr[i] = i;
for (int j = 1; j <= cnt; j++)
{
if (pr[j] * i > m||pr[j]>mpr[i])
break;
mpr[pr[j] * i] = pr[j];
}
}
}
public:
int splitArray(vector<int>& nums) {
int n,m;
n=nums.size();
m=~0x3f;
for (int i = 0; i<n; i++)
a[i+1]=nums[i],m=max(m,a[i+1]);
solv(m);
memset(dp,0x3f3f3f,sizeof dp);
memset(mpos,0x3f3f3f3f,sizeof mpos);
dp[0]=0;
for(int i=1;i<=n;i++)
{
int temp=a[i];
while(temp>1)
{
int ans=mpr[temp];
//cout<<ans<<endl;
mpos[ans]=min(mpos[ans],dp[i-1]);//得到当前最小素因子的最近位置
dp[i]=min(dp[i],mpos[ans]+1);//得到当前距离i的最小素因子的距离
temp/=ans;
}
}
return dp[n];
}
};