【四重优化,速看】剑指 Offer 13. 机器人的运动范围
立志用最少的代碼做最高效的表達(dá)
題目
地上有一個(gè)m行n列的方格,從坐標(biāo) [0,0] 到坐標(biāo) [m-1,n-1] 。一個(gè)機(jī)器人從坐標(biāo) [0, 0] 的格子開(kāi)始移動(dòng),它每次可以向左、右、上、下移動(dòng)一格(不能移動(dòng)到方格外),也不能進(jìn)入行坐標(biāo)和列坐標(biāo)的數(shù)位之和大于k的格子。例如,當(dāng)k為18時(shí),機(jī)器人能夠進(jìn)入方格 [35, 37] ,因?yàn)?+5+3+7=18。但它不能進(jìn)入方格 [35, 38],因?yàn)?+5+3+8=19。請(qǐng)問(wèn)該機(jī)器人能夠到達(dá)多少個(gè)格子?
示例 1:
輸入:m = 2, n = 3, k = 1
輸出:3
示例 2:
輸入:m = 3, n = 1, k = 0
輸出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
文章目錄
- 題目
- 第一次解題
- 第二次解題
- 第三次優(yōu)化
- 第四次優(yōu)化
- 完整可運(yùn)行代碼
第一次解題
錯(cuò)誤解法:直接遍歷二維數(shù)組試圖解題,發(fā)現(xiàn)出錯(cuò),因?yàn)闄C(jī)器人無(wú)法越過(guò)障礙
class Solution {public int movingCount(int m, int n, int k) {int num1, num2, sum = 0;for(int i = 0; i < m; i++) {for(int j = 0; j < n; j++) {num1 = 0; num2 = 0;int ii = i, jj = j;while(ii != 0) { num1 += ii%10; ii/= 10; }while(jj != 0) { num2 += jj%10; jj/= 10; }if(num1 + num2 <= k) sum++;System.out.println(i + " " + j + " " + num1 + " " + num2 + " " + sum);}}return sum;} }第二次解題
仔細(xì)思考后發(fā)現(xiàn),這是一道考查連通塊的題,即連通(0,0)的點(diǎn)的個(gè)數(shù)。
于是用DFS解,如下:
第三次優(yōu)化
解法2中考慮了m或n是100的情況,但即使m or n為100,k最大值也只能取到20,因此不滿足條件。 因此只需考慮m or n是二位數(shù)的情況即可。
class Solution {boolean[][] vis;int sum;int kk; // 代替k,定義全局變量,可以為dfs方法減少一個(gè)參數(shù)int[][] next;int mm, nn;public int movingCount(int m, int n, int k) {// 全局變量的定義vis = new boolean[m][n];sum = 1; // (0,0)一定能被訪問(wèn)到kk = k; mm = m; nn = n;next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};vis[0][0] = true;dfs(0, 0);return sum;}public void dfs(int x, int y) {// 終止條件if(x > mm || y > nn) return;// 回溯for(int i = 0; i < 4; i++) {int xx = x + next[i][0], yy = y + next[i][1];// 1、是否超界 or 是否滿足條件, continueif(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;// 2、是否曾經(jīng)走過(guò)這個(gè)點(diǎn)if(!vis[xx][yy]) {vis[xx][yy] = true;sum++;dfs(xx, yy);}}} }第四次優(yōu)化
第三次優(yōu)化中,考慮的機(jī)器人從上下左右四個(gè)方向走的問(wèn)題,但仔細(xì)思考后發(fā)現(xiàn):
由于從0,0開(kāi)始,因此只考慮向右or向下走即可。
完整可運(yùn)行代碼
最后附上完整可運(yùn)行代碼
public class 劍指Offer13_機(jī)器人的運(yùn)動(dòng)范圍 {// 錯(cuò)誤解法: 因?yàn)闊o(wú)法越過(guò)障礙static class Solution_1 {public int movingCount(int m, int n, int k) {int num1, num2, sum = 0;for(int i = 0; i < m; i++) {for(int j = 0; j < n; j++) {num1 = 0; num2 = 0;int ii = i, jj = j;while(ii != 0) { num1 += ii%10; ii/= 10; }while(jj != 0) { num2 += jj%10; jj/= 10; }if(num1 + num2 <= k) sum++;System.out.println(i + " " + j + " " + num1 + " " + num2 + " " + sum);}}return sum;}}// 解法2:dfs:本質(zhì)上是求連通塊,就是連通(0,0)點(diǎn)的所有點(diǎn)的個(gè)數(shù)Sstatic class Solution_2 {boolean[][] vis;int sum;int kk; // 代替k,定義全局變量,可以為dfs方法減少一個(gè)參數(shù)int[][] next;int mm, nn;public int movingCount(int m, int n, int k) {// 全局變量的定義vis = new boolean[m][n];sum = 1; // (0,0)一定能被訪問(wèn)到kk = k; mm = m; nn = n;next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};vis[0][0] = true;dfs(0, 0);return sum;}public void dfs(int x, int y) {// 終止條件if(x > mm || y > nn) return;// 回溯for(int i = 0; i < 4; i++) {int xx = x + next[i][0], yy = y + next[i][1];// 1、超界, continueif(xx < 0 || xx >= mm || yy < 0 || yy >= nn) continue;// 2、被訪問(wèn)過(guò),continueif(vis[xx][yy]) continue;// 3、計(jì)算是否能到達(dá)int xx1 = xx, yy1 = yy;int num1 = 0, num2 = 0;while(xx1 != 0) { num1 += xx1%10; xx1 /= 10; }while(yy1 != 0) { num2 += yy1%10; yy1 /= 10; }if(num1 + num2 <= kk) { // 符合vis[xx][yy] = true;sum++;dfs(xx, yy);}}}}// 解法2中考慮的m或n是100的情況,但即使m or n為100,k最大值也只能取到20,因此不滿足條件。 因此只需考慮m or n是二位數(shù)的情況即可。static class Solution_3 {boolean[][] vis;int sum;int kk; // 代替k,定義全局變量,可以為dfs方法減少一個(gè)參數(shù)int[][] next;int mm, nn;public int movingCount(int m, int n, int k) {// 全局變量的定義vis = new boolean[m][n];sum = 1; // (0,0)一定能被訪問(wèn)到kk = k; mm = m; nn = n;next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};vis[0][0] = true;dfs(0, 0);return sum;}public void dfs(int x, int y) {// 終止條件if(x > mm || y > nn) return;// 回溯for(int i = 0; i < 4; i++) {int xx = x + next[i][0], yy = y + next[i][1];// 1、是否超界 or 是否滿足條件, continueif(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;// 2、是否曾經(jīng)走過(guò)這個(gè)點(diǎn)if(!vis[xx][yy]) {vis[xx][yy] = true;sum++;dfs(xx, yy);}}}}// 解法4:由于從0,0開(kāi)始,因此只考慮向右or向下走即可。static class Solution_4 {boolean[][] vis;int sum;int kk; // 代替k,定義全局變量,可以為dfs方法減少一個(gè)參數(shù)int[][] next;int mm, nn;public int movingCount(int m, int n, int k) {// 全局變量的定義vis = new boolean[m][n];sum = 1; // (0,0)一定能被訪問(wèn)到kk = k; mm = m; nn = n;next = new int[][]{{1,0}, {0,1}};vis[0][0] = true;dfs(0, 0);return sum;}public void dfs(int x, int y) {// 終止條件if(x > mm || y > nn) return;// 回溯for(int i = 0; i < 2; i++) {int xx = x + next[i][0], yy = y + next[i][1];// 1、是否超界 or 是否滿足條件, continueif(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;// 2、是否曾經(jīng)走過(guò)這個(gè)點(diǎn)if(!vis[xx][yy]) {vis[xx][yy] = true;sum++;dfs(xx, yy);}}}}public static void main(String[] args) {Solution_2 solution_2 = new Solution_2();System.out.println(solution_2.movingCount(16, 8, 4));} }總結(jié)
以上是生活随笔為你收集整理的【四重优化,速看】剑指 Offer 13. 机器人的运动范围的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【附可运行代码】剑指 Offer 12.
- 下一篇: 【速看,双100%】剑指 Offer 1