庞果英雄会——最小操作数

该博客探讨了一种通过二叉树结构解决如何从单词A转换为单词B的问题,其中每次转换必须在给定的单词集合Dict内。题目提供了一个例子,展示如何从'hit'变为'cog'的最短操作序列。程序分析部分提到利用二叉链表表示法构建树形结构,并记录最短路径。测试阶段展示了具体的树形图和路径选择策略。

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

题目

给了A、B两个单词和一个单词集合Dict,每个的长度都相同。我们希望通过若干次操作把单词A变成单词B,每次操作可以改变单词中的一个字母,同时,新产生的单词必须是在给定的单词集合Dict中。求所有行得通步数最少的修改方法。

   举个例子如下:

Given:

   A = "hit"

   B = "cog"

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

Return

 [

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

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

 ]

    即把字符串A = "hit"转变成字符串B = "cog",有以下两种可能:

  1. "hit" -> "hot" ->  "dot" ->  "dog" -> "cog";
  2. "hit" ->  "hot" ->  "lot" ->  "log"  ->"cog"。

程序分析

利用二叉链表表示法将各字符串按照相差字符个数组织起来,叶子结点是目标串,建立二叉链表时记录从根结点到叶子结点的最小跳数,如果在建立过程中超个过最小跳数,则终止这条路径。

建立完二叉链表后,深度优先遍历记录节点数即可。

结构图:


黄色线表示结点的父亲结点。


测试例子中的树形图为:


黑色虚线表示这条路径的长度超过了最短的路径,只自动丢弃即可,如图从hit-->cog最长为5跳,则hit->hot->dot->lot->log...超过了5跳了,弃之

代码:

#include <string>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef struct __Tree
{
	string str;
	struct __Tree *parent;
	struct __Tree *sibling;
	struct __Tree *child;
}Tree;


class Solution
{
private:
	string *m_str;
	Tree m_head;
	int m_n;
public:
	bool compareStr(string &s1, string &s2)
	{
		int count = 0;
		int l = s1.length();
		for(int i = 0; i < l; i++)
		{
			if(s1[i] != s2[i])
			{
				count++;
				if(count > 1)
				{
					break;
				}
			}
		}

		return (count == 1) ? true : false;
	}

	void createTree(string &start, string &end, set<string>& dict)
	{
		set<string>::iterator iter;
		string str;
		bool flag = false;
		Tree *p;

		m_head.str = start;
		m_head.parent = NULL;
		m_head.sibling = NULL;
		m_n = 100000;

		//孩子节点生成过程
		for(iter = dict.begin(); iter != dict.end(); iter++)
		{
			str = *iter;
			if(compareStr(str, m_head.str))//与当前节点比较
			{			
				p = new Tree;
				p->str = str;
				p->parent = &m_head;
				m_head.child = p;
				createNode(*p, 2, end, dict);
				break;
			}
		}

		if(iter == dict.end())//如果没有差一个字符的,判断是否与end一样
		{
			if(compareStr(end, m_head.str))
			{
				p = new Tree;
				p->str = end;
				p->parent = &m_head;
				p->sibling = NULL;//不用向下比较了,之后的一定比当前的长
				m_head.child = p;

				m_n = 2;//记录最小长度
			}
			else
			{
				m_head.child = NULL;
			}
		}
	}

	void createNode(Tree &node, int n, string &end, set<string>& dict)
	{
		set<string>::iterator iter;
		string str;
		bool flag = false;
		Tree *p;

		node.child = NULL;
		node.sibling = NULL;

		//剪枝,大小最小长度,去除
		if(n > m_n)
		{
			return;
		}

		if(compareStr(end, node.str))
		{
			p = new Tree;
			p->str = end;//表示结束
			p->parent = &node;
			p->sibling = NULL;//不用向下比较了,之后的一定比当前的长
			p->child = NULL;
			node.child = p;

			if(n < m_n)
			{
				m_n = n;//记录最小长度
			}
//			return;
		}
		else
		{
			//孩子节点生成过程
			for(iter = dict.begin(); iter != dict.end(); iter++)
			{
				str = *iter;
				if(compareStr(str, node.str))//与当前节点比较
				{
					//兄弟节点比较,找到还没有用过的
					p = node.parent->child;
					while(p)
					{
						if(str.compare(p->str) == 0)
						{
							flag = true;
							break;
						}
						p = p->sibling;
					}
					if(flag == true)
					{
						flag = false;
						continue;
					}

					//父亲节点比较
					p = node.parent;
					while(p)
					{
						if(iter->compare(p->str) == 0)
						{
							flag = true;//节点之前已经存在
							break;
						}
						p = p->parent;
					}

					if(flag == true)
					{
						flag = false;
						continue;
					}

					p = new Tree;
					p->str = str;
					p->parent = &node;
					node.child = p;
					createNode(*p, n + 1, end, dict);
					break;
				}
			}

			if(iter == dict.end())//如果没有符合条件的,置空
			{
				node.child = NULL;
			}
		}

		//兄弟节点生成过程
		flag = false;
		for(iter = dict.begin(); iter != dict.end(); iter++)
		{
			str = *iter;
			if(compareStr(str, node.parent->str))//与父亲节点比较,且与当前节点不同的节点
			{
				//兄弟节点比较,找到还没有用过的
				p = node.parent->child;
				while(p)
				{
					if(str.compare(p->str) == 0)
					{
						flag = true;
						break;
					}
					p = p->sibling;
				}
				if(flag == true)
				{
					flag = false;
					continue;
				}

				//父亲节点比较,找到还没有用过的
				p = node.parent->parent;
				while(p)
				{
					if(iter->compare(p->str) == 0)
					{
						flag = true;//节点之前已经存在
						break;
					}
					p = p->parent;
				}

				if(flag == true)
				{
					flag = false;
					continue;
				}
				
				p = new Tree;
				p->str = str;
				p->parent = node.parent;
				node.sibling = p;
				createNode(*p, n, end, dict);
				break;
			}
		}

		if(iter == dict.end())//如果没有符合条件的,置空
		{
			node.sibling = NULL;
		}
	}

