BFS(一)单词接龙
问题定义
给定一个字典序列 wordList,一个初始的单词 beginWord 和一个目标单词 endWord,现在要求每次变换满足以下条件将 beginWord 转换为 endWord:
- 每次只能转换一个字母
- 转换后的单词必须出现在
wordList中
求是否能够在满足对应的转换条件的前提下,能否将 beginWord 转换成 endWord,如果可以转换,则返回转换的最少次数;如果不能转换,则返回 0
数据范围:
- \(1 <= beginWord.length <= 10\)
- \(endWord.length == beginWord.length\)
- \(1 <= wordList.length <= 5000\)
- \(wordList[i].length == beginWord.length\)
- \(beginWord\)、\(endWord\) 和 \(wordList[i]\) 由小写英文字母组成
- \(beginWord != endWord\)
解决思路
BFS这个问题是一个典型的
BFS问题,只需要每次遍历时对每个单词的每个位置进行相应的转换,再进行比较即可,使用一个Map来记录当前的操作次数双向
BFS由于数据量比较大,使用一般的
BFS的搜索方式使得导致每次的维度的节点数量爆炸式的增长,根据题意,最终的end需要在wordList中才有可能能进行转换,因此可以从beginWord和endWord两个方向出发,使得搜索的节点数大幅度减少,从而减少计算时间A*搜索每个转换的单词之间的相差的字母的数量可以看成是一个带有权重的边,此时这个问题就可以转换成为一般的图搜索问题,即找到一条权重最小的路径从
beinWord——>endWord
实现
BFSclass Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
if (!wordList.contains(endWord)) return 0; Deque<String> deque = new LinkedList<>();
Map<String, Integer> map = new HashMap<>(); // 用于记录已经访问的路径长度 deque.offer(beginWord);
map.put(beginWord, 1); while (!deque.isEmpty()) {
int size = deque.size(); // 每层需要遍历的节点的数量
while (size-- > 0) {
String node = deque.poll();
int n = node.length();
char[] array = node.toCharArray();
// 转换部分。。
for (int i = 0; i < n; ++i) {
char ch = array[i];
for (int j = 0; j < 26; ++j) {
array[i] = (char) ('a' + j);
String sub = String.valueOf(array); if (!wordList.contains(sub)) continue;
if (map.containsKey(sub)) continue; if (sub.equals(endWord))
return map.get(node) + 1; map.put(sub, map.get(node) + 1);
deque.offer(sub);
} array[i] = ch;
}
}
} return 0;
}
}
直接使用
BFS的方式会导致访问的节点数量爆炸性地增长,因此这种方式会导致超时双向
BFSclass Solution {
private final Set<String> set = new HashSet<>(); public int ladderLength(String begin, String end, List<String> wordList) {
if (!wordList.contains(end)) return 0; set.addAll(wordList); int ans = bfs(begin, end); return ans == -1 ? 0 : ans + 1;
} int bfs(String begin, String end) {
Deque<String> cur = new LinkedList<>();
Deque<String> other = new LinkedList<>(); // 从 beiginWord 向下搜索
Map<String, Integer> top = new HashMap<>();
// 从 endWord 向上搜素
Map<String, Integer> bottom = new HashMap<>(); top.put(begin, 0);
bottom.put(end, 0); cur.offer(begin);
other.offer(end); while (!cur.isEmpty() && !other.isEmpty()) {
int t = -1;
// 交替搜索,使得每次遍历的节点数是平衡的
if (cur.size() <= other.size()) {
t = update(cur, top, bottom);
} else {
t = update(other, bottom, top);
} if (t != -1) return t;
} return -1;
} int update(
Deque<String> d,
Map<String, Integer> top,
Map<String, Integer> bottom
) {
String node = d.poll();
int val = top.get(node); int n = node.length(); // 转换每个位置的字母,搜索满足条件的单词
char[] array = node.toCharArray();
for (int i = 0; i < n; ++i) {
char ch = array[i];
for (int j = 0; j < 26; ++j) {
array[i] = (char) ('a' + j);
String tmp = String.valueOf(array); if (!set.contains(tmp)) continue;
if (top.containsKey(tmp)) continue; if (bottom.containsKey(tmp))
return val + bottom.get(tmp) + 1; d.offer(tmp);
top.put(tmp, val + 1);
}
array[i] = ch;
} return -1;
}
}
A*搜索class Solution {
static class Node {
String str;
int val; Node(String _str, int _val) {
this.str= _str;
this.val = _val;
}
} String s, e;
int INF = 0x3f3f3f3f;
Set<String> set = new HashSet<>(); public int ladderLength(String _s, String _e, List<String> wordList) {
this.s = _s;
this.e = _e; this.set.addAll(wordList); int ans = aStar(); return ans == -1 ? 0 : ans + 1;
} int aStar() {
PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
Map<String, Integer> dist = new HashMap<>();
dist.put(s, 0);
pq.offer(new Node(s, find(s))); // 搜索边。。
while (!pq.isEmpty()) {
Node node = pq.poll();
String str = node.str;
if (str.equals(e)) break; int distance = dist.get(str);
int n = str.length(); // 字母转换部分
char[] array = str.toCharArray();
for (int i = 0; i < n; ++i) {
char ch = array[i];
for (int j = 0; j < 26; ++j) {
array[i] = (char) ('a' + j);
String sub = String.valueOf(array);
if (!set.contains(sub)) continue; if (!dist.containsKey(sub) || dist.get(sub) > distance + 1) {
dist.put(sub, distance + 1);
pq.offer(new Node(sub, find(sub) + dist.get(sub)));
}
} array[i] = ch;
}
} return dist.containsKey(e) ? dist.get(e) : -1;
} int find(String str) {
if (str.length() != e.length()) return INF;
int n = str.length();
int ans = 0; for (int i = 0; i < n; ++i) {
ans += str.charAt(i) == e.charAt(i) ? 0 : 1;
} return ans;
}
}
参考:
[1] https://leetcode-cn.com/problems/word-ladder/solution/gong-shui-san-xie-ru-he-shi-yong-shuang-magjd/
BFS(一)单词接龙的更多相关文章
- 单词接龙(dragon)(BFS)
单词接龙(dragon) 时间限制: 1 Sec 内存限制: 64 MB提交: 12 解决: 5[提交][状态][讨论版] 题目描述 单 词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已 ...
- Leetcode之广度优先搜索(BFS)专题-127. 单词接龙(Word Ladder)
Leetcode之广度优先搜索(BFS)专题-127. 单词接龙(Word Ladder) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tre ...
- Leetcode 126.单词接龙II
单词接龙II 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列.转换需遵循如下规则: 每次转换只能 ...
- LeetCode 126. Word Ladder II 单词接龙 II(C++/Java)
题目: Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transfo ...
- Java实现 LeetCode 127 单词接龙
127. 单词接龙 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度.转换需遵循如下规则: 每次转换只能改变一个字 ...
- Java实现 LeetCode 126 单词接龙 II
126. 单词接龙 II 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列.转换需遵循如下规则: ...
- NOIP2000单词接龙[DFS]
题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...
- Noip2000 T3 单词接龙
题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...
- 洛谷 P1019 单词接龙 Label:dfs
题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...
- 【wikioi】1018 单词接龙
题目链接 算法:DFS+考你阅题 题目描述: 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中 ...
随机推荐
- 整理php防注入和XSS攻击通用过滤
对网站发动XSS攻击的方式有很多种,仅仅使用php的一些内置过滤函数是对付不了的,即使你将filter_var,mysql_real_escape_string,htmlentities,htmlsp ...
- 其它——paramiko模块的使用
文章目录 paramiko 一 介绍 二 通过用户名密码方式远程执行命令 三 通过用户名密码方式上传下载文件 四 通过公钥私钥远程执行命令 五 通过公钥私钥远程上传下载文件 六 通过私钥字符串远程连接 ...
- gitlab ci 用 cypress/playwright 做测试并展示结果至 mr
前言 看了一下官方的教程好像都没有讲怎么将测试结果展示出来,只是给出测试的 ci 脚本,但根据 gitlab 官方的文档是有测试报告的展示的,所以这里给出一个基于 junit 测试报告的展示. 前期准 ...
- element ui的多个表格复选框,展开列显示错误
今天在公司写页面的时候碰到一个bug,我们的那个页面上有多个表格. 用v-if来判断显示,然后再使用复选框和展开列的时候出了问题.先是复选框,第二个表格的复选框下一列不显示,我试了试,在下面的一列都会 ...
- 2020/4/29 一场令人头疼的cf。。。
今天是被安排的cf...我真的是太菜了啊...又双叒叕被机房的一群dalao吊打了... 这就是我与6年级的dalao的区别吗...我裂开了 T1:A - Exercising Walk 简单题. 就 ...
- oracle命令7 -rman命令
$ rman targer /RMAN> show all; #查看rman中所有的配置RMAN configuration parameters for database with db_un ...
- CF1364B
题目简化和分析: 这题没啥好说的,找其绝对值最大,也就是找到每一个山峰山谷. 这样不仅满足选择的个数最少,并且值最大. 正确性证明: 若 \(a\le b\le c\) \(|a-b|+|b-c|=( ...
- XCODE9.1的一些新问题
自从XCODE7苹果就允许用免费的开发者账号进行真机测试了,但是还是有很多限制的. 在用的过程中发现限制如下: 1.只能生成*.app文件,不能打包成ipa.官方这么说的,但是奇诡的是,我archiv ...
- 模拟退火算法(SA)
求某个目标函数的最值 爬山法 首先我们通过爬山法来引出模拟退火算法 我们先看一个例子:求函数的最值 我们用爬山法解决这个问题的步骤 1.在解空间中随机生成一个初始解(图中小黄点就是我们生成的初始解) ...
- 为React Ant-Design Table增加字段设置
最近做的几个项目经常遇到这样的需求,要在表格上增加一个自定义表格字段设置的功能.就是用户可以自己控制那些列需要展示. 在几个项目里都实现了一遍,每个项目的需求又都有点儿不一样,迭代了很多版,所以抽时间 ...