目录

字谜游戏

我的第一版代码

我的第一版代码的结果:发现自己理解有问题

我的第二版代码

我的第三版代码

重看网友的代码

总结

我自己的数据结构和算法一向不好,就又捡起书本学习。

然后就看《数据结构与算法分析 Java语言描述(原书第3版)》一书,会做一些练习,以下就是其中之一。

字谜游戏

按照《数据结构与算法分析 Java语言描述(原书第3版)》一书所说,字谜游戏是这样的:

输入时由一些字母构成的一个二维数组以及一组单词组成。目标是找出字谜中的单词,这些单词可能是水平、垂直或沿对角线上任何方向放置的。作为例子,图1-1所示的字谜由单词this、two、fat和that组成。单词this从第一行第一列的位置即(1,1)处开始并延伸至(1,4);单词two从(1,1)dao (3,1);fat从(4,1)到(2,3);而that则从(4,4)到(1,1)。

我的第一版代码

第一版代码完全只是参考了了这个说明,实际上是有问题的。

问题就在:

  1. 我没有很好的理解它所说的对角线。我理解的对角线是整个表格的对角线,而不是某个字符的对角线。
  2. 因为没有理解好对角线问题,导致我认为二维数组的行数和列数必须是相等的。

所以,写的代码是有问题的。

先说一下第一版的算法思路:字谜板必须是二维的数组,数组的行高度等于每一行的列长度,比如数组是4*4的二维数组。

查找逐行正向查找此行是否出现这个完整单词、逐行反向查找此行是否出现这个完整单词、逐列正向查找此行是否出现这个完整单词、逐列反向查找此行是否出现这个完整单词、对角线正向查找此行是否出现这个完整单词、对角线反向查找此行是否出现这个完整单词。

package com.luoch.study.DataStructAndAlgorithmAnalysis.puzzleboard;/*** 字谜板* 字谜板必须是二维的数组,数组的行高度等于每一行的列长度,比如数组是4*4的二维数组。* 逐行正向查找、逐行反向查找、逐列正向查找、逐列反向查找、对角线正向查找、对角线反向查找。* 不管是正向查找还是反向查找,匹配的单词的首字符必须位于数组头或者数组尾。* @author luoch*/
public class PuzzleBoard {//字谜板二维数组private char[][] board = null;public PuzzleBoard(char[][] arrs) {this.board = arrs;}//找字谜public int[] find(String words) {if (words == null || words.isEmpty()) {return null;} char[] wc = words.toCharArray();if (wc.length>board.length) return null;int[] location = null;//行扫描【行数和列数相等】for (int i = 0; i < board.length; i++) {//行循环//1、逐行正向查找for (int j = 0; j < wc.length; j++) {//列循环
//              char c = board[i][j];//第i行第j列if (wc[j] != board[i][j]) {break;}if (j == wc.length-1) {location = new int[] {i,0,i,j};return location;}}//2、逐行反向查找for (int j = board.length - 1, k = 0; j >= 0 && k < wc.length ; j--,k++) {//列循环if (wc[k] != board[i][j]) {break;}if (k == wc.length-1) {location = new int[] {i,board.length-1,i,j};return location;}}}//列扫描行扫描【行数和列数相等】for (int i = 0; i < board.length; i++) {//列循环//3、逐列正向查找for (int j = 0; j < wc.length; j++) {//行循环
//              char c = board[j][i];//第j行第i列if (wc[j] != board[j][i]) {break;}if (j == wc.length-1) {location = new int[] {0,i,j,i};return location;}}//4、逐列反向查找for (int j = board.length - 1, k = 0; j >= 0 && k < wc.length ; j--,k++) {//列循环if (wc[k] != board[j][i]) {break;}if (k == wc.length-1) {location = new int[] {board.length-1,i,j,i};return location;}}}//对角线扫描【行数和列数相等】//5、对角线正向查找1for (int j = 0; j < wc.length; j++) {if (wc[j] != board[j][j]) {break;}if (j == wc.length-1) {location = new int[] {0,0,j,j};return location;}}//6、对角线反向查找1for (int j = board.length - 1, k = 0; j >= 0 && k < wc.length ; j--,k++) {if (wc[k] != board[j][j]) {break;}if (k == wc.length-1) {location = new int[] {board.length - 1,board.length - 1,j,j};return location;}}//7、对角线正向查找2for (int j=board.length - 1, k = 0; j>=0 && k < wc.length; j--, k++) {if (wc[k] != board[j][k]) {break;}if (k == wc.length-1) {location = new int[] {board.length - 1,0,j,k};return location;}}//8、对角线反向查找2for (int j=0, k = board.length - 1; j < wc.length && k >=0; j++, k--) {if (wc[j] != board[j][k]) {break;}if (j == wc.length-1) {location = new int[] {0,board.length - 1,j,k};return location;}}return location;}public static void printResult(String words, int[] loacation) {if (loacation == null)System.out.printf("can not find the words:%s\n", words);elseSystem.out.printf("start:(%d,%d), end:(%d,%d)\n", loacation[0]+1,loacation[1]+1, loacation[2]+1, loacation[3]+1);}public static void test1() {char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};PuzzleBoard board = new PuzzleBoard(arrs);String words = "this";int[] loacation = board.find(words);printResult(words, loacation);words = "oa";loacation = board.find(words);printResult(words, loacation);words = "fgdt";loacation = board.find(words);printResult(words, loacation);words = "fgdtff";loacation = board.find(words);printResult(words, loacation);words = "si";loacation = board.find(words);printResult(words, loacation);}/*** @param args*/public static void main(String[] args) {test1();}
}

