解题思路:
思路是维护两个坐标,分别为当前位置坐标和下一个目标位置坐标。假设下一个目标字符为c,则下一个目标位置坐标的横坐标为x = (c-‘a’) / 5, y = (c-‘a’) % 5;
有了上述两个坐标,我们就可以得到一个向量,从当前坐标指向目标坐标,且由题意可知,只有上下左右四个方向可以运动,因此最快的方式肯定是要么横向一直朝着左或右走,纵向一直朝着上或下走,同时横向移动和纵向移动的顺序可以随意。因此最短的移动方式有多重,这里我采用的是横着或纵着走到底。
本题还还有一个坑的地方,就是最后一个字符‘z’所处的位置,它是特殊的,除去它不看,正好是5 * 5 的方阵,加上它之后,假设target为‘zb’,那么按照上述的策略就会存在走出边界的情况,因此上述策略是不完善的,需要改善。
根据观察,我采取的解决办法是,算出上述向量的竖直方向上的分量,如果这个分量的方向是向上的,说明走向整体是向上的,当在除去‘z’的5 * 5方阵中移动时,上述策略不会有问题;当将‘z’考虑进来后,我是采用先在竖直方向上移动,然后再在水平方向上移动的策略来避免出界的。同理向竖直方向上的分量是向下的,说明走向整体是向下移动,当target为“z”,这种情况时,之前的策略会出界,我的改进策略是先让其横向移动,然后再纵向移动。
综上所述,我的改进思路就是根据情况改变先横走还是先纵走的顺序,因此代码上应该抽象出一个“移动”方法,该方法可以根据入参来判断是横走还是纵走。 具体代码如下:
class Solution {
public String alphabetBoardPath(String target) {
char[] tc = target.toCharArray();
StringBuilder sb = new StringBuilder();
int curX = 0, curY = 0;
for(int i = 0; i < tc.length; i++) {
int tarX = (tc[i]-'a') / 5, tarY = (tc[i] - 'a') % 5;
int distanceX = tarY - curY;
char c1 = distanceX>=0 ? 'R' : 'L';
int distanceY = tarX - curX;
char c2 = distanceY>=0 ? 'D' : 'U';
if(distanceY > 0) {
//当整体位移方向是向下时,采取先走横再走纵的策略来避免走出边界
go(sb, distanceX, c1);
go(sb, distanceY, c2);
}else {
//当整体位移方向是向上是,采取先走纵再走横的策略来避免走出边界
go(sb, distanceY, c2);
go(sb, distanceX, c1);
}
//到达目标位置
sb.append('!');
//更新当前坐标
curX = tarX; curY = tarY;
}
return sb.toString();
}
//移动方法
//distance: 移动距离
//c: 横移还是纵移
private void go(StringBuilder sb, int distance, char c) {
distance = distance<0 ? -distance : distance;
for(int j = 0; j < distance; j++) {
sb.append(c);
}
}
}