有几天没上来写编程挑战赛的解法了,主要是新出的c#提交都有问题,所以,只好做做之前发布的题,看了下这道题,最小操作数还没有,就做这道题吧。
先看看题目:
给了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",有以下两种可能:
- "hit" -> "hot" -> "dot" -> "dog" -> "cog";
- "hit" -> "hot" -> "lot" -> "log" ->"cog"。
这道题一看完,就觉得不算难,感觉有很多种做法,如果把每个单词当做一个点来看,就是从A点到B点的走法,要求路径最短,很像是走迷宫,呵呵,所以,就直接用A*寻径算法,其实就是动态规划算法。
既然确定了算法方向,那么就考虑具体怎么算吧。
1、首先我们要考虑评估因子,这里很容易就知道,评估因子就是路径步骤,从A到B要经过多少步。
2、需要用到几个集合来存储这些数据:A可以到达的单词集合ADic,能够直接到达B的单词集合BDic,已经走过的单词集合usedDic,还没有走过的单词集合unUsedDic,每个单词能够达到其他单词的集合Dic。
解题思路:
1、首先从A开始,吧能够达到的单词放入unUsedDic,评估因子为1.
2、然后查找评估因子为1的节点,看看此节点能否直接到达B,不能,则将能够到达的单词节点添加到unUsedDic中去,评估因子为2,并将因子为1的节点移入到useDic中去,注意,在添加节点时,要判断此节点是否在unUsedDic或者usedDic中存在过,如果存在,说明之前已经走过。不用添加,走回头路。
3、评估因子为1的全部走完后,如果没有找到,那就寻找评估因子为2的,重复步骤2,直到评估因子为K时找到为止,然后遍历评估因子为K的所有可能,找出所有可能,完成结束。
思路就是这样的,按照思路写完后提交,ok没有问题。
代码部分:
首先是几个静态的集合变量:
static Dictionary<string, string> usedDic = new Dictionary<string, string>();
static Dictionary<string, List<string>> DictKey = new Dictionary<string, List<string>>();
static Dictionary<string, string> unuseDic = new Dictionary<string, string>();
static Dictionary<string, int> BDic = new Dictionary<string, int>();
static List<string> PathString;
查找函数:
public static void find(int value,bool finded)
{
string path = "";
string key = "";
foreach (KeyValuePair<string, string> kvp in unuseDic)
{
if (kvp.Value.Split(',').Length == value)
{
key = kvp.Key;
path = kvp.Value;
break;
}
}
if (key != "")
{
usedDic.Add(key,unuseDic[key]);
unuseDic.Remove(key);
bool flag = cal(key, usedDic[key]);
if (flag)
{
PathString.Add(path + "," + key);
find(value, flag);
}
else
{
find(value, finded);
}
}
else
{
//当前的找完了,找下一步的
if (finded)
{
//最短的找到了,并且找完了,不用进一步寻找了
}
else
{
//没找到,需要进一步寻找
if (unuseDic.Count > 0)
{
find(value + 1, finded);
}
}
}
}
处理节点函数,
public static bool cal(string key,string path)
{
bool flag = false;
if (BDic.ContainsKey(key))
{
flag = true;
}
else
{
List<string> list = DictKey[key];
for (int i = 0; i < list.Count; i++)
{
if (unuseDic.ContainsKey(list[i]) || usedDic.ContainsKey(list[i]))
{
continue;
}
else
{
unuseDic.Add(list[i], path+","+key);
}
}
}
return flag;
}
主函数中的处理过程:
usedDic = new Dictionary<string, string>();
DictKey = new Dictionary<string, List<string>>();
unuseDic = new Dictionary<string, string>();
BDic = new Dictionary<string, int>();
PathString = new List<string>();
List<string> ADic = new List<string>();
string A = start;
string B = end;
string[] Dict = dict;
if(A==B)
{
string[][] r = new string[0][];
//r[0]=new string[0];
return r;
}
for (int i = 0; i < A.Length; i++)
{
if (A.Remove(i, 1) == B.Remove(i, 1))
{
PathString.Add(A + "," + B);
break;
}
}
if (PathString.Count >0)
{
string[][] r = new string[PathString.Count][];
string[] path = PathString[0].Split(',');
r[0] = path;
return r;
}
#region 初始化字典关联数据
for (int i = 0; i < Dict.Length; i++)
{
List<string> values = new List<string>();
for (int j = 0; j < Dict.Length; j++)
{
if (i == j)
{
continue;
}
for (int k = 0; k < Dict[i].Length; k++)
{
if (Dict[i].Remove(k, 1) == Dict[j].Remove(k, 1))
{
values.Add(Dict[j]);
break;
}
}
}
DictKey.Add(Dict[i], values);
}
#endregion
#region 初始化A能够变化为哪些dic,B是由哪些dic变来的
for (int i = 0; i < Dict.Length; i++)
{
for (int j = 0; j < A.Length; j++)
{
if (Dict[i].Remove(j, 1) == A.Remove(j, 1))
{
ADic.Add(Dict[i]);
unuseDic.Add(Dict[i], A);
break;
}
}
for (int j = 0; j < A.Length; j++)
{
if (Dict[i].Remove(j, 1) == B.Remove(j, 1))
{
BDic.Add(Dict[i], 1);
break;
}
}
}
#endregion
find(1, false);
for (int i = 0; i < PathString.Count; i++)
{
PathString[i] += "," + B;
}
string[][] result = new string[PathString.Count][];
for (int i = 0; i < PathString.Count; i++)
{
result[i] = PathString[i].Split(',');
}
return result;
代码写的有些啰嗦,未做整理。