【问题标题】:Find same values in array diagonally对角线在数组中查找相同的值
【发布时间】:2016-10-21 23:16:04
【问题描述】:

我有一个数组,可以说

var array = [ [1, 0, 0, 0, 0, 0, 0],
              [0, 1, 0, 0, 0, 1, 0],
              [0, 0, 1, 0, 1, 0, 0],
              [0, 0, 0, 1, 0, 0, 0],
              [0, 0, 1, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0]
            ]

我想创建一个来查找数字在对角线上出现四次的任何匹配项。

目前我正在使用

function checkDiagonal(array, bottomToTop) {
    var Ylength = array.length;
    var Xlength = array[0].length;
    var maxLength = Math.max(Xlength, Ylength);
    var temp;
    var returnArray = [];
    for (var k = 0; k <= 2 * (maxLength - 1); ++k) {
        temp = [];
        for (var y = Ylength - 1; y >= 0; --y) {
            var x = k - (bottomToTop ? Ylength - y : y);
            if (x >= 0 && x < Xlength) {
                temp.push(array[y][x]);
            }
        }
        if(temp.length > 0) {
            returnArray.push(temp.join(''));
        }
    }
    return returnArray;
}

但它并不总能找到所有解决方案

【问题讨论】:

标签: javascript arrays


【解决方案1】:

有趣的案例。实际上很难找到/编写一个简单的方法。 我试图理解您的脚本,但发现它有点难以遵循/调试,因此尝试重现您在我自己的脚本中所做的事情并设法获得所需的结果。它的代码行数比你的多,但它有一些变量与一些 cmets 一起声明,因此更容易理解(对于其他人,在未来)。

希望这会有所帮助:

function checkDiagonal(array, matchCount) {
  var result = [];

  if(array.length >= matchCount) {
    // Search towards bottom-right.
    result = result.concat(getDiagonalResult(array, matchCount, 1));

    // Search towards top-right.
    result = result.concat(getDiagonalResult(array, matchCount, -1));
  } else {
    // No use searching if not enough rows are present.
  }

  return result;
}

function getDiagonalResult(array, matchCount, direction) {
  var result = [];

  // Specific from and to points to only search in possible rows (e.g. no use searching top-right on first row).
  var yFrom, yTo;

  // Search direction (bottom-right vs top-right).
  switch(direction) {
      // Bottom-right.
    case 1:
      yFrom = 0;
      yTo = (array.length - matchCount);
      break;

      // Top-right.
    case -1:
      yFrom = (matchCount - 1);
      yTo = (array.length - 1);
      break;
  }

  // Loop through all 'rows'.
  for(var y = yFrom; y <= yTo; y++) {

    // Loop through all 'columns'.
    for(var x = 0; x <= (array[y].length - matchCount); x++) {

      // Current value to match on.
      var originalValue = array[y][x];
      var matches = [];

      // Get matches.
      for(var i = 0; i < matchCount; i++) {
        // Search direction (row up or down).
        var yDirection = (i * direction);

        var value = array[y+yDirection][x+i];

        if(value === originalValue) {
          matches.push(value);
        }
      }

      if(matches.length == matchCount) {
        result.push(matches.join(""));
      }
    }

  }

  return result;
}

var array = [
  [1, 0, 0, 0, 0, 0, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 0, 1, 0, 1, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0]
];

console.log(checkDiagonal(array, 4));

