[leetcode刷题]——搜索
此博客主要记录力扣中关于搜索的题解,包括 BFS、DFS、Backtracking
BFS
一、计算在网格中从原点到特定点的最短路径长度
1091. 二进制矩阵中的最短路径 (medium) 2021-07-12
给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。
二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:
路径途经的所有单元格都的值都是 0 。
路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
畅通路径的长度 是该路径途经的单元格总数。
经典BFS 题目。
class Solution { public int shortestPathBinaryMatrix(int[][] grid) { if(grid == null || grid.length == 0 || grid[0].length == 0){ return -1; } if(grid[0][0] == 1) return -1; int[][] dir = {{1,1}, {1, 0}, {1, -1}, {0, 1}, {0, -1}, {-1, 1}, {-1, 0}, {-1, -1}}; int m = grid.length; int n = grid[0].length; Queue<int[]> queue = new LinkedList<>(); queue.add(new int[]{0, 0}); grid[0][0] = 1; //遍历一个节点就置 1 ,记为堵塞 int path = 1; //第一层 while(!queue.isEmpty()){ int size = queue.size(); while(size > 0){ int[] cur = queue.poll(); int x = cur[0]; int y = cur[1]; //结束遍历,返回层数 if(x == m - 1 && y == n - 1){ return path; } for(int[] d : dir){ int x1 = x + d[0]; int y1 = y + d[1]; if(x1 < 0 || x1 >= m || y1 >= m || y1 < 0 || grid[x1][y1] == 1){ continue; } queue.add(new int[]{x1, y1}); grid[x1][y1] = 1; } size--; } path++; } return -1; } }
二、组成整数的最小平方数数量
279. 完全平方数 (medium) 2021-07-12
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
这个题可以使用 BFS 求解,但不是最优解,此方法时间击败 9% 空间击败 4%
class Solution { public int numSquares(int n) { List<Integer> squares = generateSquare(n); Queue<Integer> queue = new LinkedList<>(); queue.add(n); int level = 0; while(!queue.isEmpty()){ int size = queue.size(); level++; while(size-- > 0){ int cur = queue.poll(); for(int s : squares){ int next = cur - s; if(next < 0) break; if(next == 0) return level; queue.add(next); } } } return n; } //这个函数返回小于 n 的所有完全平方数的和,n >= 1 //实现方法并没有让两数直接相乘,而是使用数学规律 public List<Integer> generateSquare(int n){ List<Integer> list = new ArrayList<>(); int increment = 1; int gap = 2; int i = 1; while(i <= n){ list.add(i); i = i + increment + gap; increment += gap; } return list; } }
三、 最短单词路径
127. 单词接龙 (hard) 2021-07-12
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:
序列中第一个单词是 beginWord 。
序列中最后一个单词是 endWord 。
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典 wordList 中的单词。
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。
官方解题方法:先给每个单词标号,给每一个单词分配一个id 。创建一个由单词word 到 id 之间的映射 wordId, 并将beginWord 与 wordList 中所有的单词都加入到这个映射中。检查endWord是否在该映射内,如果不存在则输入无解。
建图的优化方法,创建虚拟节点。如 hit ,我们创建三个虚拟节点 *it , h*t, hi* ,让单词连接虚拟节点再连接单词。最后将路径长度除以 2 。
官方答案如下
class Solution { Map<String, Integer> wordId = new HashMap<String, Integer>(); List<List<Integer>> edge = new ArrayList<List<Integer>>(); int nodeNum = 0; public int ladderLength(String beginWord, String endWord, List<String> wordList) { for(String word : wordList){ addEdge(word); } addEdge(beginWord); if(!wordId.containsKey(endWord)){ return 0; } int[] dis = new int[nodeNum]; Arrays.fill(dis, Integer.MAX_VALUE); int beginId = wordId.get(beginWord); int endId = wordId.get(endWord); dis[beginId] = 0; Queue<Integer> que = new LinkedList<Integer>(); que.add(beginId); while(!que.isEmpty()){ int x = que.poll(); if(x == endId){ return dis[endId] / 2 + 1; } for(int it : edge.get(x)){ if(dis[it] == Integer.MAX_VALUE){ dis[it] = dis[x] + 1; que.add(it); } } } return 0; } public void addEdge(String word){ addWord(word); int id1 = wordId.get(word); char[] array = word.toCharArray(); int length = array.length; for(int i = 0; i < length; i++){ char tmp = array[i]; array[i] = '*'; String newWord = new String(array); addWord(newWord); int id2 = wordId.get(newWord); edge.get(id1).add(id2); edge.get(id2).add(id1); array[i] = tmp; } } public void addWord(String word){ if(!wordId.containsKey(word)){ wordId.put(word, nodeNum++); edge.add(new ArrayList<Integer>()); } } }
原文地址:https://www.cnblogs.com/nobita/p/15005361.html
- 利用autocomplete.js实现仿搜索效果(ajax动态获取后端[C#]数据)
- sql语句的简化(r2第7天)
- Ajax jsonp 跨域请求实例
- asp.net动态解析用户控件(UserControl)
- 找到多个与名为“Home”的控制器匹配的类型的解决方案
- 关于sequence问题的紧急处理(r2第26天)
- 使用动态变量进行动态数据比较(r2笔记25天)
- MVC分部视图@Html.Partial
- 基于马尔科夫链的产品评估预测
- MVC 控制器中传递dynamic(对象) 给视图
- 使用copy命令解决LONG类型的困扰(r2第24天)
- MVC 获取路由的 URL 参数值和默认值的集合。
- 用libsvm进行回归预测
- mvc路由配置.html结尾的伪静态
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ent orm笔记1---快速尝鲜
- UsoDllLoader:一款功能强大的武器化特权文件写入工具
- 宇智波程序笔记10-为什么你使用的 Spring Security OAuth 过期了
- 无线电侧信道攻击利用复现:监听显示器显示内容
- typeScript 配置文件该怎么写?
- 内网渗透:不出网渗透技巧
- Python自学成才之路 生成器的使用
- ent orm笔记2---schema使用(上)
- 力扣1514——概率最大的路径
- Pytest之自定义mark
- 全网首发 | 通达OA多枚0day漏洞分享
- ubuntu 解压rar文件
- 基于Hive进行数仓建设的资源元数据信息统计
- 我也没想到 Springboot + Flowable 开发工作流会这么简单
- k8s 调度