最大公因数等于 K 的子数组数目

2023-12-17 02:36

本文主要是介绍最大公因数等于 K 的子数组数目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说在前面

🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。

题目描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。

子数组 是数组中一个连续的非空序列。

数组的最大公因数 是能整除数组中所有元素的最大整数。

示例 1:

输入:nums = [9,3,1,2,6,3], k = 3
输出:4
解释:nums 的子数组中,以 3 作为最大公因数的子数组如下:
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]

示例 2:

输入:nums = [4], k = 7
输出:0
解释:不存在以 7 作为最大公因数的子数组。

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i], k <= 10^9

思路分析

首先我们要先理解一下题目的意思,题目会给我们一个整数数组 nums 和一个整数 k,我们需要统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。

一个序列中最大公因数等于k需要满足以下条件:

  • 1、所有元素均为k的倍数;
  • 2、至少一个元素与其他所有元素的最大公因数都是k

知道了这两个条件之后我们便可以开始编写代码了:

  • 1、记录每个位置前后连续元素为k的倍数的个数;

因为一个序列中最大公因数等于k时,序列中所有元素均为k的倍数,所以我们可以先统计每个位置前后连续元素为k的倍数的个数。

const q1 = new Array(nums.length).fill(0);
const q2 = new Array(nums.length).fill(0);
for(let i = 0; i < q1.length; i++){if(i == 0){if(nums[i] % k == 0) q1[i] = 1;if(nums[q2.length - 1] % k == 0) q2[q2.length - 1] = 1;}else{if(nums[i] % k == 0) q1[i] = q1[i-1] + 1;if(nums[q2.length - 1 - i] % k == 0) q2[q2.length - 1 - i] = q2[q2.length - i] + 1;}
}
  • 2、遍历找到两个相邻元素之间的最大公因数为k的位置;

如果一个序列中有两个元素的最大公因数为k,且其他元素均可以被k整除,那么这个序列所有元素的最大公因数也为k,所以我们可以找到任意一组最大公因数为k的元素来进行计算。

for(let i = 0; i < nums.length; i++){if(nums[i] == k) res++;if(i < nums.length - 1 && gcd(nums[i],nums[i + 1]) == k){……}
}
  • 3、计算当前位置可以组成满足条件的序列数。

如果找到一组相邻的元素他们的最大公因数为k,那么从当前位置向两边延伸,找到连续为k的倍数的元素组成的序列都为满足条件的序列。

如:nums = [3,3,4,1,2],k = 1

  • (1)、情况1(左边序列数 * 右边序列数 = 总序列数)

我们可以看到在下标i为1的时候,gcd(nums[i],nums[i + 1]) == k,此时从i往左看,我们可以得到两个连续元素均为k的倍数,[3,3];从i + 1往右看,我们可以得到三个连续元素均为k的倍数,[4,1,2]
我们只需计算两个数组的组合数即可,这里的子序列需要是连续的,所以我们可以得到的组合数应该是2 * 3 = 6;分别为:[3,4],[3,4,1],[3,4,1,2],[3,3,4],[3,3,4,1],[3,3,4,1,2];

  • (2)、情况2((左边序列数 - 上一次计算的左边序列数) * 右边序列数 = 总序列数)

第二个满足条件的下标i为2,此时从i往左看,我们可以得到两个连续元素均为k的倍数,[3,3,4];从i + 1往右看,我们可以得到三个连续元素均为k的倍数,[1,2]
我们只需计算两个数组的组合数即可,这里的子序列需要是连续的,所以我们可以得到的组合数应该是2 * 3 = 6;分别为:[4,1],[4,1,2],[3,4,1],[3,4,1,2],[3,3,4,1],[3,3,4,1,2],这时我们会发现,当前得出的结果与上一次得到的结果中有重复的子序列:[3,4,1],[3,4,1,2],[3,3,4,1],[3,3,4,1,2],因为左边的序列中[3,3]在上一次计算中已经计算过了,所以我们需要将这两个减去,可以得到(3 - 2) * 2 = 2,所以当前位置可以得到新的组合数为2;

  • (3)、子数组长度为1

题目中是这样定义的子数组:子数组 是数组中一个连续的非空序列。,所以在遇到nums[i] == k时,该元素可以单独成组。

let res = 0;
let flag = 0;
for(let i = 0; i < nums.length; i++){if(nums[i] == k) res++;if(i < nums.length - 1 && gcd(nums[i],nums[i + 1]) == k){res += (i > 0 ? (q1[i] - flag) : 1) * (q2[i + 1] || 1);flag = q1[i];}if(nums[i] % k !== 0) flag = 0;
}

完整AC代码如下:

AC代码

/*** @param {number[]} nums* @param {number} k* @return {number}*/var subarrayGCD = function(nums, k) {const gcd = (a, b) => {return a % b === 0 ? b : gcd(b, a % b);}const q1 = new Array(nums.length).fill(0);const q2 = new Array(nums.length).fill(0);for(let i = 0; i < q1.length; i++){if(i == 0){if(nums[i] % k == 0) q1[i] = 1;if(nums[q2.length - 1] % k == 0) q2[q2.length - 1] = 1;}else{if(nums[i] % k == 0) q1[i] = q1[i-1] + 1;if(nums[q2.length - 1 - i] % k == 0) q2[q2.length - 1 - i] = q2[q2.length - i] + 1;}}let res = 0;let flag = 0;for(let i = 0; i < nums.length; i++){if(nums[i] == k) res++;if(i < nums.length - 1 && gcd(nums[i],nums[i + 1]) == k){res += (i > 0 ? (q1[i] - flag) : 1) * (q2[i + 1] || 1);flag = q1[i];}if(nums[i] % k !== 0) flag = 0;}return res;
};

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

这篇关于最大公因数等于 K 的子数组数目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/502791

相关文章

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm