【问题标题】:Use recursion to find 4 consecutive 1's in 2D array使用递归在二维数组中查找 4 个连续的 1
【发布时间】:2014-05-17 15:13:52
【问题描述】:
1 1 0 0
0 0 0 0
0 0 0 0
1 1 0 0

如果以上是我的输入,我的代码应该会在其中找到四个连续的 1。 我知道我们必须使用环绕数组来解决这个问题,但我不知道如何实现它。 这是修改后的代码

public static boolean findFourOnes(int[][] arr){
    for(int i = 0; i < arr.length; i++){
        if(findVertical(arr, i, 0, 0)){
            return true;
        }
    }
    for(int i = 0; i < arr.length; i++){
        if(findHorizontal(arr, 0, i, 0)){
            return true;
        }
    }
    return false;
}
public static boolean findVertical(int[][] arr, int x, int y, int counter){
    //base case
    if(counter == 4)
        return true;

    if(arr[x][y] == 1)//consecutive 
        counter++;
    else//not consecutive
        counter = 0;

   y++;

    // wrap around case
    if(y == arr.length - 1|| y == arr.length +1){
        int max_size=4;
        if(y < 0) {y=x + max_size; return findVertical(arr, x, y, counter);}
        else if(y >= max_size) {y=x % max_size;return findVertical(arr, x, y, counter);}


    }

    return false;
}
public static boolean findHorizontal(int[][] arr, int x, int y, int counter){
    //base case
    if(counter == 4)
        return true;

    if(arr[x][y] == 1)//consecutive 
        counter++;
    else//not consecutive
        counter = 0;

   x++;

    // wrap around case
    if(x == arr.length - 1|| x == arr.length +1){
        int max_size=4;
        if(x < 0) {x=x + max_size;    return findHorizontal(arr, x, y, counter);}
        else if(x >= max_size) {x=x % max_size;    return findHorizontal(arr, x, y, counter);}

    }

   return false;


}

此代码仅检查数组中是否有四个连续的 1。如果工作正常, 我的矩阵是 4X4。在这段代码中,我的数组 b 是空的,带有零。如果我找到四个 1,我会更新该矩阵。

【问题讨论】:

  • 这是否意味着连续的 4 个可以是水平的、垂直的或对角的?你提到了环绕,但你的例子并没有真正的意义。您在寻找任何 4 组“1”吗?
  • 它可以是水平和垂直的,但不能是对角线
  • 这会引发很多NullPointerExceptions,对吧?在if 中使用价值nullBoolean 应该可以做到这一点。还有你为什么要换b?

标签: java recursion data-structures


【解决方案1】:

Cyber​​neticTwerkGuruOrc 解决方案的纯递归变体:

public class FourOnes {

    public static boolean solveArrayRecursively(int[][] array) {
        return solveRowsRecursively(array, 0, 0, 0) || solveColumnsRecursively(array, 0, 0, 0);
    }

    public static boolean solveColumnsRecursively(int[][] array, int x, int y, int found) {
        if(found >= 4) {
            // We have 4 consecutive ones
            return true;
        }
        if(x != 0 && x >= array.length) {
            // next column
            return solveColumnsRecursively(array, 0, y + 1, 0);
        }
        if(x >= array.length || y >= array[x].length) {
            // no more columns
            return false;
        }
        if(array[x][y] == 1) {
            // found another 1
            return solveColumnsRecursively(array, x + 1, y, found + 1);
        } else {
            // reset count to 0 as there is a gap in the sequence
            return solveColumnsRecursively(array, x + 1, y, 0);
        }
    }

    public static boolean solveRowsRecursively(int[][] array, int x, int y, int found) {
        if(found >= 4) {
            // We have 4 consecutive ones
            return true;
        }
        if(x >= array.length ) {
            // no more rows
            return false;
        }
        if(y >= array[x].length) {
            // next row
            return solveRowsRecursively(array, x + 1, 0, 0);
        }
        if(array[x][y] == 1) {
            // found another 1
            return solveRowsRecursively(array, x, y + 1, found + 1);
        } else {
            // reset count to 0 as there is a gap in the sequence
            return solveRowsRecursively(array, x, y + 1, 0);
        }
    }

