【问题标题】:How to detect if values in one array are in the same order as another?如何检测一个数组中的值是否与另一个数组的顺序相同?
【发布时间】:2019-03-12 21:40:27
【问题描述】:

我想在这些情况下检测数组1中的值是否与array2的顺序相同:

var array1 = ["Bob", "Jason", "Fred"];
var array2 = ["Bob", "Jason", "Fred"]; // result: true, expected: true
or
var array1 = ["Bob", "Jason", "Fred"];
var array2 = ["Bob", "Fred", "Jason"]; // result: false, expected: False
or 
var array1 = ["Bob", "Jason", "Fred"];
var array2 = ["Bob", "Jason"];         // result: true, expected: True
or 
var array1 = ["Jason", "Fred", "Bob"];
var array2 = ["Bob", "Jason"];         // result: false, expected: False
or 
var array1 = ["Jason", "Bob"];
var array2 = ["Jason", "Sue", "Bob"];  // result: false, expected: True - just because array 2 contains sue and array 1 doesn't, doesn't mean jason and bob aren't in the right order. They are. We need to ignore the fact sue is interrupting them.
or 
var array1 = ["Jason", "Sue", "Bob"];
var array2 = ["Jason", "Bob", "Sue"];  // result: false, expected: False
or 
var array1 = ["Sue", "Bob"];
var array2 = ["Jason", "Bob", "Sue"];  // result: false, expected: False
or 
var array1 = ["Bob", "Sue"];
var array2 = ["Jason", "Bob", "Sue"];  // result: false, expected: True - just because jason is playing third wheel doesn't mean bob and sue aren't in the correct order. they are. we need to ignore jason.
or 
var array1 = ["Bob", "Sue", "Bob"];
var array2 = ["Bob", "Bob", "Sue"];  // result: false, expected: False
or 
var array1 = ["Bob", "Sue", "Bob"];
var array2 = ["Bob", "Sue", "Bob"];  // result: true, expected: true
or 
var array1 = ["Bob", "Sue", "Bob"];
var array2 = ["Sue", "Bob"];  // result: false, expected: true - in this scenario, we have two Bobs. while Bob followed by Sue is false, sue followed by bob is true. we need to ignore the first Bob.

到目前为止,我已经得到了这个:

if (array1.length > array2.length) {
    var arrayLength = array1.length;
} else if (array1.length < array2.length) {
    var arrayLength = array2.length;
} else {
    var arrayLength = array1.length;
}


for (var i = 0; i < arrayLength; i++){
    if (array1[i] !== array2[i]) { 
        return false; 
    } else {
        return true;
    }
}

我的问题是上述内容并没有始终产生预期的结果。也就是说,如果两个数组的长度相同,那么我会得到预期的结果,但如果不是,我不会得到预期的结果。

我需要忽略缺失或添加的值,并纯粹查看它们是否处于相同的顺序,尽管这些缺失或添加的值。

【问题讨论】:

  • 在循环中:if (array1[i] !== array2[i]) { return false; }
  • 同一个值可以在任一数组中出现多次吗?
  • 正例中的两个数组都具有相同的第一个元素。这是要求的一部分吗? array1 = ["Jason", "Fred"]; array2 = ["Bob", "Jason", "Fred"]; 呢?
  • @GershomMaes 是的

标签: javascript arrays loops


【解决方案1】:

myArray 是一个坏名字,因为它不是一个数组。它是两个数组共享的最小长度,因此将其命名为minLength 左右。然后,您可以查看索引为 iminLength 的所有条目是正确的,但 minLength[i] 没有意义。相反,您想在数组中查找,例如array1[i]array2[i] 并比较结果(与 ===)。

有了这些信息,你应该能够以你的方式解决它:)

我会怎么做:

const result = array1.every((el, i) => i >= array2.length || el === array2[i]);

