题目描述
思路
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