【问题标题】:can anyone help me finding alternative algorithm solution - without using sort()? [closed]谁能帮我找到替代算法解决方案 - 不使用 sort()? [关闭]
【发布时间】:2019-01-04 14:57:24
【问题描述】:
function areSimilar(a, b){
    return a.sort().join('') === b.sort().join('');
 }

 console.log(areSimilar([1, 2, 3], [1, 2, 3])); //true
 console.log(areSimilar([1, 2, 3], [2, 1, 3])); //true
 console.log(areSimilar([1, 2, 2], [2, 1, 1])); //false

如果一个数组可以通过交换其中一个数组中的最多一对元素从另一个数组中获得,则称这两个数组相似。

给定两个数组a和b,检查它们是否相似。

示例

  • 对于 a = [1, 2, 3] 和 b = [1, 2, 3],输出应为 areSimilar(a, b) = true。

数组是相等的,不需要交换任何元素。

  • 对于 a = [1, 2, 3] 和 b = [2, 1, 3],输出应为 areSimilar(a, b) = true。

我们可以通过交换 b 中的 2 和 1 从 a 中得到 b。

  • 对于 a = [1, 2, 2] 和 b = [2, 1, 1],输出应为 areSimilar(a, b) = false。

【问题讨论】:

  • “如果可以通过交换其中一个数组中的最多一对元素从另一个数组中获得一个数组,则称这两个数组相似。”这不是你的@ 987654323@ 函数检查,除非您的函数只使用三元素数组调用...?例如,它会为[1, 1, 2, 2][2, 2, 1, 1] 返回true,但从前者到后者需要两次交换,而不仅仅是一次。
  • 刚要发布与 T.J 类似的评论,您的排序版本不会做问题所要求的,。它只是根据提供的示例偶然给出正确的真/假。
  • 如果我理解正确,我的想法是按值对两个数组进行排序(使用哪种“算法”、升序、降序、字符串或比较并不重要)。排序后,您可以比较每个对应的位置(键),如果发现超过 1 个差异,结果应返回 false。
  • @dev101 If I understand this right,很遗憾你错过了问题的重要部分 -> swapping at most one pair of elements 排序肯定会打破这条规则。

标签: javascript algorithm performance big-o


【解决方案1】:

如果我理解得很好,如果两个数组包含相同的元素并且差异不超过 2 个,则它们是“相似的”(因为如果您有超过 2 个差异,则不能只交换 2 个元素并得到相同的元素数组)。

所以我会去做这样的事情:

function areSimilar(a, b) {
    if (a.length != b.length) {
        return false;
    }

    var differences = [];

    for (var i = 0; i < a.length; ++i) {
    	if (a[i] !== b[i]) {
    		differences.push(i);

    		if (differences.length > 2) {
    			return false;
    		}
    	}
    }

    if (!differences.length) {
    	return true;
    }

    if (differences.length == 1) {
    	return false;
    }

    return Math.abs(differences[0] - differences[1]) == 1 && a[differences[0]] === b[differences[1]] && a[differences[1]] === b[differences[0]];
}

console.log(areSimilar([1, 2, 3], [1, 2, 3])); //true
console.log(areSimilar([1, 2, 3], [2, 1, 3])); //true 
console.log(areSimilar([1, 2, 2], [2, 1, 1])); //false
console.log(areSimilar([2, 1, 1], [1, 1, 2])); //false

【讨论】:

  • 此算法在这种情况下将返回 TRUE:A = [2, 1, 1]; B = [1, 1, 2];但是 A 中需要 2 次交换操作才能使其等于 B。
  • 等等?你只允许交换邻居元素?在问题中说出来可能很重要
  • 在 OP 问题后查看 cmets:最多交换一对元素
  • @dev101:我不认为“交换两个元素”意味着“交换两个 相邻 元素”,但也许你应该要求 OP 澄清一下。
  • @dev101:交换 其中一个数组中的两个元素。这不是 swap(a[0], b[2]);它是交换(a [0],a [2])。这给了你 [1, 1, 2]
【解决方案2】:

这是一个在 O(n) 时间内工作的版本(它只查看每个位置一次)和 O(1) 时间(没有临时容器;只有标量):

function areSimilar(a, b) {
    /* Helper function:
     * Compares a and b starting at index i, and returns the first
     * index at which they differ. If there is no difference returns
     * max(i, a.length)
     */
    function nextDiff(i) {
        while (i < a.length && a[i] == b[i]) ++i;
        return i;
    }
    /* If lengths are different, obviously not similar */
    if (a.length != b.length) return false;
    diff1 = nextDiff(0);
    /* If there is no difference, they're the same (and thus similar) */
    if (diff1 >= a.length) return true;
    /* Find the second difference */
    diff2 = nextDiff(diff1 + 1);
    /* Similar if there is a second difference
       and a swap would produce equality
       and there is no further difference.
     */
    return diff2 < a.length
           && a[diff1] == b[diff2] && a[diff2] == b[diff1]
           && nextDiff(diff2 + 1) >= a.length;
}

