【问题标题】:Recursion problem on Codewars Kata - Snail TrailCodewars Kata 上的递归问题 - Snail Trail
【发布时间】:2019-11-27 21:14:47
【问题描述】:

对编码非常陌生,所以请多多包涵。我正在尝试在 Codewars 上解决这个 Kata:https://www.codewars.com/kata/snail/train/javascript

基本上给定一个像

这样的数组
[ 
    [1, 2, 3, 4], 
    [12,13,14,5], 
    [11,16,15,6], 
    [10,9, 8, 7]
];

它会返回[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

在矩阵的外侧和内侧盘旋的蜗牛轨迹。

我只是解决矩阵为 n x n 的情况,其中 n > 1 并且现在是偶数。

我通过在函数外部声明 outputarray 使其工作,但我希望在函数内声明该数组,因此包含以下行:var outputarray = outputarray || [];

不知道我哪里出错了。

snail = function(array) {
  if (array.length == 0) {
    return outputarray
  }
  var n = array[0].length - 1;
  var outputarray = outputarray || [];
  for (var i = 0; i <= n; i++) {
    outputarray.push(array[0].splice(0, 1));
  }
  for (var i = 1; i <= n; i++) {
    outputarray.push(array[i].splice(n, 1));
  }
  for (var i = n - 1; i >= 0; i--) {
    outputarray.push(array[n].splice(i, 1));
  }
  for (var i = n - 1; i > 0; i--) {
    outputarray.push(array[i].splice(0, 1));
  }
  array.pop();
  array.shift();
  snail(array);
}

【问题讨论】:

标签: javascript arrays recursion


【解决方案1】:

一种选择是在snail 中定义另一个函数,它递归调用自身,同时在snail 中定义outputarray。这样,outputarray 就不会暴露给外部作用域,但递归函数仍然可以看到它。

还要注意splice 返回一个数组,所以现在你的outputarray 由一个数组组成。改为扩散到push 来修复它,使outputarray 变成一个数字数组:

const input = [
  [1, 2, 3, 4],
  [12, 13, 14, 5],
  [11, 16, 15, 6],
  [10, 9, 8, 7]
];

const snail = (array) => {
  const outputarray = [];
  const iter = () => {
    if (array.length == 0) {
      return
    }
    var n = array[0].length - 1;
    for (var i = 0; i <= n; i++) {
      outputarray.push(...array[0].splice(0, 1));
    }
    for (var i = 1; i <= n; i++) {
      outputarray.push(...array[i].splice(n, 1));
    }
    for (var i = n - 1; i >= 0; i--) {
      outputarray.push(...array[n].splice(i, 1));
    }
    for (var i = n - 1; i > 0; i--) {
      outputarray.push(...array[i].splice(0, 1));
    }
    array.pop();
    array.shift();
    iter(array);
  };
  iter(array);
  return outputarray;
}

console.log(snail(input));

【讨论】:

  • 这似乎是唯一真正尝试回答 OP 问题的答案 :)
【解决方案2】:

这是一种不会改变输入 array 的非递归方法。它通过跟踪左上角坐标x, y 和螺旋的大小n 来工作。

snail = function(array) {
  const { length } = array;
  const result = [];
  let x = 0;
  let y = 0;
  let n = length;

  while (n > 0) {
    // travel right from top-left of spiral
    for (let i = x; i < x + n; ++i) result.push(array[y][i]);

    // shrink spiral and move top of spiral down
    n--; y++;

    // travel down from top-right of spiral
    for (let i = y; i < y + n; ++i) result.push(array[i][x + n]);

    // travel left from bottom-right of spiral
    for (let i = x + n - 1; i >= x; --i) result.push(array[y + n - 1][i]);

    // shrink spiral
    n--;

    // travel up from bottom-left of spiral
    for (let i = y + n - 1; i >= y; --i) result.push(array[i][x]);

    // move left of spiral right
    x++;
  }

  return result;
}

console.log(snail([[1, 2, 3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7]]));

【讨论】:

    【解决方案3】:

    您可以为左、右、上、下索引设置一些边框并循环,直到没有更多索引可用。

    function snail(array) {
        var upper = 0,
            lower = array.length - 1,
            left = 0,
            right = array[0].length - 1,
            i = upper,
            j = left,
            result = [];
    
        while (true) {
            if (upper++ > lower) break;
    
            for (; j < right; j++) result.push(array[i][j]);
            if (right-- < left) break;
    
            for (; i < lower; i++) result.push(array[i][j]);
            if (lower-- < upper) break;
    
            for (; j > left; j--) result.push(array[i][j]);
            if (left++ > right) break;
    
            for (; i > upper; i--) result.push(array[i][j]);
        }
    
        result.push(array[i][j]);
        return result;
    }
    
    console.log(...snail([[1, 2, 3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7]]));

    【讨论】:

      【解决方案4】:

      这可能不符合kata的规则(或精神?),但是,您可以将它们粘在一起并排序。

      function snail(trail) {
        const numeric = (a, b) => a - b
        const gather = (items, item) => items.push(parseInt(item, 10)) && items
        const inline = (route, points) => points.reduce(gather, route) && route
        const order = paths => paths.reduce(inline, []).sort(numeric)
      
        return order(trail)
      }
      
      const trail = [
          [1, 2, 3, 4], 
          [12, 13, 14, 5], 
          [11, 16, 15, 6], 
          [10, 9, 8, 7]
      ]
      
      console.log(JSON.stringify(snail(trail)))

      【讨论】:

      • 我认为重点是在螺旋路径中遍历,而不是返回排序的值列表(例如,切换 4 和 3 应该导致 [1, 2, 4, 3...等)。
      【解决方案5】:

      试试这个:

      const input = [
        [1, 2, 3, 4],
        [12, 13, 14, 5],
        [11, 16, 15, 6],
        [10, 9, 8, 7]
      ];
      
      function snail(array) {
        var res = [];
        
        if (!array.length) return res;
        var next = array.shift();
        if (next) res = res.concat(next);
        for (var i = 0; i < array.length; i++) {
          res.push(array[i].pop());
        }
        next = array.pop()
        if (next) res = res.concat(next.reverse());
        for (var i = array.length - 1; i >= 0; i--) {
          res.push(array[i].shift());
        }
      
        return res.concat(snail(array));
      }
      console.log(snail(input));

      【讨论】:

        【解决方案6】:

        这是我的两分钱,使用惯用的递归:

        function f(A){
          return A.length > 1 ? A.splice(0,1)[0].concat(
            f(A[0].map((c, i) => A.map(r => r[i])).reverse())) : A[0]
        }
        
        var A = [[ 1, 2, 3, 4], [12,13,14, 5], [11,16,15, 6], [10, 9, 8, 7]]
        
        console.log(JSON.stringify(f(A)))

        【讨论】:

        • 应该注意的是,这个解决方案改变了原来的解决方案。在我看来,这是不合格的。 (是的,我知道这很容易解决。)
        • @ScottSauyet 我的不是这里唯一改变原始答案的答案,是吗?
        • @ScottSauyet 这仅用于演示。在实践中,我希望有一个更有效的解决方案,而不需要换位 :)
        • 不,只是我读到的第一个。我记得你answering 这个问题的早期版本以非变异的方式。由于这主要是一个难题,我想,而且不太可能耗尽堆栈空间或其他资源,我通常更喜欢最干净的解决方案,除非它被证明不切实际地慢。
        • @ScottSauyet 你如何定义“干净”?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-17
        • 2018-01-05
        • 2020-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多