    public static void main(String[] args) {
        System.out.println(solveArrayRecursively(new int[][] {
                new int[] {1, 1, 0, 0},
                new int[] {0, 0, 0, 0},
                new int[] {0, 0, 0, 0},
                new int[] {0, 0, 1, 1}
        }));
        System.out.println(solveArrayRecursively(new int[][] {
                new int[] {1, 1, 0, 0},
                new int[] {0, 0, 0, 0},
                new int[] {1, 1, 1, 1},
                new int[] {0, 0, 1, 1}
        }));
        System.out.println(solveArrayRecursively(new int[][] {
                new int[] {1, 1, 1, 0},
                new int[] {0, 0, 1, 0},
                new int[] {0, 0, 1, 0},
                new int[] {0, 0, 1, 1}
        }));
        System.out.println(solveArrayRecursively(new int[][] {
                new int[] {1, 1, 1, 1},
                new int[] {1, 1, 1, 1},
                new int[] {1, 1, 1, 1},
                new int[] {1, 1, 1, 1}
        }));
        System.out.println(solveArrayRecursively(new int[0][0]));
    }
}

备用:

    public static boolean solveArrayRecursively(int[][] array) {
        return solveRecursively(array, 0, 0, 0, 0);
    }

    public static boolean solveRecursively(int[][] array, int x, int y, int foundX, int foundY) {
        if(foundX >= 4 || foundY >= 4) {
            return true;
        }
        if(x >= array.length || y >= array[x].length) {
            return false;
        }
        if(array[x][y] == 1) {
            return solveRecursively(array, x + 1, y, foundX + 1, 1)
                    || solveRecursively(array, x, y + 1, 1, foundY + 1);
        } else {
            return solveRecursively(array, x + 1, y, 0, 0)
                    || solveRecursively(array, x, y + 1, 0, 0);
        }
    }

