JavaScript 中的嵌套循环和频率图
JavaScript 中的嵌套循环和频率图
问题
这篇文章将介绍用于检查可迭代 JavaScript 对象中某些条件的方法。例如,让我们比较两个整数数组。数组的顺序不同,但我们想知道两者中是否存在相同的数字。
常量数组1 = [1, 2, 2, 3, 4, 5]
const array2 = [2, 3, 5, 1, 4, 2]
//真的
我们可以看到这两个数组是相同的,但是我们如何编写一个函数来为我们检查这个条件呢?我们需要检查array1中的每个值,看看array2中是否有对应的值。除此之外,我们还需要确保相应的值以相同的频率出现。换句话说,如果我们查看 array1,我们会找到两个 2,因此我们还需要在 array2 中找到两个 2。
常量数组1 = [1, 2, 2, 3, 4, 5]
const array2 = [1, 3, 5, 1, 4, 2]
//错误的
现在 array1 仍然包含两个 2,但 array2 只包含一个 2 和两个 1,所以我们将编写的函数应该返回 false。
解决方案 1:嵌套循环
编写函数来检查两个整数数组是否相同的一种方法是使用嵌套循环或循环内的循环。外部循环可以负责array1,内部循环将管理对array2的迭代。让我们看看一个 ** for 循环** .
for (让 i = 0; i < array1.length; i++) {
//代码块做一些事情
}
For 循环总是以关键字“for”开头,后跟 3 个用分号分隔的参数。第一个参数初始化一个计数器变量,通常初始化为 0,因为数组是 0 索引的。第二个参数指定循环将运行多少次,第三个参数在循环内每个代码块完成时递增或递减计数器。在示例中,我们希望从 array1 中的第一个值开始,即索引 0。在循环中,“let i = 0”从 array1[0] 开始。代码块运行,然后 我++ 递增计数器, 一世 , 由 1. 现在, 我 = 1, 用于访问数组中的第二个值, 数组1[1] 依此类推,直到 一世 等于数组的长度。
现在我们可以遍历 array1 中的每个元素,我们要检查该值是否存在于 array2 中。一种方法是逐个遍历 array2 并询问“array1 中的这个值是否等于 array2 中的第一个值?”、“否”、“好的,那么 array2 中的下一个值呢?”等等,直到我们找到一个匹配。如果我们没有找到匹配项,那么我们知道 array1 与 array2 不同。有了这个计划,让我们编写嵌套循环。
for (让 i = 0; i < array1.length; i++) {
for (让 j = 0; j < array2.length; j++) {
//代码块
}
}
现在,当 我=0 , j 将从 0 递增到 array2 中最后一个元素的索引。这是嵌套循环的更好可视化:
我:0 | 1 | 2 | 3 | ... j: 0 1 2 3 4 5 | 0 1 2 3 4 5 | 0 1 2 3 4 5 | 0 1 2 3 4 5 | ...
在外循环的第一次迭代中,i = 0,内循环运行直到完成。至此,外循环的第一次迭代完成, 一世 递增到 1。内部循环再次运行,这反过来又满足传递给外部循环的参数,并且 一世 递增到 2,依此类推……
了解嵌套循环的工作原理后,我们就可以编写函数了。
函数检查数组(arr1,arr2){
如果(arr1.length !== arr2.length){
返回假;
} for (让 i = 0; i < arr1.length; i++){
for (让 j = 0; j < arr2.length; j++){
如果 (arr1[i] === arr2[j]) {
arr2.splice(j, 1);
休息;
}
}
} if (arr2.length !== 0){
返回假
}
返回真;
}
第一个条件检查两个数组的长度是否相同。如果不是,我们知道它们不可能相同并返回 false。接下来,对于 array1 中的每个值,我们遍历 array2 中的每个值,直到找到匹配项。为了跟踪两个数组中重复值的频率,我们将使用 .splice() 方法从 array2 中删除匹配元素。找到匹配项后,我们停止遍历 array2(中断)并移动到 array1 中的下一个元素。循环完成后,如果我们在两个数组中找到具有相同频率的相同元素,则 array2 应该为空。如果 array2 仍然包含任何元素,我们知道这两个数组不是完美匹配并返回 false。
使用嵌套循环来解决这个问题对于小型数组非常有效,但是如果数组增长到数千个元素,您可以想象这个过程需要多长时间。大多数嵌套循环的时间复杂度为 O(N²)。
解决方案 2:频率图
频率图还有许多其他名称,例如哈希图、频率计数器等。它们都指的是相同的模式。对于数组中的每个元素或字符串中的每个字符(对于简单示例),记录每个项目在该列表或字符串中出现的次数。将此计数存储在一个对象中。该代码遵循类似的方法,但用频率图替换了嵌套循环,以将我们的时间复杂度大大提高到 O(N)。
函数检查数组(arr1,arr2){
如果(arr1.length !== arr2.length){
返回假;
} 让频率映射 = {}; 对于(arr1 的值){
如果(freqMap中的val){
频率映射[val] += 1;
} 别的 {
频率映射[val] = 1;
}
} 对于(arr2 的值){
if (val in freqMap && freqMap[val] > 0) {
频率映射[val] -= 1;
} 别的 {
返回假
}
}
返回真;
}
在上面的解决方案中,我们创建了一个对象,将在 array1 中找到的每个整数存储为初始值为 1 的键。如果再次找到相同的元素,则该属性的值增加 1。为简单起见,我们使用 for 循环 代替 for 循环 以前使用过,但我们仍然循环遍历 array1 中的每个项目。在循环中,我们检查该值是否已经作为 freqMap 中的键存在。如果是,则将其值加 1。如果不是,将属性初始化为 1。将 array1 中的每个元素添加到我们的频率图后,freqMap 应如下所示:
常量数组1 = [1, 2, 2, 3, 4, 5] freqMap = {'1': 1, '2': 2, '3': 1, '4': 1, '5': 1}
然后我们循环遍历array2中的每个值,检查该值是否作为freqMap中的键存在并且其值大于0。如果是,则将该属性的值减1。如果array1和array2相同,我们应该结束加上以下内容:
freqMap = {'1': 0, '2': 0, '3': 0, '4': 0, '5': 0}
在两个数组不匹配的情况下,频率图中的关联键将剩余一个大于 0 的值。如果我们比较之前的错误示例:
常量数组1 = [1, 2, 2, 3, 4, 5]
const array2 = [1, 3, 5, 1, 4, 2]
//错误的 freqMap = {'1': 0, '2': 1, '3': 0, '4': 0, '5': 0}
我们的函数将返回 错误的 但是,由于我们函数的第二个循环的条件,array2 中有两个 1,array1 中只有一个:
if (val in freqMap && freqMap[val] > 0)
结论
我们通过删除嵌套循环并将其替换为两个单独的循环加上一个频率图,对我们的代码进行了巨大的改进。频率图通过记录给定元素在可迭代对象中出现的次数使这种改进成为可能。现在我们不必多次循环array2(array1.length 次)。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明