leetcode803. 打砖块

我们有一组包含1和0的网格;其中1表示砖块。 当且仅当一块砖直接连接到网格的顶部,或者它至少有一块相邻(4 个方向之一)砖块不会掉落时,它才不会落下。
我们会依次消除一些砖块。每当我们消除 (i, j) 位置时, 对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这个消除而落下。
返回一个数组表示每次消除操作对应落下的砖块数目。

示例 1:
输入:
grid = [[1,0,0,0],[1,1,1,0]]
hits = [[1,0]]
输出: [2]
解释:
如果我们消除(1, 0)位置的砖块, 在(1, 1) 和(1, 2) 的砖块会落下。所以我们应该返回2。

示例 2:
输入:
grid = [[1,0,0,0],[1,1,0,0]]
hits = [[1,1],[1,0]]
输出:[0,0]
解释:
当我们消除(1, 0)的砖块时,(1, 1)的砖块已经由于上一步消除而消失了。所以每次消除操作不会造成砖块落下。注意(1, 0)砖块不会记作落下的砖块。
注意:

网格的行数和列数的范围是[1, 200]。
消除的数字不会超过网格的区域。
可以保证每次的消除都不相同,并且位于网格的内部。
一个消除的位置可能没有砖块,如果这样的话,就不会有砖块落下。

解答:
正向思考:
每次敲之前,看看附近的格子是不是靠顶,如果靠顶就不掉落,掉落时候,进行统计数目。
耗时很长,有点惭愧

代码:

int[][] his;
int xLen;
int yLen;

public int[] hitBricks(int[][] grid, int[][] hits) {
    int[] ans = new int[hits.length];
    xLen = grid.length;
    yLen = grid[0].length;
    his = new int[xLen][yLen];
    for (int i = 0; i < hits.length; i++) {
        int x = hits[i][0];
        int y = hits[i][1];
        if (grid[x][y] == 0) {
            ans[i] = 0;
            continue;
        }
        grid[x][y] = 0;
        ans[i] += hit(x, y - 1, grid, i + 1);
        ans[i] += hit(x, y + 1, grid, i + 1);
        ans[i] += hit(x - 1, y, grid, i + 1);
        ans[i] += hit(x + 1, y, grid, i + 1);
    }
    return ans;
}

private int hit(int x, int y, int[][] grid, int hisV) {
    if (x < 0 || x >= xLen || y < 0 || y >= yLen) {
        return 0;
    }
    if (grid[x][y] == 0) {
        return 0;
    }
    boolean kq = getKq(x, y, grid, hisV);
    if (kq) {
        return 0;
    }
    return remove(x, y, grid);
}

private int remove(int x, int y, int[][] grid) {
    if (x < 0 || x >= xLen || y < 0 || y >= yLen) {
        return 0;
    }
    if (grid[x][y] == 0) {
        return 0;
    }
    grid[x][y] = 0;
    int ans = 1;
    ans += remove(x - 1, y, grid);
    ans += remove(x + 1, y, grid);
    ans += remove(x, y - 1, grid);
    ans += remove(x, y + 1, grid);
    return ans;
}

private boolean getKq(int x, int y, int[][] grid, int hisV) {
    if (x == xLen || y == yLen || y < 0) {
        return false;
    }
    if (grid[x][y] == 0) {
        return false;
    }
    if (x == 0) {
        return true;
    }
    if (his[x][y] == hisV) {
        return true;
    }
    if (his[x][y] == 0 - hisV) {
        return false;
    }
    //先装作不靠墙,防止重复
    his[x][y] = 0 - hisV;
    if (getKq(x - 1, y, grid, hisV)) {
        his[x][y] = hisV;
        return true;
    }
    if (getKq(x + 1, y, grid, hisV)) {
        his[x][y] = hisV;
        return true;
    }
    if (getKq(x, y - 1, grid, hisV)) {
        his[x][y] = hisV;
        return true;
    }
    if (getKq(x, y + 1, grid, hisV)) {
        his[x][y] = hisV;
        return true;
    }
    return false;
}

倒过来思考:
现在是敲完的状态,看看还有多少格子是保留的,进行标记。反过来把敲掉的格子粘回去,还可以附属粘多少。
代码:

public int[] hitBricks(int[][] grid, int[][] hits) {
    int[] ans = new int[hits.length];
    //把要敲掉的格子进行镂空
    for (int i = 0; i < hits.length; i++) {
        if (grid[hits[i][0]][hits[i][1]] == 1) {
            grid[hits[i][0]][hits[i][1]] = -1;
        }
    }
    for (int i = 0; i < grid[0].length; i++) {
        if (grid[0][i] == 1) {
            cleanToTwo(grid, 0, i);
        }
    }
    for (int i = hits.length - 1; i >= 0; i--) {
        //倒过来
        if (grid[hits[i][0]][hits[i][1]] == -1 && nearTwo(grid, hits[i][0], hits[i][1])) {
            ans[i] = cleanToTwo(grid, hits[i][0], hits[i][1]) - 1;
        }
    }
    return ans;
}

//判断是不是邻近2,如果不临近,只把自己刷回1
private boolean nearTwo(int[][] grid, int x, int y) {
    grid[x][y] = 1;
    if (x == 0) {
        return true;
    }
    if (x > 0 && grid[x - 1][y] == 2) {
        return true;
    }
    if (x < grid.length - 1 && grid[x + 1][y] == 2) {
        return true;
    }
    if (y > 0 && grid[x][y - 1] == 2) {
        return true;
    }
    if (y < grid[0].length - 1 && grid[x][y + 1] == 2) {
        return true;
    }
    return false;
}

//把靠顶的都刷成2
private int cleanToTwo(int[][] grid, int x, int y) {
    int ans = 1;
    grid[x][y] = 2;
    if (x > 0 && grid[x - 1][y] == 1) {
        ans += cleanToTwo(grid, x - 1, y);
    }
    if (x < grid.length - 1 && grid[x + 1][y] == 1) {
        ans += cleanToTwo(grid, x + 1, y);
    }
    if (y > 0 && grid[x][y - 1] == 1) {
        ans += cleanToTwo(grid, x, y - 1);
    }
    if (y < grid[0].length - 1 && grid[x][y + 1] == 1) {
        ans += cleanToTwo(grid, x, y + 1);
    }
    return ans;
}

}

你可能感兴趣的:(算法,leetcode)