【讨论】:

    【解决方案2】:

    一种可能是.join 两个数组都使用一个在任何字符串中都不出现的分隔符,然后检查较长的.includes 是否越短:

    const array1 = ["Jason", "Bob"];
    const array2 = ["Jason", "Bob", "Sue"];
    
    const str1 = array1.join('_');
    const str2 = array2.join('_');
    
    console.log(
      str1.length > str2.length
      ? str1.includes(str2)
      : str2.includes(str1)
    );

    【讨论】:

    • “在任何字符串中都没有出现的分隔符”实际上在现实世界的应用程序中很难找到
    • 你的答案实际上是让我得到预期结果的最接近的答案,但是,他们指出分隔符的问题并没有错......
    【解决方案3】:

    您可以检查数组最小长度切片的元素。

    function sameOrder(a, b) {
        return a
            .slice(0, Math.min(a.length, b.length))
            .every((v, i) => v === b[i]);
    }
    
    console.log(sameOrder(["Bob", "Jason", "Fred"], ["Bob", "Jason", "Fred"])); //  true
    console.log(sameOrder(["Bob", "Jason", "Fred"], ["Bob", "Fred", "Jason"])); // false
    console.log(sameOrder(["Bob", "Jason", "Fred"], ["Bob", "Jason"]));         //  true
    console.log(sameOrder(["Jason", "Fred", "Bob"], ["Bob", "Jason"]));         // false
    console.log(sameOrder(["Jason", "Bob"], ["Jason", "Sue", "Bob"]));          // false
    console.log(sameOrder(["Jason", "Bob"], ["Jason", "Bob", "Sue"]));          //  true

    【讨论】:

      【解决方案4】:

      const sameSequence = (array1, array2) => {
        const longest = array1.length > array2.length ? array1 : array2;
        const shortest = array1.length <= array2.length ? array1 : array2;
        return shortest.every((item, index) => item === longest[index]);
      };
      
      array1 = console.log(sameSequence(["Bob", "Jason", "Fred"], ["Bob", "Jason", "Fred"]));
      array1 = console.log(sameSequence(["Bob", "Jason", "Fred"], ["Bob", "Fred", "Jason"]));
      array1 = console.log(sameSequence(["Bob", "Jason", "Fred"],  ["Bob", "Jason"]));
      array1 = console.log(sameSequence(["Jason", "Fred", "Bob"], ["Bob", "Jason"]));
      array1 = console.log(sameSequence(["Jason", "Bob"], ["Jason", "Sue", "Bob"]));
      array1 = console.log(sameSequence(["Jason", "Bob"], ["Jason", "Bob", "Sue"]));

      【讨论】:

        【解决方案5】:

        如果我继续你的方法,以下功能有效

        function matchArrays(arr1, arr2){
        
            //First result is true
        
            var result= true;
        
            //Get minimum length
            var iteration= Math.min(arr1.length, arr2.length);
        
            //For loop
            for(var i = 0; i<iteration;i++){
        
               //if not matched
               if(arr1[i]!=arr2[i]){
                 result=false;
                 break;
               }
            }
            return result;
        }
        

        array1 = ["Bob", "Jason", "Fred"];
        array2 = ["Bob", "Jason", "Fred"]; // true
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        //or
        
        array1 = ["Bob", "Jason", "Fred"];
        array2 = ["Bob", "Fred", "Jason"]; // False
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        //or 
        
        array1 = ["Bob", "Jason", "Fred"];
        array2 = ["Bob", "Jason"];         // True
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        //or 
        
        array1 = ["Jason", "Fred", "Bob"];
        array2 = ["Bob", "Jason"];         // False
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        //or 
        
        array1 = ["Jason", "Bob"];
        array2 = ["Jason", "Sue", "Bob"];  // False
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        //or 
        
        array1 = ["Jason", "Bob"];
        array2 = ["Jason", "Bob", "Sue"];  // True
        document.write(matchArrays(array1, array2));
        document.writeln("<br>");
        
        function matchArrays(arr1, arr2){
        	var result= true;
        	var iteration= Math.min(arr1.length, arr2.length);
            for(var i = 0; i<iteration;i++){
            	if(arr1[i]!=arr2[i]){
                	result=false;
                    break;
                }
            }
            return result;
        }

        【讨论】:

          【解决方案6】:

          此代码将帮助您找到数组的顺序。checkOrder 如果数组的顺序相同,函数将返回 true 并返回 如果两个数组都不按顺序排列,则为 false。

          let v = ['bathri','nathan',2];
          let x = ['bathri','nathan'];
          let value = [];
          
          let checkOrder = function(one, two){
          
            if(one.length != two.length){
               value = one.length < two.length ? one : two;
            }
            else{
              value = one;
            }
            
            for(let i = 0; i < value.length; i++){
              if(v[i] != x[i])
              {
                return false;
                break;
              }
            }
            return true;
          }
          
          console.log(checkOrder(v,x));

          从叶子编辑

          感谢您的贡献,但没有帮助:-\

          N = !(Y = true);
          
          // tests[3 * i] = expected result
          // tests[3 * i + 1] = array A
          // tests[3 * i + 2] = array B
          
          tests = [
            N, "BAA".split(""), "ABA".split(""),
            N, "ABA".split(""), "BAA".split(""),
            Y, "ABA".split(""), "BA+".split(""),
            Y, "BA+".split(""), "ABA".split(""),
            Y, "ABACD".split(""), "BADCD".split(""),
            Y, "ABACDDCABA".split(""), "BADCDDCDAB".split(""),
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason", "Fred"],
            N, ["Bob", "Jason", "Fred"], ["Bob", "Fred", "Jason"],
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason"],
            N, ["Jason", "Fred", "Bob"], ["Bob", "Jason"],
            Y, ["Jason", "Bob"], ["Jason", "Sue", "Bob"],
            N, ["Jason", "Sue", "Bob"], ["Jason", "Bob", "Sue"],
            N, ["Sue", "Bob"], ["Jason", "Bob", "Sue"],
            Y, ["Bob", "Sue"], ["Jason", "Bob", "Sue"],
            N, ["Bob", "Sue", "Bob"], ["Bob", "Bob", "Sue"],
            Y, ["Bob", "Sue", "Bob"], ["Bob", "Sue", "Bob"],
            Y, ["Bob", "Sue", "Bob"], ["Sue", "Bob"]
          ];
          
          for (i = 0; i < tests.length; i += 3) {
            a = tests[i + 1];
            b = tests[i + 2];
            shouldMatch = tests[i];
            doesMatch = checkOrder(a, b);
            console.log(
              shouldMatch ? "Y" : "N",
              doesMatch ? "Y" : "N",
              JSON.stringify(a),
              JSON.stringify(b)
            );
          }
          
          function checkOrder (one, two) {
            if (one.length != two.length) {
              value = one.length < two.length ? one : two;
            } else {
              value = one;
            }
            for (let i = 0; i < value.length; i++) {
              if (one[i] != two[i]) {
                return false;
                break;
              }
            }
            return true;
          }

          【讨论】:

          • 我已经编辑了您的答案,以表明您的函数没有给出预期的结果(带有“Y N”或“N Y”的行是失败的)。更多细节在这里:stackoverflow.com/a/55153120/1636522.
          【解决方案7】:

          澄清

          本部分包含我与 OP(原始海报)之间讨论的摘录。

          首先我们像这样重新定义问题:

          ME:所以你想比较常见元素的顺序?

          OP:如果是这样的话,是的。请记住,名称可以在一个或两个数组中重复。我们正在尝试检测是否发生反转,即使可能存在无关元素。

          然后我们将问题简化为比较两个单词之间常用字母的顺序:

          OP: [CUT] "AB" == "ACB", "AB" == "ABC", "AB" == "CAB", "AB" !== "BCA ", "AB" !== "CBA", "AB" !== "BAC"

          最后OP发布了以下建议:

          OP:我认为最简单的方法是检测那些没有出现在另一个数组中的元素并将它们删除。以相反的方向执行此操作,然后进行比较(删除 C)。我只是不知道该怎么做。

          我还没有尝试过,但我认为它非常接近下面的第一个算法,因为它会简单地忽略不在另一个数组中的元素。

          算法#1

          这个想法是从左到右读取数组,删除成对的公共元素,然后检查剩余集合中是否还有公共元素。

          警告。“ABACD”和“BADCD”失败。

          注意 1. 这个反例很有趣,因为它表明无论match 函数的参数顺序如何,我们都会错过一对有效的数组。

          注 2。在这种情况下以相反的方式进行迭代,但使用回文我们可以证明它并不总是有帮助,例如,“ABACDDCABA”和“BADCDDCDAB”。

          注 3。如果我们去掉“ABACD”的第一个字母,算法会给出预期的结果,这表明递归方法可能是合适的。

          一张图抵千言:

          a = "ABA", b = "BA" => a[i] != b[j] => x = 0b000, y = 0b00
               ^          ^                              ^         ^
               i          j                              i         j
          
          a = "ABA", b = "BA" => a[i] == b[j] => x = 0b001, y = 0b10
               ^           ^                             ^        ^
               i           j                             i        j
          
          > | a.split("").filter(function (_, i) {
            |   return bit(i, x) === 0;
            | })
          < | ["B", "A"]
          > | b.split("").filter(function (_, i) {
            |   return bit(i, y) === 0;
            | })
          < | ["B"]
          

          如果最终数组包含公共元素,我们会说存在反转。在这种情况下,我们必须交换原始数组以再次比较它们:

          a = "BA", b = "ABA" => a[i] != b[j] => x = 0b00, y = 0b000
               ^         ^                              ^          ^
               i         j                              i          j
          
          a = "BA", b = "ABA" => a[i] == b[j] => x = 0b01, y = 0b010
               ^          ^                             ^         ^
               i          j                             i         j
          
          a = "BA", b = "ABA" => a[i] == b[j] => x = 0b11, y = 0b110
                ^          ^                           ^         ^
                i          j                           i         j
          
          > | a.split("").filter(function (_, i) {
            |   return bit(i, x) === 0;
            | })
          < | []
          > | b.split("").filter(function (_, i) {
            |   return bit(i, y) === 0;
            | })
          < | ["A"]
          

          考虑到最后的结果,我们会说“ABA”和“BA”符合您的条件。

          fails = 0;
          N = !(Y = true)
          
          // tests[3 * i] = expected result
          // tests[3 * i + 1] = array A
          // tests[3 * i + 2] = array B
          
          tests = [
            N, "BAA".split(""), "ABA".split(""),
            N, "ABA".split(""), "BAA".split(""),
            Y, "ABA".split(""), "BA+".split(""),
            Y, "BA+".split(""), "ABA".split(""),
            Y, "ABACD".split(""), "BADCD".split(""),
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason", "Fred"],
            N, ["Bob", "Jason", "Fred"], ["Bob", "Fred", "Jason"],
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason"],
            N, ["Jason", "Fred", "Bob"], ["Bob", "Jason"],
            Y, ["Jason", "Bob"], ["Jason", "Sue", "Bob"],
            N, ["Jason", "Sue", "Bob"], ["Jason", "Bob", "Sue"],
            N, ["Sue", "Bob"], ["Jason", "Bob", "Sue"],
            Y, ["Bob", "Sue"], ["Jason", "Bob", "Sue"],
            N, ["Bob", "Sue", "Bob"], ["Bob", "Bob", "Sue"],
            Y, ["Bob", "Sue", "Bob"], ["Bob", "Sue", "Bob"],
            Y, ["Bob", "Sue", "Bob"], ["Sue", "Bob"]
          ];
          
          for (i = 0; i < tests.length; i += 3) {
            a = tests[i + 1];
            b = tests[i + 2];
            shouldMatch = tests[i];
            doesMatch = match(a, b) || match(b, a);
            if (shouldMatch !== doesMatch) fails++;
            console.log(
              shouldMatch ? "Y" : "N",
              doesMatch ? "Y" : "N",
              JSON.stringify(a),
              JSON.stringify(b)
            );
          }
          
          console.log(
            "fails =", fails
          );
          
          function bit (i, n) {
            return n >> i & 1;
          }
          
          function match (a, b) {
            var offset = 0, x = 0, y = 0;
            for (var i = 0; i < a.length; i++) {
              for (var j = offset; j < b.length; j++) {
                if (a[i] === b[j]) {
                  x += 1 << i;
                  y += 1 << j;
                  offset = j + 1;
                  j = b.length; // break
                }
              }
            }
            a = a.filter(function (_, i) {
              return bit(i, x) === 0;
            });
            b = b.filter(function (_, i) {
              return bit(i, y) === 0;
            });
            return !a.some(function (x) {
              return b.some(function (y) {
                return x === y;
              });
            });
          }

          算法#2

          警告。此算法的正确性必须验证(目前没有反例)。

          这个想法是比较取K的N个元素的每个组合,K从N到0。

          具体情况

          让我们关注 N = 3 和 K = 2 的特定情况。为了简化代码,我用+ 符号填充了最小的单词,以便以相同长度的单词开头:

          rmDots = w => w.replace(/\.+/g, ""); // dots remover
          a = "ABA"; b = "BA+"; // words
          n = 3; // words length
          
          for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
              // explode `a` and `b`
              x = a.split("");
              y = b.split("");
              // hide one letter starting
              // from the rightmost one
              x[n - (i + 1)] = ".";
              y[n - (j + 1)] = ".";
              // implode `a` and `b`
              x = x.join("");
              y = y.join("");
              // print out
              console.log(
                // match ? "Yes" : "No"
                rmDots(x) === rmDots(y) ? "Y" : "N",
                JSON.stringify(x), JSON.stringify(y)
              );
            }
          }

          之后,您必须检查匹配组合对以过滤没有剩余常用字母的组合。例如,使用“ABA”和“BAA”,并且 K = 2(并且 N = 3,因为 N 是字符串的长度),您会得到 3 对匹配组合:

          Y "A.A" ".AA"
          Y ".BA" "BA."
          Y ".BA" "B.A"
          

          但是,总是有一个剩余的共同字母(在点后面),分别是".B.""B.."、“A..""..A",以及 "A.."".A."。因此,与K = 2,实际上没有任何一对组合符合您的条件,您必须使用 K = 1 再试一次。

          概括

          以下代码sn-p应该有助于理解最终算法:

          function C (n, k) {
            var acc = 1, i = 0;
            while (++i <= k) acc *= (n - k + i) / i;
            return acc;
          }
          
          function Ci (n, k, i) {
            var j, c, flags = new Array(n);
            for (j = 1; j <= n; j++) {
              if (k > 0 && (c = C(n - j, k - 1)) > i) {
                k -= 1; flags[j - 1] = true;
              } else {
                i -= c; flags[j - 1] = false;
              }
            }
            return flags;
          }
          
          /* ignore this line */ (function(){for(var n=/^ */,e=">",t="<",r="!",o="+",i=Array.prototype.map,l=Array.prototype.slice,a=document.getElementsByTagName("pre"),u=0,c=arguments.length;u<c;u++)a[u].innerHTML=i.call(arguments[u],function(n){return p(n[0])+f(n[2])+s(n[1])}).join("");function p(t){var r=t.split("\n"),o=r[0].match(n)[0].length;return y(e,d(r.map(function(n){return n.slice(o)}).join("\n")))}function s(n){return n instanceof Error?y(r,g("#F00",n+"")):y(t,void 0===n?g("#999","undefined"):d(JSON.stringify(n)))}function f(n){return n.reduce(function(n,e){var t="string"!=typeof e[0],r=l.call(e).map(function(n){return"string"!=typeof n||t?JSON.stringify(n):n}).join(" ");return n+y(o,t?d(r):r)},"")}function y(n,e){return'<span style="display:block"><span style="display:inline-block">'+e.split("\n").map(function(e,t){return(0===t?n:" ")+" | "}).join("\n")+'</span><span style="display:inline-block">'+e+"</span></span>"}function g(n,e){return"<span "+('style="color:'+n+'"')+">"+e+"</span>"}function d(n){return"<code>"+n+"</code>"}}).apply(this,eval("["+function(){var n=/("|\\)/g,e=/^.*?\n|\n.*?$/g,t=Array.prototype.map,r=Array.prototype.filter,o=document.getElementsByTagName("pre");return t.call(o,function(t){return"["+r.call(t.childNodes,function(n){return 8===n.nodeType&&n.nodeValue.split("\n").length>2}).map(function(t){return["function(b,i,o){","return console.log=b[0],[","i,o,b[1]","];","}(function(f,l){","return console.log=function(){","return l.push(arguments),(","f.apply(console,arguments)",");","},[f,l];","}(console.log,[]),",t=JSON.stringify(t.nodeValue.replace(e,"")),',eval("try{',"eval(",t.replace(n,"\\$1"),")",'}catch(e){e}"))'].join("")}).join(",")+"]"}).join(",")}()+"]"));
          /* ignore this line */ body{padding:1em !important}html,body{min-width:auto !important}
          <link href="https://cdn.sstatic.net/Shared/stacks.css?v=58428843e325" rel="stylesheet"/>
          <link href="https://cdn.sstatic.net/Sites/stackoverflow/primary.css?v=2ed743cc91af" rel="stylesheet"/>
          <link href="https://cdn.sstatic.net/clc/styles/clc.min.css?v=768595a6d237" rel="stylesheet"/>
          <blockquote>
            <p><strong>Help.</strong> Run this snippet then press "Full page".</p>
          </blockquote>
          <blockquote>
            <p><strong>Help.</strong> <code>&gt;</code> = "input", <code>&lt;</code> = "output", <code>+</code> = "log".</p>
          </blockquote>
          <p>Taking 2 things among 3:</p>
          <pre>
          <!--
          n = 3
          --><!--
          k = 2
          --><!--
          Ci(n, k, 0) // 1st combination
          --><!--
          Ci(n, k, 2) // 3rd combination
          -->
          </pre>
          <p>Enumerating combinations:</p>
          <pre>
          <!--
          c = C(n, k) // how many combinations?
          --><!--
          for (i = 0; i < c; i++) {
            console.log(i, Ci(n, k, i));
          }
          -->
          </pre>
          <p>Hiding 2 letters among 3:</p>
          <pre>
          <!--
          letters = "ABC".split("")
          --><!--
          for (i = 0; i < c; i++) {
            flags = Ci(n, k, i);
            console.log(i, letters.map(function (letter, i) {
              var hide = flags[i];
              return hide ? "." : letter;
            }).join(""), flags);
          }
          -->
          </pre>
          <p>Taking 2 letter among 3:</p>
          <pre>
          <!--
          letters = "XYZ".split("")
          --><!--
          for (i = 0; i < c; i++) {
            flags = Ci(n, k, i);
            console.log(i, letters.filter(function (_, i) {
              var take = flags[i];
              return take;
            }).join(""), flags);
          }
          -->
          </pre>

          请记住,这是一种蛮力方法。每个 K 有 C(n,k) * C(n,k) 个可能的组合对(有关 C(n,k) 的详细信息,请参阅 Wikipedia),因此,比较字符串所需的时间可能关于字符串 (n) 的大小呈指数增长 (C(n,k)^2)。换句话说,大字符串可能会耗尽您的 CPU...

          fails = 0;
          N = !(Y = true);
          
          // tests[3 * i] = expected result
          // tests[3 * i + 1] = array A
          // tests[3 * i + 2] = array B
          
          tests = [
            N, "BAA".split(""), "ABA".split(""),
            N, "ABA".split(""), "BAA".split(""),
            Y, "ABA".split(""), "BA+".split(""),
            Y, "BA+".split(""), "ABA".split(""),
            Y, "ABACD".split(""), "BADCD".split(""),
            Y, "ABACDDCABA".split(""), "BADCDDCDAB".split(""),
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason", "Fred"],
            N, ["Bob", "Jason", "Fred"], ["Bob", "Fred", "Jason"],
            Y, ["Bob", "Jason", "Fred"], ["Bob", "Jason"],
            N, ["Jason", "Fred", "Bob"], ["Bob", "Jason"],
            Y, ["Jason", "Bob"], ["Jason", "Sue", "Bob"],
            N, ["Jason", "Sue", "Bob"], ["Jason", "Bob", "Sue"],
            N, ["Sue", "Bob"], ["Jason", "Bob", "Sue"],
            Y, ["Bob", "Sue"], ["Jason", "Bob", "Sue"],
            N, ["Bob", "Sue", "Bob"], ["Bob", "Bob", "Sue"],
            Y, ["Bob", "Sue", "Bob"], ["Bob", "Sue", "Bob"],
            Y, ["Bob", "Sue", "Bob"], ["Sue", "Bob"]
          ];
          
          for (i = 0; i < tests.length; i += 3) {
            a = tests[i + 1];
            b = tests[i + 2];
            shouldMatch = tests[i];
            doesMatch = match(a, b);
            if (shouldMatch !== doesMatch) fails++;
            console.log(
              shouldMatch ? "Y" : "N",
              doesMatch ? "Y" : "N",
              JSON.stringify(a),
              JSON.stringify(b)
            );
          }
          
          console.log(
            "fails =", fails
          );
          
          function C (n, k) {
            var acc = 1, i = 0;
            while (++i <= k) acc *= (n - k + i) / i;
            return acc;
          }
          
          function Ci (n, k, i) {
            var j, c, flags = new Array(n);
            for (j = 1; j <= n; j++) {
              if (k > 0 && (c = C(n - j, k - 1)) > i) {
                k -= 1; flags[j - 1] = true;
              } else {
                i -= c; flags[j - 1] = false;
              }
            }
            return flags;
          }
          
          function match (a, b) {
            var n, c, i, j;
            var k; // drop `k` elements
            var a2, b2, a3, b3, aFlags, bFlags;
            n = Math.max(a.length, b.length);
            if (a.length < n) a = a.concat(
              new Array(n - a.length).fill(null)
            );
            if (b.length < n) b = b.concat(
              new Array(n - b.length).fill(null)
            );
            for (k = 0; k < n; k++) {
              c = C(n, k);
              for (i = 0; i < c; i++) {
                aFlags = Ci(n, k, i);
                a2 = a.filter(function (_, i) {
                  return !aFlags[i];
                });
                for (j = 0; j < c; j++) {
                  bFlags = Ci(n, k, j);
                  b2 = b.filter(function (_, i) {
                    return !bFlags[i];
                  });
                  // a2[i] = b2[i] (i in [0-(n-k)])
                  // means that we found the biggest
                  // sequence of common elements.
                  // Therefore, we can stop searching
                  // and check if there is at least
                  // one pair of common elements
                  // in the remaining set.
                  if (a2.every(function (x, i) {
                    return x === b2[i];
                  })) {
                    a3 = a.filter(function (_, i) {
                      return aFlags[i];
                    });
                    b3 = b.filter(function (_, i) {
                      return bFlags[i];
                    });
                    return !a3.some(function (x) {
                      return b3.some(function (y) {
                        return x === y;
                      });
                    });
                  }
                }
              }
            }
            return false;
          }

          请注意,我用null 值填充最小的数组以从相同长度的数组开始。如果数组已经包含 null 值,则可能会出现问题,但找到解决方法并不是什么大问题。

          【讨论】:

            猜你喜欢
            • 2018-08-30
            • 1970-01-01
            • 2019-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-10
            相关资源
            最近更新 更多