	void DFS(Tree *root, int n, vector<string> &vec, vector<vector<string>> &vvec, string &end)
	{
		vector<string> *p;
		if(root == NULL)
		{
			return;
		}

		if(n > m_n)//超过最小长度的,去除掉
		{
			return;
		}

		cout << "第" << n + 1 << "层:" << root->str<<endl;
		vec.insert(vec.begin() + n, root->str);

		if(root->str.compare(end) == 0)
		{
			p = new vector<string>;
			for(vector<string>::iterator iter = vec.begin(); iter < vec.end(); iter++)
			{
				p->push_back(*iter);
			}
			vvec.push_back(*p);
		}

		DFS(root->child, n + 1, vec, vvec, end);
		
		//去除前一个过程中的后面部分
		for(int i = vec.size(); i > n; i--)
		{
			vec.pop_back();
		}

		DFS(root->sibling, n, vec, vvec, end);


	}

    vector<vector<string>> findLadders(string start, string end, set<string>& dict)
    {
		vector<string> vec;
		vector<vector<string>> vvec;

		if(start == end)
		{
			return vvec;
		}
		else if(compareStr(start, end))
		{
			vec.push_back(start);
			vec.push_back(end);
			vvec.push_back(vec);
		}
		else
		{
			createTree(start, end, dict);
			DFS(&m_head, 0, vec, vvec, end);
		}

		return vvec;
    }
};

测试

测试一:
int main()
{
	Solution aa;
//	string start("a2b");
	string start("hit");
	vector<vector<string>> vec;
	vector<string>a;
//	string end("bmn");
	string end("cog");

	set<string> set1;
	set1.insert("hot");
	set1.insert("dot");
	set1.insert("dog");
	set1.insert("lot");
	set1.insert("log");
	//set1.insert("amn");
	//set1.insert("a2n");
	//set1.insert("b2b");
	//set1.insert("bhb");
	//set1.insert("b2n");
	//set1.insert("ahn");
	vec = aa.findLadders(start, end, set1);

	for(vector<vector<string>>::iterator vviter = vec.begin(); vviter < vec.end(); vviter++)
	{
		cout << *vviter->begin();
		for(vector<string>::iterator iter = vviter->begin() + 1; iter < vviter->end(); iter++)
		{
			cout << "->" <<*iter;
		}
		cout << endl;
	}
	return 0;
}
结果:


测试二:
int main()
{
	Solution aa;
	string start("a2b");
//	string start("hit");
	vector<vector<string>> vec;
	vector<string>a;
	string end("bmn");
//	string end("cog");

	set<string> set1;
	//set1.insert("hot");
	//set1.insert("dot");
	//set1.insert("dog");
	//set1.insert("lot");
	//set1.insert("log");
	set1.insert("amn");
	set1.insert("a2n");
	set1.insert("b2b");
	set1.insert("bhb");
	set1.insert("b2n");
	set1.insert("ahn");
	vec = aa.findLadders(start, end, set1);

	for(vector<vector<string>>::iterator vviter = vec.begin(); vviter < vec.end(); vviter++)
	{
		cout << *vviter->begin();
		for(vector<string>::iterator iter = vviter->begin() + 1; iter < vviter->end(); iter++)
		{
			cout << "->" <<*iter;
		}
		cout << endl;
	}
	return 0;
}
结果:


写在最后:之前自己测试了很多例子,结果都正确,然后就写博客没有提交。但看到大家评论后我也提交了代码,但没有通过,想不到什么原因,可能是溢出或超时。


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值