题目链接
https://leetcode.cn/problems/number-of-subarrays-with-gcd-equal-to-k/
题目
思路
方案一 暴力枚举
g = gcd(g, nums[j])
class Solution {
public int subarrayGCD(int[] nums, int k) {
int res = 0;
for (int i = 0; i < nums.length; i++){
int g = nums[i];
for (int j = i; j < nums.length; j ++){
g = gcd(g, nums[j]);
if (g == k){
res++;
}
}
}
return res;
}
private int gcd(int a, int b) {
while (b != 0) {
int tmp = a % b;
a = b;
b = tmp;
}
return a;
}
}
稍加改进,如果当前的最大公约数已经小于k,那么没必要继续循环下去
class Solution {
public int subarrayGCD(int[] nums, int k) {
int res = 0;
for (int i = 0; i < nums.length; i++) {
int g = nums[i];
for (int j = i; j < nums.length; j++) {
g = gcd(g, nums[j]);
if (g == k) {
res++;
} else if (g < k) {
break;
}
}
}
return res;
}
private int gcd(int a, int b) {
while (b != 0) {
int tmp = a % b;
a = b;
b = tmp;
}
return a;
}
}
方案二 滑动窗口
满足最大公约数是k的子数组里的所有元素,要么是k,要么是2k,3k,4k…
-
当进入窗口的数字不是k或者nk,数组被截断,窗口清空
-
当进入窗口的数字是k时,以当前数字k为结尾的满足答案的子数组有i-left+1
-
当进入窗口的数字是nk时
-
窗口只有当前数字时,没有满足答案的子数组
-
窗口内有别的元素时,以当前数字nk为结尾的满足答案的子数组通过倒序遍历求得
- 例如:k=1,窗口内有[3,5,7,9],我们倒序判断[7,9],[5,7,9],[3,5,7,9]是否满足即可
- 例如:k=1,窗口内有[3,5,7,9],我们倒序判断[7,9],[5,7,9],[3,5,7,9]是否满足即可
-
class Solution {
public int subarrayGCD(int[] nums, int k) {
int n = nums.length;
int left = 0;
int res = 0;
for (int i = 0; i < n; i++) {
if (nums[i] % k != 0) {
left = i + 1;
} else if (nums[i] == k) {//k
res += (i - left + 1);
} else {//nk
res += getCount(nums, k, left, i);
}
}
return res;
}
private int getCount(int[] nums, int k, int left, int right) {
int res = 0;
int g = nums[right];
for (int i = right - 1; i >= left; i--) {
g = gcd(g, nums[i]);
if (g == k) {
res++;
} else if (g < k) {
break;
}
}
return res;
}
private int gcd(int a, int b) {
while (b != 0) {
int tmp = a % b;
a = b;
b = tmp;
}
return a;
}
}