题目描述
牛妹在和牛牛下牛客象棋。现在轮到牛妹了,牛妹想知道她在这一回合能否战胜牛牛。
棋盘chessboard上只可能包含:炮,将,车,兵
牛客象棋的规则解释:
炮:炮在不吃子的时候,走动与车完全相同,但炮在吃棋子时,必须跳过一个棋子,我方的和敌方的都可以
兵:可以上下左右移动,每次只能移动一格
车:上下左右均可走,只要无棋子阻拦,步数不受限制。
将:可以上下左右移动,每次只能移动一格
接下来给出一个棋盘,牛妹的棋子用大写字母表示,牛牛的棋子用小写字母表示。
将用J,jJ,j表示,炮用P,pP,p表示,车用C,cC,c表示,兵用B,bB,b表示,没有棋子的格子用..表示
保证棋盘上一定同时包含JJ与jj各一个。
牛妹能胜利则返回"Happy",否则返回"Sad"
方法一:暴力解法
求解思路
对于本题牛妹能否取得胜利,我们可以采用枚举的方法,将牛妹获胜的情况一一列举出来。我们首先找到牛牛的“将”在什么位置,然后我们分四种情况进行讨论,看牛牛是否能用兵,将,车,炮中的某一颗棋子赢得胜利。只要满足其中的一种,就返回“happy”,否则的话返回“sad”。
解题代码
import java.util.*; public class Solution { private char[][] chess; // 声明棋盘 private int x,y,m,n; public String playchess (String[] chessboard) { m=chessboard.length; // 棋盘的长和宽 n=chessboard[0].length(); //定义二维字符数组,存放棋子 chess=new char[m][n]; //初始化牛牛的将所在位置 x=0; y=0; //查找牛牛的将,并将所有棋子转移到chess数组 for(int i=0;i<m;i++) // 棋盘横轴竖轴循环,二层循环 { for(int j=0;j<n;j++) { chess[i][j]=chessboard[i].charAt(j); if(chess[i][j]=='j') { x=i; y=j; } } } return (winBySoldier()||winByGeneral()||winByCarriage()||winByGun())?"Happy":"Sad"; } private boolean winBySoldier() // 判断牛妹是否能用兵取得胜利 { boolean win=false; if(x>0&&chess[x-1][y]=='B') { win=true; } if(x<m-1&&chess[x+1][y]=='B') { win=true; } if(y>0&&chess[x][y-1]=='B') { win=true; } if(y<n-1&&chess[x][y+1]=='B') { win=true; } return win; } private boolean winByGeneral() // 判断牛妹是否能用将取得胜利 { boolean win=false; if(x>0&&chess[x-1][y]=='J') { win=true; } if(x<m-1&&chess[x+1][y]=='J') { win=true; } if(y>0&&chess[x][y-1]=='J') { win=true; } if(y<n-1&&chess[x][y+1]=='J') { win=true; } return win; } private boolean winByCarriage() // 判断牛妹是否能用车取得胜利 { boolean win=false; for(int i=0;i<m;i++) { //同一列上是否有车 if(chess[i][y]=='C') { boolean barrier=false; if(i>x) { for(int k=x+1;k<i;k++) { if(chess[k][y]!='.') { barrier=true; } } } else { for(int k=x-1;k>i;k--) { if(chess[k][y]!='.') { barrier=true; } } } //如果车和将之间没有其它棋子,牛妹胜利 if(!barrier) { win=true; } } } for(int j=0;j<n;j++) { //同一行上是否有车 if(chess[x][j]=='C') { boolean barrier=false; if(j>y) { for(int k=y+1;k<j;k++) { if(chess[x][k]!='.') { barrier=true; } } } else { for(int k=y-1;k>j;k--) { if(chess[x][k]!='.') { barrier=true; } } } if(!barrier) { win=true; } } } return win; } private boolean winByGun() // 判断牛妹是否能用炮取得胜利 { boolean win=false; for(int i=0;i<m;i++) { //同一列上是否有炮 if(chess[i][y]=='P') { int count=0; if(i>x) { for(int k=x+1;k<i;k++) { if(chess[k][y]!='.') { count++; } } } else { for(int k=x-1;k>i;k--) { if(chess[k][y]!='.') { count++; } } } if(count==1) { win=true; } } } for(int j=0;j<n;j++) { //同一行上是否有炮 if(chess[x][j]=='P') { int count=0; if(j>y) { for(int k=y+1;k<j;k++) { if(chess[x][k]!='.') { count++; } } } else{ for(int k=y-1;k>j;k--) { if(chess[x][k]!='.') { count++; } } } //如果炮和将之间仅有一个棋子,牛妹胜利 if(count==1) { win=true; } } } return win; } }
复杂度分析
时间复杂度:两层循环,因此时间复杂度为( )
空间复杂度:引入chess[n][n],使用额外的内存地址空间,因此空间复杂度为( )
方法二:模拟搜索的思想求解
求解思路
基于方法一,我们对解法进行优化。我们首先找到牛牛的“将”在什么位置,然后以牛牛的将为起点,沿着四个方向进行搜索,当与起点位置相邻,并且当前位置是牛妹的将或者兵时,说明牛妹可以赢,此时返回“happy”。当与起点位置之间的棋子数为0个,并且当前位置是牛妹的“车”时,说明牛妹可以赢,直接返回“happy”,同样当前位置是牛妹的“炮”时,也返回“happy”。最后如果没有找到赢的情况,则返回“sad”。
解题代码
import java.util.*; public class Solution { public String playchess (String[] chessboard) { int m=chessboard.length; // 棋盘的长和宽 int n=chessboard[0].length(); int[][] directions={{-1,0},{0,-1},{1,0},{0,1}}; // 定义搜索的方向 //记录牛牛的将所在位置 int x=0,y=0; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { //找到牛牛的将所在位置 if(chessboard[i].charAt(j)=='j') { x=i; // 更新横坐标 y=j; // 更新纵坐标 break; } } } //向左下右上四个方向搜索 for(int k=0;k<4;k++) { int nx=x+directions[k][0]; int ny=y+directions[k][1]; //是否与将相邻 boolean neighbor=true; //与将的中间隔了多少个棋子 int count=0; //保证位置在棋盘内 while(nx>=0&&nx<m&&ny>=0&&ny<n) { if(((chessboard[nx].charAt(ny)=='B'||chessboard[nx].charAt(ny)=='J')&&neighbor) ||((chessboard[nx].charAt(ny)=='P')&&count==1) ||((chessboard[nx].charAt(ny)=='C')&&count==0)) { return "Happy"; } neighbor=false; if(chessboard[nx].charAt(ny)!='.') { count++; } //如果障碍棋子超过2,直接终止搜索 if(count>1) { break; } //下一个位置 nx+=directions[k][0]; // 更新位置 ny+=directions[k][1]; // 更新位置 } } return "Sad"; } }
复杂度分析
时间复杂度:两层循环,因此时间复杂度为( )
空间复杂度:引入常数级别的数组,因此空间复杂度为