Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
For example,
Given:
start ="hit"
end ="cog"
dict =["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
- All words have the same length.
- All words contain only lowercase alphabetic characters.
给出了一个开始和一个结束,还有一个数组,每次变更一个字母,用数组中的词把首尾链接起来,吐出最短的列表。
来更新这个问题了,刚刚想明白BFS要比DFS对于这个题更优,由于是去最小的,所以采用BFS。
今天太晚了,明天来更新。大概的思路和求最短长度一样,使用bfs把这个模型转化成一个有向图,从开头指向结尾,然后获取所有的分组就可以了。
<?php
/**
* Class Node
* 定义一个存储节点的类
* 要把图构造处理必须从后往前搜索
*/
class Node {
public $val;
public $arrNode = array();
public function __construct($val) {
$this->val = $val;
}
}
function onlyOneStr($word1, $word2) {
$noEqualNum = 0;
$num = strlen($word1);
for ($i = 0; $i < $num; $i ++) {
if ($word1[$i] !== $word2[$i]) {
$noEqualNum ++;
}
}
if ($noEqualNum == 1) {
return true;
} else {
return false;
}
}
function findLadders($arrWord, $startWord, $stopWord) {
$arrNode = array();//这个数据结构应该用的是队列,先进先出
$objNode = new Node($stopWord);
array_push($arrNode, $objNode);//最后一层
$objStartNode = new Node($startWord);
$getStartFlag = 0;
$arrWordNode = array();
foreach ($arrWord as $value) {
$arrWordNode[$value] = new Node($value);
}
while (!empty($arrNode)) {
$num = count($arrNode);//第n层的节点个数
foreach ($arrNode as $test) {
print $test->val;
}
print $num."\n";
$arrUnsetKey = array();
while ($num > 0) {//当这一层还有节点数的时候,继续获取节点
$node = array_shift($arrNode);
//判断现在是否可以连上结尾了
if (onlyOneStr($node->val, $startWord)) {
$objStartNode->arrNode[] = $node;
$getStartFlag = 1;
}
$num --;
//获取这个节点的所有下层节点
foreach ($arrWordNode as $key => $item) {
//如果属于下层节点
if (onlyOneStr($item->val ,$node->val)) {
$item->arrNode[] = $node;
if (!in_array($key, $arrUnsetKey)) {
$arrUnsetKey[] = $key;
array_push($arrNode, $item);
}
}
}
}
//去掉已经确定层数的点
foreach ($arrUnsetKey as $key) {
unset($arrWordNode[$key]);
}
//开始到下一层的计算
if ($getStartFlag == 1) {
break;
}
}
return $objStartNode;
}
function getRet($node, &$arrRet, &$arrTmp) {
array_push($arrTmp, $node->val);
if (empty($node->arrNode)) {
$arrRet[] = $arrTmp;
}
foreach ($node->arrNode as $nextNode) {
getRet($nextNode, $arrRet, $arrTmp);
}
array_pop($arrTmp);
}
$arrWord = ["hot","dot","dog","lot","log"];
$startWord = "hit";
$stopWord = "cog";
$ret = findLadders($arrWord, $startWord, $stopWord);
if ($ret != null) {
//遍历图结构
$arrRet = array();
$arrTmp = array();
getRet($ret, $arrRet, $arrTmp);
print json_encode($arrRet);
}
看很多人讨论超时的问题,由于没有平台ac,所以只能把一种思路写在这里了,体会不到那种思路是对的,但是要优化的糟心和快感了。
下面是DFS的方法:
<?php
function findLadders($arrWord, $startWord, $stopWord, &$arrRet, &$arrTmp) {
if (empty($arrWord) && !onlyOneStr($startWord, $stopWord)) {
return;
}
array_push($arrTmp, $startWord);
if (onlyOneStr($startWord, $stopWord)) {
array_push($arrTmp, $stopWord);
print '接上了'.$startWord.$stopWord."\n";
$arrRet[] = $arrTmp;
array_pop($arrTmp);
}
foreach ($arrWord as $key => $item) {
//如果可以和开始匹配上,则更新开始继续往下找
if (onlyOneStr($item, $startWord)) {
unset($arrWord[$key]);
$arrNewWord = $arrWord;
findLadders($arrNewWord, $item, $stopWord, $arrRet, $arrTmp);
$arrWord[$key] = $item;
}
}
array_pop($arrTmp);
}
function onlyOneStr($word1, $word2) {
$noEqualNum = 0;
$num = strlen($word1);
for ($i = 0; $i < $num; $i ++) {
if ($word1[$i] !== $word2[$i]) {
$noEqualNum ++;
}
}
if ($noEqualNum == 1) {
return true;
} else {
return false;
}
}
$arrWord = ["hot","dot","dog","lot","log"];
$startWord = "hit";
$stopWord = "cog";
$arrRet = array();
$arrTmp = array();
findLadders($arrWord, $startWord, $stopWord, $arrRet, $arrTmp);
foreach ($arrRet as $key => $item) {
$num = count($item);
$arrIndex[$num][] = $key;
if (!isset($minNum)) {
$minNum = $num;
continue;
}
if ($minNum > $num) {
$minNum = $num;
}
}
foreach ($arrIndex[$minNum] as $item) {
$arrOutput[] = $arrRet[$item];
}
print json_encode($arrOutput);