《leetcode-php》给出头尾和字典,求拼接的最短路径

本文探讨了如何使用广度优先搜索(BFS)解决单词转换问题,即寻找从一个单词到另一个单词的最短路径,每次仅改变一个字母,并确保每一步都形成一个有效的单词。通过将问题建模为图的遍历,文章详细介绍了BFS算法的实现过程,包括节点定义、图的构建以及最短路径的查找。

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

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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值