【问题标题】:Two nested for/loops without duplicated pairs两个没有重复对的嵌套 for/loop
【发布时间】:2016-09-20 13:52:57
【问题描述】:

我们有数组:

var arr = [0,1,2];

和循环:

for ( var i=0; i<arr.length; i++ ) {
    for ( var j=0; j<arr.length; j++ ) {
        if ( arr[i] == arr[j] ) continue;
        console.log(arr[i], arr[j]);
    }
}

和输出:

0,1 //a--|
0,2 //b--|--|
1,0 //a--|  |
1,2 //c-----|--|
2,0 //b-----|  |
2,1 //c--------|

我们可以看到有重复的对(在 cmets 中 a、b 和 c 出现了两次)

我们摆脱重复对的唯一方法是将已经“匹配”的对存储在某种内存中?

var mem = {};

for ( var i=0; i<arr.length; i++ ) {
    for ( var j=0; j<arr.length; j++ ) {
        var left = i;
        var right = j;
        if ( left > right ) {
            var temp = right;
            right = left;
            left = temp;
        }

        if ( arr[i] == arr[j] || mem[arr[left]+","+arr[right]] ) continue;

        console.log(arr[i], arr[j]);
        mem[arr[left]+","+arr[right]] = true;
    }
}

和输出:

0,1
0,2
1,2

但这需要额外的内存(对于更大的数组,它需要很多......)

有没有其他方法不存储任何额外的东西?

【问题讨论】:

  • 简短的回答是......不
  • 这些循环是否会达到数百万,因为如果不是,我看不到过早优化的理由。当这确实会导致可衡量的问题时,可能会有一个更有效的过滤器,我不是这方面的专家。即便如此,我怀疑它使用相同的内存,只是在代码中不太明显。

标签: javascript algorithm loops permutation


【解决方案1】:

如果您的输入数组是唯一的,为什么不直接从 i+1 开始您的 j

for ( var i=0; i<arr.length; i++ ) {
    for ( var j= i + 1 ; j<arr.length; j++ ) {
        console.log(arr[i], arr[j]);
    }
}

【讨论】:

  • 哇,这实际上比我这样做的方式更有效,尽管它使用了相同的原理。不错!
  • @Feathercrown:也更适合链表。
  • 另外,虽然它和你的一样大 O,但由于 for 循环更短,它在实践中会运行得更快。
【解决方案2】:

一种可能的算法如下:

  1. 对数组进行排序。

  2. 从数组中删除重复值(留下 1),对于每个具有重复值的值 x,输出 (x,x)

  3. 对于每对索引ij使得i &lt; j,输出对应的一对(i,j)

虽然这可能不会产生已排序的输出,但它确实可以处理重复值和未排序的输入数组。

【讨论】:

    【解决方案3】:
    for ( var i=0; i<arr.length; i++ ) {
        for ( var j=0; j<arr.length; j++ ) {
            if ( arr[i] == arr[j] || j<i) continue;
            console.log(arr[i], arr[j]);
        }
    }
    

    这应该可行。

    说明: 如果 j 小于 i,那么您可以切换 i 和 j 以获得具有相同两个值的另一个输出。但是如果你让 j 在数组中“领先”于 i,则不会输出重复。

    它“看起来”如何:

    o=数组值

    x=arr[i]

    |=arr[j]

    -=arr[i] 和 arr[j] 都在这个位置

    -oooo //继续

    x|ooo

    xo|oo

    xoo|o 呵呵|

    那么,没有变化:

    |xooo //输出!与第 2 行(/step)相同!

    o-ooo //继续

    牛|oo

    随着变化: |xooo //j 在 i 之前,所以不输出。避免重复行(/step) 2.

    o-ooo //继续

    牛|oo

    等等

    【讨论】:

    • 类似于 Amin J 的回答,但有额外的不必要的计算。
    • @TomerW 是的,我看到了。不过,我还是要离开它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 2013-12-01
    • 2018-06-13
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    相关资源
    最近更新 更多