☀️ 1.球会落何处
用一个大小为 m x n 的二维网格 grid 表示一个箱子。你有 n 颗球。箱子的顶部和底部都是开着的。
箱子中的每个单元格都有一个对角线挡板,跨过单元格的两个角,可以将球导向左侧或者右侧。
将球导向右侧的挡板跨过左上角和右下角,在网格中用 1 表示。
将球导向左侧的挡板跨过右上角和左下角,在网格中用 -1 表示。
在箱子每一列的顶端各放一颗球。每颗球都可能卡在箱子里或从底部掉出来。如果球恰好卡在两块挡板之间的 "V" 形图案,或者被一块挡导向到箱子的任意一侧边上,就会卡住。
返回一个大小为 n 的数组 answer ,其中 answer[i] 是球放在顶部的第 i 列后从底部掉出来的那一列对应的下标,如果球卡在盒子里,则返回 -1 。
题目链接:球会落何处https://leetcode-cn.com/problems/where-will-the-ball-fall/
题目分析:
这道题可能难度不难,但是对于新手却是一道非常好的用来练习模拟能力和分析题目能力的一道题。我们通过题目和图结合分析可以首先得到这些信息:
1.当球到达边界时,如果挡板然后指向墙壁,则球会被卡住。比如当纵坐标为0时,当球到达这且该处值为-1(说明挡板从跨过右上角和左上角)则会被卡住。同理纵坐标为n-1时该处值为1则会卡住。
2.这时考虑球不在边界的情况,当球处于的位置值(i,j)为1时,此时挡板从左上角指向右下角,小球受到重力因素只能往右移动。注意了,我们发现如果此时(i-1,j)为-1时,小球会被卡住,为1时小球则会顺利下落。同理(i,j)为-1时,我们要去考虑(i+1,j)的位置是否为-1,否则也会被卡住。
有了上面的思路我们可以实现以下代码:
class Solution { int m; int n; //记录答案 int[] arr; public int[] findBall(int[][] grid) { m=grid.length; n=grid[0].length; arr=new int[n]; //从下标为0列到n-1列 for(int i=0;i<n;i++){ check(i,grid); } return arr; } //j表示第几列 void check(int col,int[][] grid){ //记录k为小球的出发位置,也就是起始位置。 int k=col; //i为层数,当能走完这个循环,说明球顺利出来 for(int i=0;i<m;i++){ //考虑卡在左墙壁的情况 if(col==0&&grid[i][col]==-1){ arr[k]=-1; return; } //考虑卡在右墙壁的情况 if(col==n-1&&grid[i][col]==1){ arr[k]=-1; return; } //从左往右移动了一格 if(grid[i][col]==1&&grid[i][col]==grid[i][col+1]){ col++; continue; //从右往左移动了一格 }else if(grid[i][col]==-1&&grid[i][col]==grid[i][col-1]){ col--; continue; //从左往右边被卡住的情况 }else if(grid[i][col]==1&&grid[i][col]!=grid[i][col+1]){ arr[k]=-1; return; //从右往左卡住的情况 }else if(grid[i][col]==-1&&grid[i][col]!=grid[i][col-1]){ arr[k]=-1; return; } } //能顺利走出for循环,说明小球顺利出来,col的值就是它出来的位置 arr[k]=col; } }
相信加上注释大家能很容易看懂上面的代码,如果理解了题目的话可以再尝试看下面较为精简的代码(出自三叶姐)。
class Solution { int m, n; int[][] g; public int[] findBall(int[][] grid) { g = grid; m = g.length; n = g[0].length; int[] ans = new int[n]; for (int i = 0; i < n; i++) ans[i] = getVal(i); return ans; } int getVal(int x) { int r = 0, c = x; while (r < m) { int ne = c + g[r][c]; if (ne < 0 || ne >= n) return -1; if (g[r][c] != g[r][ne]) return -1; r++; c = ne; } return c; } }