【leetcode 127.单词接龙】(单源无权最短路 | 数学建模 | BFS | 双向BFS | A-Star)

题目直达icon-default.png?t=N7T8https://leetcode.cn/problems/word-ladder/description/

题目介绍

转换序列:是一个字符串转换序列 first_word -> s1 -> s2 -> ... -> sk -> last_word

要求:相邻两个字符串只相差一个字符,并且除了first_word,其他字符串必须出现在指定字符串集合words当中。求最短字符串转换序列

示例:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。

就是一个隐式单源无权最短路问题,朴素的BFS就能解决。(有很多类似的题目,比如基因突变序列,信息输送验证一类的)

但是这题的新意在于数学建模(hash、虚拟节点)和算法优化(bidirDFS、A-Star)。

朴素BFS

#include <unordered_map>
#include <string>
#include <vector>
#include <array>
#include <limits>
#include <queue>

constexpr int N { 50 };
constexpr int M { 10 };
std::unordered_map<std::string, int> hash;
std::array<std::array<int, N * M>, N * M> graph {};
std::array<int, N * M> counter;
std::array<int, N * M> distance;
int index {};
void hashing(std::string& Str){
	if(!hash.count(Str)) hash[Str] = index ++;
}

void insert(std::string& Str){
	hashing(Str);
	int from { hash[Str] };
	for(char& ref : Str){
		char buffer { ref };
		ref = '*';
		hashing(Str);
		int to { hash[Str] };
		graph[from][counter[to] ++] = to;
		graph[to][counter[from] ++] = from;
		ref = buffer;
	}
}
int ladder_length(std::string& begin, std::string& end, std::vector<std::string>& words){
	for(auto& Str : words) insert(Str);
	insert(begin);
	if(!hash.count(end)) return 0;
	distance.fill(std::numeric_limits<int>::max());
	distance[hash[begin]] = 0;
	std::queue<int> Q;
	Q.push(hash[begin]);
	while(!Q.empty()){
		int current { Q.front() };
		Q.pop();
		if(current == hash[end]) return distance[hash[end]] / 2 + 1;
		for(int i {}; i < counter[current]; ++i){
			int next { graph[current][i] };
			if(distance[next] == std::numeric_limits<int>::max()){
				distance[next] = distance[current] + 1;
				Q.push(next);
			}
		}
	}
	return 0;
}

双向BFS

#include <unordered_map>
#include <string>
#include <vector>
#include <array>
#include <limits>
#include <queue>

constexpr int N { 50 };
constexpr int M { 10 };
std::unordered_map<std::string, int> hash;
std::array<std::array<int, N * M>, N * M> graph {};
std::array<int, N * M> counter;
std::array<int, N * M> distance;
std::array<int, N * M> rdistance;

int index {};
void hashing(std::string& Str){
	if(!hash.count(Str)) hash[Str] = index ++;
}

void insert(std::string& Str){
	hashing(Str);
	int from { hash[Str] };
	for(char& ref : Str){
		char buffer { ref };
		ref = '*';
		hashing(Str);
		int to { hash[Str] };
		graph[from][counter[to] ++] = to;
		graph[to][counter[from] ++] = from;
		ref = buffer;
	}
}

int ladder_length(std::string& first, std::string& last, std::vector<std::string>& words){
	for(auto& s : words) insert(s);
	insert(first);
	if(!hash.count(last)) return 0;
	distance.fill(std::numeric_limits<int>::max());
	rdistance.fill(std::numeric_limits<int>::max());
	distance[hash[first]] = rdistance[hash[last]] = 0;
	std::queue<int> Q;
	std::queue<int> rQ;
	Q.push(hash[first]);
	rQ.push(hash[last]);
	while(!Q.empty() && !rQ.empty()){
		int s_Q = Q.size();
		int s_rQ = rQ.size();
		while(s_Q--){
			auto current {Q.front()};
			Q.pop();
			if(!(rdistance[current] == std::numeric_limits<int>::max()))
				return (distance[current] + rdistance[current]) / 2 + 1;
			for(int i {}; i < counter[current]; +i){
				int next {graph[current][i]};
				if(distance[next] == std::numeric_limits<int>::max()){
					distance[next] = distance[current] + 1;
					Q.push(next);
				}
			}
		}
		while(s_rQ--){
			auto current {rQ.front()};
			rQ.pop();
			if(!(distance[current] == std::numeric_limits<int>::max()))
				return (distance[current] + rdistance[current]) / 2 + 1;
			for(int i {}; i < counter[current]; +i){
				int next {graph[current][i]};
				if(rdistance[next] == std::numeric_limits<int>::max()){
					rdistance[next] = rdistance[current] + 1;
					Q.push(next);
				}
			}
		}
	}
	return 0;
	
}

A-Star BFS

#include <unordered_map>
#include <vector>
#include <array>
#include <limits>
#include <string>
#include <queue>
#include <ranges>

constexpr int N { 64 };
std::unordered_map<std::string const&, int> hash;
std::unordered_map<std::int, std::string const&> rehash;
std::array<std::array<int, N>, N> graph {};
std::array<int, N> counter  {};
std::array<int, N> distance {};
std::array<int, N> value    {};

int ladder_length(std::string& first, std::string& last, std::vector<std::string>& words){
	int index {};
	auto len { words[0].length() };
	auto f { [&](std::string& source, std::string& target){
		int __value__ {};
		for(auto i {0U}; i < len; ++i) __value__ += target[i] == source[i];
		return __value__;
	} };
	
	for(auto& s : words) {
		hash[s] = index;
		rehash[index ++] = s;
		value[hash[s]] = f(s, last);
	}
	for(auto &s : words)
		for(auto &t : words | std::views::filter([&s](auto t){ return t == s; }))
			if(f(s, t) == 1){
				graph[hash[s]][counter[hash[s]] ++] = hash[t];
				graph[hash[t]][counter[hash[t]] ++] = hash[s];
			}
			
	if(!hash.count(last)) return 0;
	distance.fill(std::numeric_limits<int>::max());
	distance[hash[first]] = 0;
	std::priority_queue<std::pair<int, int>> Q;
	Q.emplace(0, hash[first]);
	while(!Q.empty()){
		auto [dummy, current] = Q.top();
		Q.pop();
		if(current == hash[last]) return distance[hash[last]];
		for(int i {}; i < counter[current]; ++i){
			int next { graph[current][i] };
			if(distance[next] == std::numeric_limits<int>::max()){
				distance[next] = distance[current] + 1;
				Q.emplace(distance[next] + f(rehash[current], rehash[next]));
			}
		}
	}
	return 0;
}

当然也可以用IDA* DFS优化,就不多赘述,留给读者自己试着编写了

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值