【讨论】:

    【解决方案2】:

    我会通过旋转每个子数组来预处理数组,使数字在彼此下方形成一条对角线。首先定义函数以通过n 元素在任一方向上旋转单个数组:

    const rotateLeft     = (array, n) => array.slice(n).concat(array.slice(0, n));
    const rotateRight    = (array, n) => rotateLeft(array, -n);
    

    以及在任一方向以不断增加的量旋转每个子数组的函数:

    const rotateAllLeft  = array => array.map(rotateLeft);
    const rotateAllRight = array => array.map(rotateRight);
    

    你的数组现在看起来像这样,垂直排列:

    var array = [ [1, 0, 0, 0, 0, 0, 0],
                  [1, 0, 0, 0, 1, 0, 0],
                  [1, 0, 1, 0, 0, 0, 0],
                  [1, 0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 1, 0],
                  [0, 0, 0, 0, 0, 0, 0]
                ]
    

    问题现在简化为寻找垂直线。为此,首先转置数组是最简单的方法,您可以这样做:

    const transpose = array => array[0].map((_, i) => array.map(row => row[i]));
    

    我们现在将编写一个小函数,它接受一个数组并返回另一个数组,其值是特定值的“运行”长度:

    const run = (array, val, cnt = 0) => array.map(elt => cnt = elt === val ? ++cnt : 0;
    

    对于[1, 1, 1, 1, 0, 0],这将返回[1, 2, 3, 4, 0, 0]4 表示到该点为止的四个 1 值的运行。

    编写小函数来测试单个数组中某个最小长度的特定值的运行,或任何子数组中某个最小长度的特定值的运行:

    const hasRunOf = (array, val, n) => run(array, val).some(len => len >= n);
    const hasAnyRunOf = (array, val, n) => array.some(subarray => hasRunOf(subarray, val, n));
    

    您现在可以测试是否存在四个或更多的运行

    hasAnyRunOf(transpose(rotateAllLeft(array)), 1, 4) || 
      hasAnyRunOf(transpose(rotateAllRight(array)), 1, 4)        
    

    捕获有关对角线运行的确切位置的信息留作练习。

    【讨论】:

      【解决方案3】:

      嗯,这是从我这里得到的最好的。它只计算n 大小组中的每个元素一次。换句话说,一个存在于一个组中的元素不能存在于另一个组中。

      这是一个游戏,使用最佳数量的xy 起始索引,然后从该起始点开始计算每个元素在对角线向前和向后驻留的索引。显然,我们应该在右边的 xy 索引处开始和停止,我们可以在对角线上找到 n 元素的数量。一旦n 增长,这将减少要完成的工作量。因此,每组 12 个元素的 100x100 数组的计算速度将比每组 4 个元素的数组快得多。

      function getDiagonals(a,rep){
        var xLen = a[0].length,         // x dimension
            yLen = a.length,            // y dimension
            xMin = rep-1,               // minimum x value to start testing from
            xMax = xLen-rep,            // maximum x value to test up until
            yMin = rep-1,               // minimum y value to start testing from
            yMax = yLen-rep,            // maximum y value to test up until
          minDim = Math.min(yLen,xLen), // the smallest dimensison
         quadros = [],                  // the resutls array
           temp1 = [],                  // utility array #1
           temp2 = [],                  // utility array #2
           item1,                       // current element on the slash test
           item2;                       // current element on the backslash test
      
        for (var x = xMin; x < xLen; x++){
        	for(var y = 0; y <= x && y < minDim; y++){
        	  item1 = a[y][x-y];          // slash test on x axis
        	  item2 = a[yLen-1-y][x-y];   // backslash test on x axis
        	  temp1[0] === item1 ? temp1.length < rep-1 ? temp1.push(item1)
        	                                            : (temp1.push(item1), quadros.push(temp1), temp1 = [])
        	                     : temp1 = [item1];
        	  temp2[0] === item2 ? temp2.length < rep-1 ? temp2.push(item2)
        	                                            : (temp2.push(item2), quadros.push(temp2), temp2 = [])
        	                     : temp2 = [item2];
        	}
        	temp1 = [];
        	temp2 = [];
        }
        for (var y = 1; y <= yMax; y++){
        	for(var x = xLen-1; x >= xLen - minDim + y; x--){
        	  item1 = a[y-x+xLen-1][x];   // slash test on y axis
        	  item2 = a[yLen-y-xLen+x][x];// backslash test on y axis
        	  temp1[0] === item1 ? temp1.length < rep-1 ? temp1.push(item1)
        	                                            : (temp1.push(item1), quadros.push(temp1), temp1 = [])
        	                     : temp1 = [item1];
        	  temp2[0] === item2 ? temp2.length < rep-1 ? temp2.push(item2)
        	                                            : (temp2.push(item2), quadros.push(temp2), temp2 = [])
        	                     : temp2 = [item2];
        	}
        	temp1 = [];
        	temp2 = [];
        }
        return quadros;
      }
      
      var arr = [ [1, 0, 0, 0, 0, 0, 0],
                  [0, 1, 0, 0, 0, 1, 0],
                  [0, 0, 1, 0, 1, 0, 0],
                  [0, 0, 0, 1, 0, 0, 0],
                  [0, 0, 1, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0]
                ],
          brr = Array(100).fill().map(_ => Array(100).fill().map(e => ~~(Math.random()*2))),
       result = getDiagonals(arr,4);
      console.log(JSON.stringify(result),result.length);
       result = getDiagonals(brr,12);
      console.log(JSON.stringify(result),result.length);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多