谁能帮助我找到替代算法的解决方案-无需使用sort()?

时间:2019-01-04 14:57:25

标签: javascript algorithm performance big-o

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)=假。

4 个答案:

答案 0 :(得分:3)

如果我理解得很好,则2个数组如果包含相同的元素,并且它们之间的差异不超过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

答案 1 :(得分: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)

答案 2 :(得分:1)

您可以对项目进行计数,并使用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

答案 3 :(得分:0)

这是我的答案:如果需要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)