console.log(areSimilar([1, 2, 3], [1, 2, 3])); //true  (identical)
console.log(areSimilar([1, 2, 3], [2, 1, 3])); //true  (single swap) 
console.log(areSimilar([1, 2, 2], [2, 1, 1])); //false (not permutation)
console.log(areSimilar([2, 1, 1], [1, 1, 2])); //true  (single swap, not adjacent)
console.log(areSimilar([1, 2, 3], [2, 3, 1])); //false (permutation, needs two swaps)

【讨论】:

    【解决方案3】:

    您可以清点物品并使用Map 来跟踪计数。

    function areSimilar(a, b) {
        return a.length === b.length
            && b.every(
                (m => v => m.get(v) && m.set(v, m.get(v) - 1))
                (a.reduce((m, v) => m.set(v, (m.get(v) || 0) + 1), new Map()))
            );
    }
    
    console.log(areSimilar([1, 2, 3], [1, 2, 3])); //  true
    console.log(areSimilar([1, 2, 3], [2, 1, 3])); //  true
    console.log(areSimilar([1, 2, 2], [2, 1, 1])); // false

    【讨论】:

    • 这非常漂亮,但是就像 OP 中的错误代码一样,它只检查两个数组是否是彼此的排列。它将返回真给定输入[1, 2, 3], [2, 3, 1],不能与单个交换相同。即便如此,为胖箭头的一个可爱示例 +1。
    【解决方案4】:

    这是我的答案版本:如果需要 2 个或更多交换操作,它将返回 false。

    该算法实际上非常简单且易于理解,尽管在速度方面可能不是最佳的。

    调试控制台日志仅用于教育目的,因此您可以了解它是如何工作的! :)

    function areSimilar(a, b) {
      if (a.length != b.length) {
        return false;
      }
    
      let differences = 0;
    
      for (let i=0; i < a.length; i++) {
        // console.log('a[i] = ' + a[i]);
        // console.log('b[i] = ' + b[i]);
        if (a[i] !== b[i]) {
          differences++;
        }
      }
    
      // console.log('differences: ' + differences);
    
      // trivial case: arrays are identical
      if (differences == 0) {
        return true;
      }
    
      // we know that in this case no swap combination can return a == b
      if (differences == 1) {
        return false;
      }
    
      // clone a array into c array
      let c = a.slice(0);
    
      // set comparison variables
      let comparison = 0;
      let matchFound = 0;
    
      // only this case should be tested, because if difference is > 2 similarity fails according to initial condition
      if (differences == 2) {
        for (let j=0; j < a.length; j++) {
          for (let k=0; k < a.length; k++) {
            // re(set) temp variables
            c = a.slice(0);
            comparison = 0;
          //  console.log('a = ' + a);
          //  console.log('reset c = ' + c);
          //  console.log('reset comparison = ' + comparison);
            if (j !== k) {
              // swap array value pairs
              [ c[j], c[k] ] = [ c[k], c[j] ];
              // console.log('c[j' + j + '][k' + k + ']: ' + c);
              // compare arrays
              for (let n=0; n < c.length; n++) {
                if (b[n] !== c[n]) {
                  // console.log('b[n] = ' + a[n]);
                  // console.log('c[n] = ' + c[n]);
                  comparison++;
                  // console.log('comparison [' + n + '] = ' + comparison);
                }
              }
    
              if (comparison === 0) {
                matchFound = 1;
                break;
              }
            }
          }
        }
      }
    
      // evaluate final result
      if (matchFound === 1) {
        return true;
      }
    
      return false;
    }
    
    // TEST ARRAYS
    
    var a = [1, 2, 2, 3, 4];
    var b = [1, 2, 2, 4, 3];
    
    // TEST FUNCTION
    
    if (areSimilar(a, b)) {
      console.log('a & b are similar!');
    } else {
      console.log('a & b are NOT similar!');
    }
    
    // OTHER 'COMMON' TESTS
    console.log(areSimilar([1, 2, 3], [1, 2, 3])); //true  (identical)
    console.log(areSimilar([1, 2, 3], [2, 1, 3])); //true  (single swap) 
    console.log(areSimilar([1, 2, 2], [2, 1, 1])); //false (not permutation)
    console.log(areSimilar([2, 1, 1], [1, 1, 2])); //true  (single swap, not adjacent)
    console.log(areSimilar([1, 2, 3], [2, 3, 1])); //false (permutation, needs two swaps)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-11
      • 2021-09-23
      • 2014-05-15
      • 1970-01-01
      • 2021-07-15
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多