leetcode LCP 14. 切分数组-动态规划-Java

tech2024-05-25  77

问题描述:切分数组

给定一个整数数组 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


动态规划 假设 nums[0] - nums[i-1](最少可以切成多少个子数组)已知。会有2种情况

已知的组 + nums[i]这一组,就是 f[i] = f[i-1]+1 nums[i] 和 nums[0] - nums[i-1]间的某一个是的公约数大于1。 设 这某一个数的下标是j 所以 f[i] = f[j-1] + 1 预置一份 1 - 10^6内数字n的因子数组 minPrime[n]

对数组元素进行因子分解,并记录得到这个因子的位置(posMap)

设 n下标的元素是6 因子分解后记录的位置,posMap[2]=n, posMap[3]=n。 当其他元素分解出为2的因子时,获取$posMap[2]记录中的位置n。 所以此处可切,得到dp[n-1]时的结果 + 1。

例: [10,6,3,5,7] posMap - 记录得到这个因子的位置 dp     - 记录执行到位置的次数   10   posMap[2] = 0;   posMap[5] = 0;   dp[0] = 1;   ------------------------------------------   10, 6   posMap[3] = 1;   dp[1] = 1;     // 已出现相同质因数2位置在0,0-1可以分,零开始直接 dp[1] = 1   ------------------------------------------   10, 6, 3   dp[2] = 2;     // 已出现相同质因数3位置在1。1-2可以分,取dp[1]记录值+1   ------------------------------------------   10, 6, 3, 5   dp[3] = 1;     // 已出现相同质因数5位置在0。0-2可以分,零开始直接 dp[3] = 1   ------------------------------------------   10, 6, 3, 5, 7   posMap[7] = 4;   dp[4] = 2;     // posMap未出现过7,取上次dp记录值+1 补课:

因子:假如整数n除以m,结果是无余数的整数,那么m就是n的因子。一个整数n的因子数为包含它自身的所有因子个数。例,12的因子数为6(1,2,3,4,6,12) 质数:质数又被称为素数,是指一个大于1的自然数,除了1和它自身外,不能被其它自然数整除的数叫做质数,其个数是无穷的,具有许多独特的性质,现如今多被用于密码学上。 约数:又称因数。整数a除以整数b(b≠0) 商是整数而没有余数,a能被b整除 或 b能整除a。a称为b的倍数,b称为a的约数。 互质:互质是公约数只有1的两个整数,叫做互质整数。公约数只有1的两个自然数,叫做互质自然数,后者是前者的特殊情形。 公约数:亦称“公因数”。它是一个能被若干个整数同时均整除的整数。如果一个整数同时是几个整数的约数,称这个整数为它们的“公约数”;公约数中最大的称为最大公约数。1总是它们的公因数。 质因数:在数论里是指能整除给定正整数的 质数。根据算术基本定理,不考虑排列顺序的情况下,每个正整数都能够以唯一的方式表示成它的质因数的乘积。

例:   99的因数  - 1,3,9,11,33,99   99的质因数- 3,11   33的因数  - 1,3,11,33   33的质因数- 3,11   99和33的公约数 - 3,11

作者:FlagMain 链接:https://leetcode-cn.com/problems/qie-fen-shu-zu/solution/qie-fen-shu-zu-dong-tai-gui-hua-java-by-flagmain/


class Solution { public int splitArray(int[] nums) { // 预置 minPrime int[] minPrime = new int[1000000 + 1]; for (int i = 2; i < minPrime.length; i++) { if (minPrime[i] < 2) { for (int j = i; j < minPrime.length; j += i) { minPrime[j] = i; } } } // 记录执行到位置的次数 int[] dp = new int[nums.length]; // 记录因子位置 Map<Integer,Integer> posMap=new HashMap<Integer,Integer>(); for (int i = 0; i < nums.length; i++) { // 预设次数 dp[i] = i > 0 ? dp[i - 1] + 1 : 1; // 分解 $nums[$i] 的因子; int n = nums[i]; while (n > 1) { int factor = minPrime[n]; int minIndex = i; if (posMap.containsKey(factor)) { minIndex = posMap.get(factor); }else { posMap.put(factor, minIndex); } if (minIndex == 0) { dp[i] = 1; } else { // 和 已记录处理的位置+1 对比去一个低的 if ( ( dp[minIndex - 1] + 1 ) < dp[i] ){ dp[i] = dp[minIndex - 1] + 1; } } // 更新posMap if (dp[i] < dp[minIndex]) { posMap.put(factor, i); } n = n / factor; } } return dp[nums.length - 1]; } }

最新回复(0)