【力扣roadmap】2584. 分割数组使乘积互质

15 阅读3分钟

题目描述

image.png

思路

WA了5发才过。写完代码后评估题目,感觉算数评级有点虚高。

题目要求在数组中找一个位置,从这个位置切断,形成两半(这个位置的元素含在前一半),让前一半和后一半的gcd等于1(互质)。

其实拿到这个题我先写了一遍前缀积,我看每个元素10^6,一共10^4个元素,下意识把两个乘在一起,发现才10^10,对于判断是否互质并不困难。写完过了样例之后,感觉这个红题不会这么简单吧,我又想了想,才回过味来.... 一万个一百万级别的元素,是这些元素进行相乘,那么最大的积有(10^6)^(10^4)这么大,也就是10^(6w).这还算个鸡毛。

然后我考虑到判断两个数字是否互质,本质是看他们的质因数分解的结果是否存在交集。如果两个数分别进行质因数分别,发现相互没有交集,说明两个数字肯定互质。

然后题目就是需要找一个最左侧的idx,让[0,idx]的质因数集合和[idx+1,n-1]的质因数集合没有交集。

其实这好办。我们记录每个质因数出现的最左侧下标和最右侧下标,这样每个出现的质因数就形成了一个个区间。对于质因数x来说,其出现的最左侧下标为l,最右侧下标为r,这说明nums[l]nums[r]分解出了质因数x,并且比l更左或比r更右的元素都没有x这个质因数。

所以对于找一个最左侧的idx,让[0,idx]的质因数集合和[idx+1,n-1]的质因数集合没有交集这个问题,就是计算区间合并的时候,在idx这个位置断开了。于是乎,这个问题转化成了区间合并问题。

最后补充一下边界问题: 如果数组nums中有1这个元素,注意1是不改变乘积结果的,1也不算是质因数(最小质因数是2,你对1进行质因数分解有点犯不上),1和谁都互质,换句话说(对咱们的区间问题来讲),1的位置可以和任何质因数的区间合并一起,很灵活,我们在特判的时候,如果遇上了1,就让1自成一个区间(形成最小区间)。每遇到一个1就让它自成一个区间。

代码

class Solution:
    def findValidSplit(self, nums: List[int]) -> int:
        seg_mapper = dict() # 记录每个质因数出现的最早位置和最晚位置
        seg = []
        for i,x in enumerate(nums) :
            if x == 1 :
                seg.append([i,i])
                continue 
            for j in range(2,int(x**0.5) + 1) :
                if x % j == 0 :
                    if j not in seg_mapper :
                        seg_mapper[j] = [i,i]
                    else :
                        seg_mapper[j][-1] = i 
                    while x % j == 0 :
                        x //= j
            if x > 1:
                if x not in seg_mapper :
                    seg_mapper[x] = [i,i]
                else :
                    seg_mapper[x][-1] = i 
        seg_tmp = list(seg_mapper.values())
        seg.extend(seg_tmp)
        if not seg : 
            return -1 
        seg.sort() 
        l , r = seg[0][0] , seg[0][1] 
        for i in range(1,len(seg)):
            cur_l , cur_r = seg[i][0], seg[i][1] 
            if cur_l > r :
                return r
            else :
                r = max(r , cur_r) 
        return -1