我的第一版代码的结果:发现自己理解有问题

写完第一版代码后,我并没有发现我自己的理解有问题。不过,我打开了某位网友的文章:https://blog.csdn.net/weixin_42675298/article/details/105578768 。我发现它的代码和我的很不一样,不仅简短,而且起初我居然没看懂他为什么这么写,因为一些细节不明白。比如:1、第三个for的8次循环时干什么的?2、还有那个while循环。

我当时还是原谅了自己的菜。运行了他的程序,完全运行正确。“难道是对角线”理解的不对?”,我这样怀疑。

于是我运行这位网友的代码时,特意输入以字符对角线连成的单词,没想他程序找到了单词位置。

那看来的确是我想叉了:

  1. 书中的二维数组并非行数与列数相等。
  2. 对角线并非是行数与列数相等的二维矩阵的对角线,而是数组汇总某个字符的对角线。

我的第二版代码

第一版的算法思路有问题,那么之前的查找算法就不能用了。那就重新设计算法,以下第二版的算法:

既然是要按照字符对角线来查找,那么在循环遍历二维数组时,对于每一个目标字符,实际上就有8个方向可以查找:左、右、上、下、左上、左下、右上、右下。程序开始时取得单词的首字符,开始遍历二维数组,找到第一个与这个首字符相匹配的目标字符。找到目标字符后,按照这8个方向延伸出去,不断取的下一个目标字符与单词中的下一个字符匹配。(我现在开始有点理解那位网友为什么要写那个8次循环的for了,难道就是这样的算法?)

于是我又看了他的代码,虽然某些细节逻辑不是很懂。

看别人的代码如果看不懂,那就不如按照自己想的逻辑来写,只要确保自己的思路是对的,那便没问题。于是我按照我自己的思路又写了一个2.0版本的代码。如下:

package com.luoch.study.DataStructAndAlgorithmAnalysis.puzzleboard;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** 字谜板2.0* 字谜板必须是二维的数组,2.0不再要求是行数和列数相等。在字谜板1.0中的算法是:* 逐行正向查找、逐行反向查找、逐列正向查找、逐列反向查找、对角线正向查找、* 对角线反向查找。在2.0中废弃了1.0的算法,2.0的算法为:从第0行第0列开始遍历* 二维数组,遇到与单词首字母相等的字符时,则要向这个字符所在矩阵的8个方向(左、* 右、上、下、左上、左上、右上、右下)逐个方向遍历,判断下一个字符是否匹配。* 如某一方向的字符匹配,则在此方向继续匹配,直到匹配结束(整个单词完全匹配* 或单词未匹配完但遇到了不匹配的字符);否则回到与单词首字符匹配的字符位置,* 接着检查下一个字符是否与单词首字符匹配。如此重复上述过程,直到这个二维数组* 遍历完。* 如下的二维数组,要在其中查找abc这个单词:* xxxxxxxxxxxxxxxx* xxxxcxcxcxxxxxxx* xxxxxbbbxxxxxxxx* xxxxcbabcxxxxxxx* xxxxxbbbxxxxxxxx* xxxxcxcxcxxxxxxx* xxxxxxxxxxxxxxxx* xxxxxxxxxxxxxxxx* 那么,就先遍历这个数组,直到在第4行第7列遇到了字符'a'。接下来,就是如之前* 的描述,先检查本行的前一列的字符是否与单词中的'b'匹配,接着再检查再前面的* 字符是否与'c'匹配。显然,这个找到了匹配的结果,将结果记下。回到字符'a',接着* 检查本行的后一列的字符是否与'b'匹配。8个方向都检查完毕后,接着遍历数组,看* 下一字符是否与'a'匹配,重复之前的操作。* 参照了https://blog.csdn.net/weixin_42675298/article/details/105578768* 的程序,但源程序的结构我能看懂,但一些细节我看不懂,于是我按照我自己的思路* 来写这个程序。* @author luoch*/
public class PuzzleBoard2 {//字谜板二维数组private char[][] board = null;/*** 存放查找结果的map,key是一个单词,值是这个单词出现* 位置的list。每个list元素存放一个int数组,这个int数组* 存放key这个单词对应的字符出现的开始和结束坐标,所以每* 个int数组的长度都是4。*/private Map<String, List<int[]>> result= new HashMap<String, List<int[]>>();public PuzzleBoard2(char[][] arrs) {this.board = arrs;}/*** 找字谜* @param words 要找的单词* @return 如果为true,则说明在字谜板中找到了单词;否则,未找到。*/public boolean find(String words) {if (words == null || words.isEmpty()) {return false;}boolean get = false;//单词转数组char[] w = words.toCharArray();/*单词字符数组长度*/int wlength = w.length;/*单词位置,长度为4:[0-头字符所在行][1-头字符所在列][2-尾字符所在行][3-尾字符所在列]*/int[] location = null;for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[i].length; j++) {//单词首字符与目标字符相等if (board[i][j] == w[0]) {//0、单词长度为1时,记录,接着遍历数组。if (wlength == 1) {location = new int[] {i,j,i,j};record(words, location);get |= true;continue;}//1、往左遍历查找/*单词字符索引*/int idx = 0;location = new int[] {i,j,0,0};/*临时变量,目标字符列索引*/int temp_y = j;//【在本行中,目标字符的前面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && idx < wlength-1) {--temp_y;++idx;//出现不匹配,直接跳出if (board[i][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[i][temp_y] == w[idx] && idx == wlength-1) {location[2] = i;location[3] = temp_y;record(words, location);get = true;break;}}//2、往右遍历查找idx = 0;location = new int[] {i,j,0,0};temp_y = j;//【在本行中,目标字符的后面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && idx < wlength-1) {++temp_y;++idx;//出现不匹配,直接跳出if (board[i][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[i][temp_y] == w[idx] && idx == wlength-1) {location[2] = i;location[3] = temp_y;record(words, location);get = true;break;}}//3、往上遍历查找idx = 0;location = new int[] {i,j,0,0};/*临时变量,目标字符行索引*/int temp_x = i;//【在本列中,目标字符的上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_x > 0 && idx < wlength-1) {--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][j] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][j] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = j;record(words, location);get = true;break;}}//4、往下遍历查找idx = 0;location = new int[] {i,j,0,0};temp_x = i;//【在本列中,目标字符的下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_x < board.length-1 && idx < wlength-1) {++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][j] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][j] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = j;record(words, location);get = true;break;}}//5、往左上遍历查找idx = 0;location = new int[] {i,j,0,0};temp_x = i;temp_y = j;//【在本列中,目标字符的左上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && temp_x > 0 && idx < wlength-1) {--temp_y;--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}//6、往左下遍历查找idx = 0;location = new int[] {i,j,0,0};temp_x = i;temp_y = j;//【在本列中,目标字符的左下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && temp_x < board.length-1 && idx < wlength-1) {--temp_y;++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}//7、往右上遍历查找idx = 0;location = new int[] {i,j,0,0};temp_x = i;temp_y = j;//【在本列中,目标字符的右上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && temp_x > 0 && idx < wlength-1) {++temp_y;--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}//8、往右下遍历查找idx = 0;location = new int[] {i,j,0,0};temp_x = i;temp_y = j;//【在本列中,目标字符的右下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && temp_x < board.length-1 && idx < wlength-1) {++temp_y;++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}}}}return get;}/*** @param args*/public static void main(String[] args) {
//      test1();
//      test2();char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};String[] words = new String[] {"this","oa","a", "h", "that","two","fat"};test3(arrs, words);}private void printResult() {if (!result.isEmpty()) {Set<String> set = result.keySet();Iterator<String> iter = set.iterator();while(iter.hasNext()) {String key = iter.next();List<int[]> list = result.get(key);for (int[] location : list) {System.out.printf("%s start:(%d,%d), end:(%d,%d)\n", key,location[0]+1,location[1]+1, location[2]+1, location[3]+1);}}}}private void printResult(String words) {if (!result.isEmpty()) {List<int[]> list = result.get(words);for (int[] location : list) {System.out.printf("%s start:(%d,%d), end:(%d,%d)\n", words, location[0]+1,location[1]+1, location[2]+1, location[3]+1);}}}private void record(String words, int[] location) {if (result.containsKey(words)) {List<int[]> value = result.get(words);if (!lookup(value, location)) {value.add(location);}} else {List<int[]> value = new ArrayList<>();value.add(location);result.put(words, value);}}private boolean lookup(List<int[]> list, int[] a) {for (int i = 0; i < list.size(); i++) {int[] e = list.get(i);if (e[0] == a[0]&& e[1] == a[1]    && e[2] == a[2]   && e[3] == a[3]) {return true;}}return false;}private static void test1() {char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};PuzzleBoard2 board = new PuzzleBoard2(arrs);board.find("this");board.find("fgdt");boolean flag = board.find("fgdtff");board.find("si");board.find("ah");board.find("ts");board.find("dhti");board.find("fo");board.find("ha");board.find("ag");board.find("two");board.find("twof");board.find("tdgf");board.find("o");board.find("ao");board.find("iao");board.find("staf");board.find("hw");board.find("gd");board.find("ha");board.find("that");board.find("at");board.find("th");board.find("h");board.find("a");board.find("a");board.find("oa");board.find("ghao");board.find("abc");board.find("haag");board.find("two");board.find("dhti");board.find("tah");board.find("tha");board.find("fat");board.find("staf");board.find("gh");board.find("ghs");board.find("taht");board.printResult();}private static void test2() {char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};PuzzleBoard2 board = new PuzzleBoard2(arrs);String words = "this";board.find(words);boolean flag = board.find("oa");if (flag) {board.printResult("oa");}board.printResult();}private static void test3(char[][] arrs, String[] words) {PuzzleBoard2 board = new PuzzleBoard2(arrs);for (int i = 0; i < words.length; i++) {String word = words[i];board.find(word);}board.printResult();}}

“居然写了这么长的代码,还是技不如人呐。”别人几十行就搞定的事情我写了这么多。但这个代码的确是满足要求的,只是方find方法长了一点。代码多了一代。

我的第三版代码

第三版代码,我没有对算法逻辑做修改,只是将find方法做了拆分。如下:

package com.luoch.study.DataStructAndAlgorithmAnalysis.puzzleboard;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** 字谜板2.0* 字谜板必须是二维的数组,2.0不再要求是行数和列数相等。在字谜板1.0中的算法是:* 逐行正向查找、逐行反向查找、逐列正向查找、逐列反向查找、对角线正向查找、* 对角线反向查找。在2.0中废弃了1.0的算法,2.0的算法为:从第0行第0列开始遍历* 二维数组,遇到与单词首字母相等的字符时,则要向这个字符所在矩阵的8个方向(左、* 右、上、下、左上、左上、右上、右下)逐个方向遍历,判断下一个字符是否匹配。* 如某一方向的字符匹配,则在此方向继续匹配,直到匹配结束(整个单词完全匹配* 或单词未匹配完但遇到了不匹配的字符);否则回到与单词首字符匹配的字符位置,* 接着检查下一个字符是否与单词首字符匹配。如此重复上述过程,直到这个二维数组* 遍历完。* 如下的二维数组,要在其中查找abc这个单词:* xxxxxxxxxxxxxxxx* xxxxcxcxcxxxxxxx* xxxxxbbbxxxxxxxx* xxxxcbabcxxxxxxx* xxxxxbbbxxxxxxxx* xxxxcxcxcxxxxxxx* xxxxxxxxxxxxxxxx* xxxxxxxxxxxxxxxx* 那么,就先遍历这个数组,直到在第4行第7列遇到了字符'a'。接下来,就是如之前* 的描述,先检查本行的前一列的字符是否与单词中的'b'匹配,接着再检查再前面的* 字符是否与'c'匹配。显然,这个找到了匹配的结果,将结果记下。回到字符'a',接着* 检查本行的后一列的字符是否与'b'匹配。8个方向都检查完毕后,接着遍历数组,看* 下一字符是否与'a'匹配,重复之前的操作。* 参照了https://blog.csdn.net/weixin_42675298/article/details/105578768* 的程序,但源程序的结构我能看懂,但一些细节我看不懂,于是我按照我自己的思路* 来写这个程序。* @author luoch*/
public class PuzzleBoard3 {//字谜板二维数组private char[][] board = null;/*** 存放查找结果的map,key是一个单词,值是这个单词出现* 位置的list。每个list元素存放一个int数组,这个int数组* 存放key这个单词对应的字符出现的开始和结束坐标,所以每* 个int数组的长度都是4。*/private Map<String, List<int[]>> result= new HashMap<String, List<int[]>>();public PuzzleBoard3(char[][] arrs) {this.board = arrs;}//找字谜public boolean find(String words) {if (words == null || words.isEmpty()) {return false;}boolean get = false;//单词转数组char[] w = words.toCharArray();/*单词字符数组长度*/int wlength = w.length;/*单词位置,长度为4:[0-头字符所在行][1-头字符所在列][2-尾字符所在行][3-尾字符所在列]*/int[] location = null;for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[i].length; j++) {//单词首字符与目标字符相等if (board[i][j] == w[0]) {//0、单词长度为1时,记录,接着遍历数组。if (wlength == 1) {location = new int[] {i,j,i,j};record(words, location);get |= true;continue;}//1、往左遍历查找get |= lookupLeft(i, j, wlength, words, w);//2、往右遍历查找get |= lookupRight(i, j, wlength, words, w);//3、往上遍历查找get |= lookupUp(i, j, wlength, words, w);//4、往下遍历查找get |= lookupDown(i, j, wlength, words, w);//5、往左上遍历查找get |= lookupLeftUp(i, j, wlength, words, w);//6、往左下遍历查找get |= lookupLeftDown(i, j, wlength, words, w);//7、往右上遍历查找get |= lookupRightUp(i, j, wlength, words, w);//8、往右下遍历查找get |= lookupRightDown(i, j, wlength, words, w);}}}return get;}/*** @param args*/public static void main(String[] args) {
//      test1();
//      test2();char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};String[] words = new String[] {"this","oa","a", "h", "that","two","fat"};test3(arrs, words);}/*** 在当前行往左遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupLeft(int i, int j, int wlength, String words, char[] w) {/*单词字符索引*/int idx = 0;int[] location = new int[] {i,j,0,0};/*临时变量,目标字符列索引*/int temp_y = j;boolean get = false;//【在本行中,目标字符的前面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && idx < wlength-1) {--temp_y;++idx;//出现不匹配,直接跳出if (board[i][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[i][temp_y] == w[idx] && idx == wlength-1) {location[2] = i;location[3] = temp_y;record(words, location);get = true;break;}}return get;}/*** 在当前行往右遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupRight(int i, int j, int wlength, String words, char[] w) {/*单词字符索引*/int idx = 0;int[] location = new int[] {i,j,0,0};/*临时变量,目标字符列索引*/int temp_y = j;boolean get = false;//【在本行中,目标字符的后面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && idx < wlength-1) {++temp_y;++idx;//出现不匹配,直接跳出if (board[i][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[i][temp_y] == w[idx] && idx == wlength-1) {location[2] = i;location[3] = temp_y;record(words, location);get = true;break;}}return get;}/*** 在当前列往上遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupUp(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};/*临时变量,目标字符行索引*/int temp_x = i;boolean get = false;//【在本列中,目标字符的上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_x > 0 && idx < wlength-1) {--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][j] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][j] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = j;record(words, location);get = true;break;}}return get;}/*** 在当前列往下遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupDown(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};int temp_x = i;boolean get = false;//【在本列中,目标字符的下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_x < board.length-1 && idx < wlength-1) {++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][j] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][j] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = j;record(words, location);get = true;break;}}return get;}/*** 在当前列往左上遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupLeftUp(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};int temp_x = i;int temp_y = j;boolean get = false;//【在本列中,目标字符的左上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && temp_x > 0 && idx < wlength-1) {--temp_y;--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}return get;}/*** 在当前列往左下遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupLeftDown(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};int temp_x = i;int temp_y = j;boolean get = false;//【在本列中,目标字符的左下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y > 0 && temp_x < board.length-1 && idx < wlength-1) {--temp_y;++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}return get;}/*** 在当前列往右上遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupRightUp(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};int temp_x = i;int temp_y = j;boolean get = false;//【在本列中,目标字符的右上面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && temp_x > 0 && idx < wlength-1) {++temp_y;--temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}return get;}/*** 在当前列往右下遍历查找* @param i 目标字符所在当前行索引* @param j 目标字符所在当前列索引* @param wlength 单词长度* @param words 单词* @param w 单词数组* @return 是否找到的标识,找到为true,未找到为false*/private boolean lookupRightDown(int i, int j, int wlength, String words, char[] w) {int idx = 0;int[] location = new int[] {i,j,0,0};int temp_x = i;int temp_y = j;boolean get = false;//【在本列中,目标字符的右下面还有字符】 并且 【单词中当前字符不是单词的结束字符】while (temp_y < board[i].length-1 && temp_x < board.length-1 && idx < wlength-1) {++temp_y;++temp_x;++idx;//出现不匹配,直接跳出if (board[temp_x][temp_y] != w[idx]) {break;}//单词的最后一个字符if (board[temp_x][temp_y] == w[idx] && idx == wlength-1) {location[2] = temp_x;location[3] = temp_y;record(words, location);get = true;break;}}return get;}private void printResult() {if (!result.isEmpty()) {Set<String> set = result.keySet();Iterator<String> iter = set.iterator();while(iter.hasNext()) {String key = iter.next();List<int[]> list = result.get(key);for (int[] location : list) {System.out.printf("%s start:(%d,%d), end:(%d,%d)\n", key,location[0]+1,location[1]+1, location[2]+1, location[3]+1);}}}}private void printResult(String words) {if (!result.isEmpty()) {List<int[]> list = result.get(words);for (int[] location : list) {System.out.printf("%s start:(%d,%d), end:(%d,%d)\n", words, location[0]+1,location[1]+1, location[2]+1, location[3]+1);}}}private void record(String words, int[] location) {if (result.containsKey(words)) {List<int[]> value = result.get(words);if (!lookup(value, location)) {value.add(location);}} else {List<int[]> value = new ArrayList<>();value.add(location);result.put(words, value);}}private boolean lookup(List<int[]> list, int[] a) {for (int i = 0; i < list.size(); i++) {int[] e = list.get(i);if (e[0] == a[0]&& e[1] == a[1]   && e[2] == a[2]   && e[3] == a[3]) {return true;}}return false;}private static void test1() {char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};PuzzleBoard3 board = new PuzzleBoard3(arrs);board.find("this");board.find("fgdt");boolean flag = board.find("fgdtff");board.find("si");board.find("ah");board.find("ts");board.find("dhti");board.find("fo");board.find("ha");board.find("ag");board.find("two");board.find("twof");board.find("tdgf");board.find("o");board.find("ao");board.find("iao");board.find("staf");board.find("hw");board.find("gd");board.find("ha");board.find("that");board.find("at");board.find("th");board.find("h");board.find("a");board.find("a");board.find("oa");board.find("ghao");board.find("abc");board.find("haag");board.find("two");board.find("dhti");board.find("tah");board.find("tha");board.find("fat");board.find("staf");board.find("gh");board.find("ghs");board.find("taht");board.printResult();}private static void test2() {char[][] arrs = new char[][] {{'t','h','i','s'},{'w','a','t','s'},{'o','a','h','g'},{'f','g','d','t'}};PuzzleBoard3 board = new PuzzleBoard3(arrs);String words = "this";board.find(words);boolean flag = board.find("oa");if (flag) {board.printResult("oa");}board.printResult();}private static void test3(char[][] arrs, String[] words) {PuzzleBoard3 board = new PuzzleBoard3(arrs);for (int i = 0; i < words.length; i++) {String word = words[i];board.find(word);}board.printResult();}
}

重看网友的代码

在改完第三版代码,我又重回去看了网友的代码,再结合自己的思路,终于明白之前不理解的地方了。以下是他的代码。

//来自https://blog.csdn.net/weixin_42675298/article/details/105578768
class Riddle {public static final String[] WORDS = {"this", "two", "fat", "that"};public static final char[][] CONST = {{'t', 'h', 'i', 's'}, {'w', 'a', 't', 's'}, {'o', 'a', 'h', 'g'}, {'f', 'g', 'd', 't'}};public static void main(String[] args) {findWords(CONST, WORDS);}public static void findWords(char[][] arr, String[] words) {
//        记录首字母,不重复StringBuilder initials = new StringBuilder();for (String word : words) {String initial = word.substring(0, 1);if (!initials.toString().contains(initial)) {initials.append(initial);}}
//        遍历每个元素是否是首字母for (int x = 0; x < arr.length; x++) {for (int y = 0; y < arr[x].length; y++) {if (initials.toString().contains(String.valueOf(arr[x][y]))) {for (int p = 1; p <= 8; p++) {String tem = "";int xEnd = x, yEnd = y;while (xyAva(arr, xEnd, yEnd)) {tem += arr[xEnd][yEnd];printWord(tem, x, y, xEnd, yEnd);if (p == 1) {xEnd--;}if (p == 2) {xEnd++;}if (p == 3) {yEnd++;}if (p == 4) {yEnd--;}if (p == 5) {xEnd--;yEnd++;}if (p == 6) {xEnd++;yEnd--;}if (p == 7) {xEnd++;yEnd++;}if (p == 8) {xEnd--;yEnd--;}}}}}}}public static boolean xyAva(char[][] arr, int x, int y) {if (0 <= x && x < arr.length) {return 0 <= y && y < arr[x].length;}return false;}/***     判断是否是给定的单词并打印*/public static void printWord(String word, int x, int y, int xEnd, int yEnd) {for (String s : WORDS) {if (word.equals(s)) {System.out.println("单词:"+ s + "\t向量:" + "(" + (x + 1) + "," + (y + 1) + ")->(" + (xEnd + 1) + "," + (yEnd + 1) + ")");}}}
}

他的实现算法基本和我想的一致。但个别地方实现有差异。

比如:

1、虽然是按照当前字符的8个方向去判断下一个目标字符是否匹配,但他的while循环就写得比我的精简。(算因为我个人原因我期初是没看懂的)

2、在它的while循环中,有两行代码:【tem += arr[xEnd][yEnd];printWord(tem, x, y, xEnd, yEnd);】这两行的代码的逻辑是:将之前数组中匹配的目标字符存放到tem变量中,然后再取数组中的下一个目标字符与之前的tem拼接。拼接后的新term,会拿来和输入的单词集合做比对,判断这个tem是否与集合中的某个单词匹配。而我的是怎么写的呢,将单词拆分成字符数组,这个字符数组将字符数组中的字符取出与二维数组中的目标字符逐个做判断是否匹配。

3、网友的二维数组的边界判断写在了xyAva(char[][] arr, int x, int y)方法中,而我的则是分情况分散在8个地方。

当然还有其他地方差异,比如我的是逐个取单词取比对,而他的这是取所有单词的首字母去比对。

总结

这个字谜的Java代码虽然写3版,但和其他网友还是有差距的,继续努力吧。

字谜游戏Java程序实现相关推荐