请注意,虽然在某些情况下替代获取会表现得更好,但它并不是一个简单的 [尾递归](http://en.wikipedia.org/wiki/Tail_call],它会增加大量堆栈溢出的风险数组,而第一个解决方案会在调试中产生更多的堆栈溢出,因为尾递归很可能没有优化。

另请注意,第一个解决方案以1 + (columns+1)*(rows+1) 的最大递归深度进行1 + 2*(columns+1)*(rows+1) 调用,而第二个解决方案以1 + columns + rows 的最大深度进行调用,如下所示:

 x=0 x=1 x=2 x=3 x=4
y=0 1 1 1 1 1
y=1 1 2 3 4 4
y=2 1 3 6 10 10
y=3 1 4 10 20 20
y=4 1 4 10 20 

【讨论】:

  • 谢谢你的帮助....我只是想让你知道我必须使用包装数组
  • 嘿,我正在尝试更改 Cyber​​neticTwerkGuruOrc 的纯递归变体的代码,以便它可以用于环绕数组,但它总是返回 false
  • @user3487291 你在哪里需要 rto wrap arround?线路是否连接?列是否连接? 4个就够了吗?
  • 我正在开发kmap,需要检查角落1
【解决方案2】:

您不需要为行和列编写单独的方法 - 只需转置输入数组并使用相同的方法:

public class FourConsecutiveOnes {

    public static boolean fourOnes(final int[][] input, int x, int y, int remaining) {
        if (remaining == 0) {
            return true;
        }
        if (y == input[0].length) {
            remaining = 4;
            y = 0;
            x = x + 1;
        }
        if (x == input.length) {
            return false;
        }
        if (input[x][y] == 1) {
            return fourOnes(input, x, y + 1, remaining - 1);
        } else {
            return fourOnes(input, x, y + 1, 4);
        }
    }

    public static int[][] transpose(final int[][] input) {
        int[][] result = new int[input[0].length][input.length];
        for (int i = 0; i < input.length; i++) {
            for (int j = 0; j < input[0].length; j++) {
                result[j][i] = input[i][j];
            }
        }
        return result;
    }

    public static void main(String[] args) {
        final int[][] input = new int[][]{
                new int[] {1, 1, 0, 0},
                new int[] {1, 1, 1, 0},
                new int[] {0, 0, 0, 0},
                new int[] {1, 0, 0, 0},
        };

        System.out.println(fourOnes(input, 0, 0, 4) || fourOnes(transpose(input), 0, 0, 4));
    }
}

【讨论】:

  • 您的转置是迭代的。为什么不去public static boolean solveArrayIteratively(int[][] array) { final int[] yCounts = new int[array[0].length]; int xCount; for (int[] row : array) { xCount = 0; for (int y = 0; y &lt; row.length; y++) { if (row[y] == 1) { yCounts[y]++; xCount++; if (yCounts[y] &gt;= 4 || xCount &gt;= 4) { return true; } } else { yCounts[y] = 0; xCount = 0; } } } return false; }
【解决方案3】:

您需要 4 个参数。二维数组 (arr)、当前x 位置、当前y 位置和一个整数counter 用于1。您应该为水平搜索和垂直搜索创建两种单独的递归方法。最后有一个循环二维数组并调用这两个搜索方法的主要方法。

这是您调用并传入数组的主要方法:

public static boolean findFourOnes(int[][] arr){
    for(int i = 0; i < arr.length; i++){
        if(findVertical(arr, i, 0, 0)){
            return true;
        }
    }
    for(int i = 0; i < arr.length; i++){
        if(findHorizontal(arr, 0, i, 0)){
            return true;
        }
    }
    return false;
}

现在是垂直递归方法:

public static boolean findVertical(int[][] arr, int x, int y, int counter){
    //base case
    if(counter == 4)
        return true;

    if(arr[x][y] == 1)//consecutive 
        counter++
    else//not consecutive
        counter = 0;

    y++;

    //change this to handle wrap around case
    if(y == arr[x].length - 1)
        return false;

    return findVertical(arr, x, y, counter);
}

现在是水平递归方法:

public static boolean findHorizontal(int[][] arr, int x, int y, int counter){
    //base case
    if(counter == 4)
        return true;

    if(arr[x][y] == 1)//consecutive 
        counter++
    else//not consecutive
        counter = 0;

    x++;

    //change this to handle wrap around case
    if(x == arr.length - 1)
        return false;

    return findHorizontal(arr, x, y, counter);
}

这两种递归方法看起来非常相似,但有明显的细微差别。

注意 1:我没有尝试过这段代码,但它非常接近可行(我认为......现在已经很晚了......)。

注意 2:这不处理环绕的情况,但调整这个伪代码以这种方式工作应该相对容易。

【讨论】:

  • 感谢您的帮助,我会尽力完成并在此处发布以供审核...谢谢
  • 嘿,我照你说的做了,但我的代码总是返回 false 任何输出需要一些帮助 public static boolean findVertical(int[][] arr, int x, int y, int counter) {//基本情况 if (counter == 4) {return true;}if (arr[x][y] == 1) {//连续 counter++;} else {//not Continuouscounter = 0;}y++;// 环绕caseif (y == arr.length - 1 || y == arr.length + 1) {int max_size = 4;if (y = max_size) {y = x % max_size;return findVertical(arr, x, y, counter);} } return false;}
  • @user3487291 将格式化代码添加到问题部分,以便于阅读。另外,请给我您尝试使用的示例输入。
  • 嘿,我已经用我的更改修改了问题部分
猜你喜欢
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 2015-11-07
  • 1970-01-01
  • 2021-08-17
  • 2019-07-12
  • 2017-10-04
相关资源
最近更新 更多