一.题目描述
NC518下象棋
牛妹在和牛牛下牛客象棋。现在轮到牛妹了,牛妹想知道她在这一回合能否战胜牛牛。
棋盘chessboard上只可能包含:炮,将,车,兵
牛客象棋的规则解释:
炮:炮在不吃子的时候,走动与车完全相同,但炮在吃棋子时,必须跳过一个棋子,我方的和敌方的都可以
兵:可以上下左右移动,每次只能移动一格
车:上下左右均可走,只要无棋子阻拦,步数不受限制。
将:可以上下左右移动,每次只能移动一格
接下来给出一个棋盘,牛妹的棋子用大写字母表示,牛牛的棋子用小写字母表示。
将用J,j表示,炮用P,p表示,车用C,c表示,兵用B,b表示,没有棋子的格子用.表示保证棋盘上一定同时包含J与j各一个。牛妹能胜利则返回"Happy",否则返回"Sad"
二.算法(模拟)
对于该题我们首先要明白题目是在着一回合下能否战胜牛牛,也就是牛妹能不能再这一回合将军(吃掉牛牛的将)。对于兵、车和将我们都能理解,但是这个炮我们需要注意一样,该题目是要求跳过一个棋子,并不是按照象棋规则那样。
对于上面牛妹战胜牛牛的几种情况,我们可以进行模拟。我们首先遍历找到牛牛的将的位置,然后反向推出是否可以满足上述的情况,进而判断是不是可以胜利,下面是完整代码:
class Solution { public: string playchess(vector<string>& chessboard) { //方向数组,上下左右四个方位 int dx[]={0,-1,1,0}; int dy[]={-1,0,0,1}; //n,m分别表示棋盘的长和宽 int n=chessboard.size(); int m=chessboard[0].size(); int x=0,y=0; for(int i=0;i<chessboard.size();i++){ for(int j=0;j<chessboard[0].size();j++){ if(chessboard[i][j]=='j'){ x=i; y=j; //(x,y)表示牛牛的将的位置 break; } } } for(int k=0;k<4;k++){ //对每一个相邻位置进行判断 int nx=x+dx[k]; int ny=y+dy[k]; bool ck=true;//判断当前位置是否和牛牛将相邻 int cnt=0;//和牛牛将中间隔了多少棋子 while(nx>=0&&nx<n&&ny>=0&&ny<m){ //旁边有牛妹的将或者是兵 牛妹就之间胜利 if((chessboard[nx][ny]=='B'||chessboard[nx][ny]=='J')&&ck){ return "Happy"; } if(chessboard[nx][ny]=='P'&&cnt==1) return "Happy"; if(chessboard[nx][ny]=='C'&&cnt==0) return "Happy"; //此时已经不是相邻位置了 所以ck=false ck=false; if(chessboard[nx][ny]!='.'){ cnt++; } if(cnt>1) break; //下一个位置进行搜索 nx+=dx[k]; ny+=dy[k]; } } return "Sad"; } };
时间复杂度:其中n,m分别表示棋盘的长和宽。
空间复杂度:没有使用其他额外空间
优缺点:思路简单,但是实现起来麻烦
三.算法(模拟+java实现)
首先找到牛牛的将在什么位置。分四种情况进行讨论,看牛牛是否能用兵、将、车、炮中得某一种赢得胜利,只要满足其中之一,就返回"Happy",否则返回"Sad"。
以牛牛将的位置为起点,沿着四个方向进行搜索,当与起点位置相邻
(1)当前位置是牛妹的兵时,说明牛妹可以赢,直接返回"Happy";
(2)当与起点位置相邻,并且当前位置是牛妹的将时,说明牛妹可以赢,直接返回"Happy";
(3)当与起点位置之间的棋子数为0个,并且当前位置是牛妹的车时,说明牛妹可以赢,直接返回"Happy";
(4)当与起点位置之间的棋子数只有一个,并且当前位置是牛妹的炮时,说明牛妹可以赢,直接返回"Happy"。
下面是完整代码:
import java.util.*; public class Solution { public String playchess (String[] chessboard) { int n = chessboard.length; int m = chessboard[0].length(); // 将String类转换为字符数组 方便处理 char[][] board = new char[n][m]; for (int i=0;i<n;i++){ board[i] = chessboard[i].toCharArray(); } // 当前位置的上下左右 int dx[]={-1,0,1,0}; int dy[]={0,1,0,-1}; for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++){ // 发现牛牛的将的位置 if (board[i][j] == 'j'){ // 判断牛牛将上下左右各方方向上的棋子,利用l更新牛牛将上(下左右)方第几个格子 for(int k=0;k<4;k++){ //对每一个相邻位置进行判断 int nx=i+dx[k]; int ny=j+dy[k]; boolean ck=true;//判断当前位置是否和牛牛将相邻 int cnt=0;//和牛牛将中间隔了多少棋子 while(nx>=0&&nx<n&&ny>=0&&ny<m){ //旁边有牛妹的将或者是兵 牛妹就之间胜利 if((board[nx][ny]=='B'||board[nx][ny]=='J')&&ck) return "Happy"; if(board[nx][ny]=='P'&&cnt==1) return "Happy"; if(board[nx][ny]=='C'&&cnt==0) return "Happy"; //此时已经不是相邻位置了 所以ck=false ck=false; if(board[nx][ny]!='.') cnt++; if(cnt>1) break; //下一个位置进行搜索 nx+=dx[k]; ny+=dy[k]; } } } } } return "Sad"; } }
时间复杂度:其中n,m分别表示棋盘的长和宽。
空间复杂度:没有使用其他额外空间
优缺点:思路和算法二思路差不多,但是感觉写起来相比于c++麻烦一点