  1. Java游戏里面的星球大战_星球大战手机游戏-JAVA程序算法

    内容简介: 毕业设计 星球大战手机游戏-JAVA程序算法,共18页,9196字 摘 要 近年来,随着各种不同设备,尤其是移动通信设备的飞速发展诞生了一项新的开发技术-J2ME.它定位在消费性电子产品的 ...

  2. quicktype游戏java程序_使用QuickType工具从json自动生成类型声明代码

    一.QuickType 工具功能简介 QuickType 是一款可以根据 json 文本生成指定语言(如 Type Script,C++,,Java,C#,Go 等)类型声明代码的工具. 例如我们在写 ...

  3. java图形界面猜字游戏,java程序,猜字游戏,希望大神帮忙

    package com.may.eighteen; import java.util.Random; import java.util.Scanner; public class WeekDemo1  ...

  4. Java黑皮书课后题第5章:**5.34(游戏:石头、剪刀、布)编程练习题3.17给出玩石头-剪刀-布游戏的程序。修改这个程序,让用户可以连续玩这个游戏,直到用户或者计算机赢对手两次以上为止

    5.34(游戏:石头.剪刀.布)编程练习题3.17给出玩石头-剪刀-布游戏的程序.修改这个程序,让用户可以连续玩这个游戏,直到用户或者计算机赢对手两次以上为止 题目 题目概述 编程练习题3.17 破题 ...

  5. Java黑皮书课后题第3章:*3.17(游戏:剪刀、石头、布)编写可以玩流行的剪刀-石头-布游戏的程序

    *3.17(游戏:剪刀.石头.布)编写可以玩流行的剪刀-石头-布游戏的程序 题目 题目概述 运行示例 ***特别注意*** 破题 代码 题目 题目概述 *3.17(游戏:剪刀.石头.布)编写可以玩流行 ...

  6. 不会玩游戏的程序员不是好作家,《深入理解Java虚拟机》周志明来了!

    嘉宾:周志明.杨福川 采访.撰文:Satoh_AI 这次采访起源来自于我和豆瓣的一位读者有同样的好奇心,为什么网上搜不到周志明老师的更多信息?为什么"80后玩家"可以把本本书都维持 ...

  7. java打字小游戏_java实现打字游戏小程序

    本文实例为大家分享了java实现打字游戏小程序的具体代码,供大家参考,具体内容如下 一.设计思路 1.创建一个窗体 2.在窗体上放置一个面板,用paint方法画出英文字母,随机放置字母位置,并随时间自 ...

  8. 猜数字java程序设计分析_JAVA程序设计课程设计-猜数字游戏设计

    JAVA程序设计课程设计-猜数字游戏设计 课 程 设 计 报 告课程设计名称 Java 程序设计 专 业 计算机科学与技术 班 级 2 班 学 号 08030212 姓 名 指导教师 成 绩 2011 ...

  9. JAVA程序连连看的项目总结,JAVA课程设计连连看游戏的开发

    JAVA课程设计连连看游戏的开发 计算机科学与工程学院集中性实践教学计划书( 2013 - 2014 学年第 1 学期)课程名称: 专业实习 姓 名: 学 号: 2010081303 专 业: 计算机 ...

  10. 打地鼠java代码流程图_51单片机 普中51 打地鼠游戏 仿真 程序 流程图

    51单片机 普中51 打地鼠游戏 仿真 程序 流程图 51单片机 普中51 打地鼠游戏 仿真 程序 流程图 普中51-单核-A3&A4开发板原理图 用到数码管.LED.矩阵按键 描述: (1) ...

最新文章

  1. linux镜像修改密码,OpenStack 镜像修改密码方案
  2. 网易开源支持图像识别的自动化UI测试工具,零基础亲测好评!
  3. 管理表空间和数据文件——使用OMF方式管理表空间
  4. cisco 路由器访问权限的设置
  5. Xenix 操作系统的简史
  6. 这就是数据分析之数据集成
  7. scipy.sparse.csr_matrix函数和coo_matrix函数
  8. web测试内容及工具经典总结
  9. 汉字转拼音(较完整)
  10. mac m1 安装svn/subversion
  11. Ipsec phase1 and phase2
  12. 诗字辈大全:诗仙、诗圣、诗魔、诗佛、诗神、诗鬼、诗杰、诗狂、诗骨、诗家夫子、诗豪、诗囚、诗奴...
  13. 安徽省2016“京胜杯”程序设计大赛_C_箭无虚发
  14. 计算智能——K-均值算法
  15. HTML5触摸事件(多点、单点触控)
  16. LTE 随机接入 --(1)流程
  17. 【Oracle】 ORA-00257: archiver error. Connect internal only, until freed
  18. 人工智能本科学位的完整4年课程规划
  19. 埙曲推荐,《葬花吟》简谱
  20. 全国专业技术人员计算机应用能力考试广东,广东省人事厅关于全国专业技术人员计算机应用能力考试扩充科目(模块)有关问题的通知...

热门文章

  1. 如何看计算机系统是x86,怎么看电脑是x86还是x64 x64和x86有区别讲解分享
  2. 零基础学前端难吗?前端好学吗?
  3. linux下安装配置dble--新手入门
  4. 万娟 白话大数据和机械学习_白话大数据与机器学习 (高扬著) 带书签目录 完整pdf扫描版[71MB]...
  5. ThinkPHP 提示验证码输入错误
  6. AdaBoost 人脸检测介绍(5) : AdaBoost算法的误差界限
  7. word 参考文献插入整理
  8. axios系列之发送请求时 headers 携带数据的方式
  9. linux读取ads1115ADC例程
  10. 制作字幕.html教程,如何制作电影字幕,视频字幕制作软件|免费给视频加字幕