Arithmetic problem | 单词接龙 II

本文详细解析了如何找出从一个单词到另一个单词的所有最短转换序列,并提供了具体实现代码。重点在于通过比特位操作判断字母变化及构建图的深度优先搜索算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目如下:

给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列

比如:

  1. 每次只能改变一个字母。
  2. 变换过程中的中间单词必须在字典中出现。

 注意事项
  • 所有单词具有相同的长度。
  • 所有单词都只包含小写字母。


样例

给出数据如下:

start = "hit"

end = "cog"

dict = ["hot","dot","dog","lot","log"]

返回

[

    ["hit","hot","dot","dog","cog"],

    ["hit","hot","lot","log","cog"]

  ]


解题思路:

这题目在题意上本人有一点疑惑,因为题意表示每一次只改变一个字母,但没说明在哪种前提下。在这里可以理解成“只要其他字母相同即可”跟“其他字母跟所在位置相同”。例如“dig”,“gad”这两个单词(d,g相同,i,a不同)也是符合题意的。虽然如此,但本人还是以最大困难的前提“只要其他字母相同即可“来解题。从而可以兼顾两种前提。

解题过程中,需要注意以下几点:

1:既然选择了字母位置无关性的前提,那么该如何判断“只改变一个字母”。

【字母位置的无关性前提下,使用标记法显然会事半功倍,以前的博文中早有提及,合理使用bitset能省下不少麻烦。并且,单词(对于重复元素,出现偶数次记0,奇数次记1)之间如果只改变了一个字母,那么标记后产生的数字相异或也就会剩下两个1,这里使用bitset的count方法即可。】

2:由于需要转化成图,该使用何种方法插入节点。

【既然判断已完成,那么遍历上本人就以深度优先来遍历建图,当然其中还有一些需要注意的地方,不难思考因此简略。】

3:建图后,怎么寻找最短路径。

【由于路径存在重复元素的输出,使用回溯法明显比使用深度或宽度优先遍历更加明智,至于是否最短路径,比较size即可】

思路结构定义如下:

typedef struct NNODE
{
	int count = 0; int index = 0; vector<NNODE *>child;
	NNODE(int c, int i) { count = c; index = i; }
	NNODE() {}
	~NNODE() { for (NNODE*n : child) { if (n)delete n; } }
}NNODE;

思路代码实现如下:

int part_1(char *c)
{
	int m = 0;
	while (*c){
		if (m&(1 << (*c - 'a')))
			m ^= 1 << (*c - 'a');
		else
			m |= 1 << (*c - 'a');
		c++;
	}return m;
}

bool part_2(NNODE *root,pair<int,int> &in)
{
	NNODE *temp_; bool l = false;
	stack<NNODE *>stack_;
	stack_.push(root);
	while (!stack_.empty()){
		temp_ = stack_.top(); stack_.pop();
		if (in.first == temp_->count)continue;
		bitset<32>bitset_(in.first^temp_->count);	
		for (NNODE * n : temp_->child)
			stack_.push(n);
		if (bitset_.count() == 2){
			NNODE *in_ = new NNODE(in.first, in.second);
			temp_->child.push_back(in_);
			l = true;
		}
	}
	return l;
}

void Method(char *start, char *end, vector<char *> &dict, vector<vector<char *>> &result)
{
	dict.push_back(end); int m = 1;
	deque<pair<int, int>> deque_; 
	pair<int, int> ptemp_; 
	vector<char *> vtemp_;
	NNODE *root_ = new NNODE(part_1(start), -1), *child_ = 0, *temp_ = 0;
	for (int i = 0; i < (int)dict.size(); ++i)
	{
		ptemp_ = make_pair(part_1(dict[i]), i);
		if (!part_2(root_, ptemp_)){
			deque_.push_back(ptemp_); continue;
		}
		while (!deque_.empty() && m){
			m = 0; int s = deque_.size();
			for (int i = 0; i < s; ++i){
				ptemp_ = deque_.front(); deque_.pop_front();
				if (part_2(root_, ptemp_))
					m++;
				else
					deque_.push_back(ptemp_);
			}
		}
	}
	while (!deque_.empty()){
		int i = deque_.back().second;
		deque_.pop_back();
		if (dict[i] == end){
			vtemp_.push_back("none"), result.push_back(vtemp_); return;
		}
	}
	child_ = root_; m = 2147483647;
	while (true){
		vtemp_.push_back(child_->index == -1 ? start : dict[child_->index]);

		int i = child_->child.size();
		bool l = child_->index == -1 ? false : dict[child_->index] == end;
		if (i == 0 || l){
			if (l) if (m >= (int)vtemp_.size())result.push_back(vtemp_), m = vtemp_.size();
			vtemp_.clear();
			child_ = root_;
			if (temp_)
				delete temp_->child[temp_->child.size() - 1],
				temp_->child.pop_back(),
				temp_ = 0;
			else if (i == 0) break;
			continue;
		}
		if (i > 1)
			temp_ = child_,
			child_ = child_->child[i - 1];

		else child_ = child_->child[0];
	}
	delete root_;
}



 注意事项
  • 所有单词具有相同的长度。
  • 所有单词都只包含小写字母。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值