第一题
题型转化:可以转化为边权为一的最短路问题
将最开始的字符串定义为起点,我们将初识字符串每一个元素改变一次定义为移动一个位置,最后的字符串定义为中点,就这样每一次改变一个元素,最后成功改变成最终字符且改变的次数最少的次数就是我们需要的答案;
步骤一:
使用hash表来存放基因库中的字符串,方便我们在改变字符后检查改变后的字符串是否合理;
使用hash表2来存放我们已经改变过的字符串,这样方便我们检查我们的已经改变过的字符串变回原来的样子;
步骤二:
将我们需要改变成的元素放在数组中,这样方便后期改变元素;
步骤三:
我们改变后的字符串,判断条件(没有改变回之前的样子且满足基因库的条件),才可以存放进队列,进行以下一次的改变;
至此,代码如下:
class Solution { public int minMutation(String startGene, String endGene, String[] bank) { Set<String> vis = new HashSet<>();//用来标记已经搜索过的状态 Set<String> hash = new HashSet<>();//用来统计基因库里面的字符串 for(String s : bank){ hash.add(s); } char[] cha = {'A','C','G','T'}; if(startGene.equals(endGene)) return 0; if(!hash.contains(endGene)) return -1; Queue<String> q = new LinkedList<>(); q.add(startGene); vis.add(startGene); int step = 0; while(!q.isEmpty()){ step++; int size = q.size(); while(size-- != 0){ String t = q.poll(); for(int i = 0;i < 8 ;i++){ char[] tmp = t.toCharArray();//字符串变数组 for(int j = 0 ;j< 4 ;j++){ tmp[i] = cha[j]; String next = new String(tmp); if(hash.contains(next) && !vis.contains(next)) { if(next.equals(endGene)) return step; q.add(next); vis.add(next); } } } } } return -1; } }
第二题
本题分析如上题故事,代码如下:
class Solution { public int ladderLength(String beginWord, String endWord, List<String> wordList) { Set<String> hash = new HashSet<>(); Set<String> vis = new HashSet<>(); for(String s : wordList){ hash.add(s); } if(!hash.contains(endWord)) return 0; Queue<String> q = new LinkedList<>(); q.add(beginWord); vis.add(beginWord); int ret = 1; while(!q.isEmpty()){ ret ++; int size = q.size(); while(size-- != 0){ String t = q.poll(); for(int i = 0;i < t.length();i++){ char[] tmp = t.toCharArray(); for(char ch = 'a';ch <= 'z';ch++){ tmp[i] = ch; String next = new String(tmp); if(hash.contains(next) && !vis.contains(next)){ if(next.equals(endWord)) return ret; q.add(next); vis.add(next); } } } } } return 0; } }
第三题
如下图所示,为砍树的图,
按照题意的规则,就是从(0,0)坐标出发,先到2砍树,再到6、7、9、9、21依次砍树;并最后返回移动的最短次数;
步骤一:
首先我们遍历整个矩阵,将有树的位置都放入到一个队列中,并按照该位置中树的个数由小到大依次排序;
步骤二:
我们按照上述队列中位置的顺序,依次进行bfs移动,并记录每一个位置到下一个位置的移动次数,当所有的有效位置都便利完成时即砍完树了,最后返回总移动的步数;
至此,代码如下:
class Solution { int m,n; public int cutOffTree(List<List<Integer>> f) { m = f.size(); n = f.get(0).size(); //1、将所有的树放入到表中,并从小到大排序 List<int[]> trees = new ArrayList<>(); for(int i = 0; i<m; i++){ for(int j = 0; j< n ;j++){ if(f.get(i).get(j) > 1){ trees.add(new int[]{i,j}); } } } Collections.sort(trees,(a,b) -> { return f.get(a[0]).get(a[1]) - f.get(b[0]).get(b[1]); }); //2、按照顺序砍树 int ret = 0; int bx = 0,by = 0; for(int[] t : trees){ int x = t[0],y = t[1]; int step = bfs(f,bx,by,x,y); if(step == -1) return -1;//此时到不了下一个节点,即砍不了树 ret += step; bx = x;by = y; } return ret; } int[] dx = {0,0,1,-1}; int[] dy = {1,-1,0,0}; public int bfs (List<List<Integer>> f,int bx, int by, int ex, int ey){ if(bx == ex && by == ey) return 0; Queue<int[]> q = new LinkedList<>(); boolean[][] vis = new boolean[m][n]; q.add(new int[]{bx,by}); vis[bx][by] = true; int step = 0; while(!q.isEmpty()){ step ++; int sz = q.size(); while(sz-- != 0){ int[] t = q.poll(); int a = t[0],b = t[1]; for(int i = 0; i < 4;i++){ int x = a+dx[i],y = b+dy[i]; if(x >= 0 && y >=0 && y<n && x<m && f.get(x).get(y) != 0 && !vis[x][y]){ if(x == ex && y == ey) return step; q.add(new int[]{x,y}); vis[x][y] = true; } } } } return -1; } }
ps:本次的内容就到这里了,如果对你有所帮助的话就请一键三连哦!!!