元素 x 若能整除 numsDivide 的所有元素,等价于 x 是所有 numsDivide}[i] 的因子,这也等价于 x 是 numsDivide 所有元素的最大公因数 g 的因子。
提示 2
由于要求用 nums 的最小元素去整除 g,不妨将 nums 排序后,从小到大找到第一个能整除 g 的元素 x,所有小于 x 的元素都需要删除。
[sol1-Python3]
1 2 3 4 5
classSolution: defminOperations(self, nums: List[int], numsDivide: List[int]) -> int: g = gcd(*numsDivide) nums.sort() returnnext((i for i, x inenumerate(nums) if g % x == 0), -1)
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution { publicintminOperations(int[] nums, int[] numsDivide) { varg=0; for (var x : numsDivide) g = gcd(g, x); Arrays.sort(nums); for (vari=0; i < nums.length; i++) if (g % nums[i] == 0) return i; return -1; }
intgcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); } }
[sol1-C++]
1 2 3 4 5 6 7 8 9 10
classSolution { public: intminOperations(vector<int> &nums, vector<int> &numsDivide){ int g = 0; for (int x : numsDivide) g = gcd(g, x); sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size(); i++) if (g % nums[i] == 0) return i; return-1; } };
funcminOperations(nums, numsDivide []int)int { g := 0 for _, x := range numsDivide { g = gcd(g, x) } sort.Ints(nums) for i, x := range nums { if g%x == 0 { return i } } return-1 }
funcgcd(a, b int)int { for a != 0 { a, b = b%a, a } return b }
也可以不用排序,通过两次遍历得到答案。
[sol2-Python3]
1 2 3 4 5
classSolution: defminOperations(self, nums: List[int], numsDivide: List[int]) -> int: g = gcd(*numsDivide) mn = min((x for x in nums if g % x == 0), default=0) returnsum(x < mn for x in nums) if mn else -1
[sol2-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution { publicintminOperations(int[] nums, int[] numsDivide) { varg=0; for (var x : numsDivide) g = gcd(g, x); varmin= Integer.MAX_VALUE; for (var num : nums) if (g % num == 0) min = Math.min(min, num); if (min == Integer.MAX_VALUE) return -1; varans=0; for (var x : nums) if (x < min) ++ans; return ans; }
intgcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); } }
[sol2-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution { public: intminOperations(vector<int> &nums, vector<int> &numsDivide){ int g = 0; for (int x : numsDivide) g = gcd(g, x); int mn = INT_MAX; for (int x : nums) if (g % x == 0) mn = min(mn, x); if (mn == INT_MAX) return-1; int ans = 0; for (int x : nums) if (x < mn) ++ans; return ans; } };
funcminOperations(nums, numsDivide []int) (ans int) { g := 0 for _, x := range numsDivide { g = gcd(g, x) } min := math.MaxInt32 for _, x := range nums { if g%x == 0 && x < min { min = x } } if min == math.MaxInt32 { return-1 } for _, x := range nums { if x < min { ans++ } } return }
funcgcd(a, b int)int { for a != 0 { a, b = b%a, a } return b }
复杂度分析
时间复杂度:O(m+\log U + n),其中 m 为数组 numsDivide 的长度,U=\max(\textit{numsDivide}),n 为数组 nums 的长度。注意到求最大公因数 g 的过程(设初始 g=U),要么使 g 不变,要么使 g 至少减半,而 g 至多减半 O(\log U) 次,因此求最大公因数的迭代次数为 O(m+\log U) 次。总的时间复杂度为 O(m+\log U + n)。