广度优先搜索(BFS与双向BFS)_"127. Word Ladder"为例解法详解

概述

BFS最简单的方式如下:

BFS()
{
	初始化队列
	while(队列不为空且未找到目标节点)
	{
		取队首节点扩展,并将扩展出的非重复节点放入队尾;
	}
}

示例题简介

下面以一经典LeetCode(题号:172)为例看一下BFS的写法。
给定一个其实单词和一个终止单词,从起始单词出发,每次在所给单词列表中找一个单词有且只有一个字母与当前单词不同,如果能到达终止单词,返回最短路径的长度。

BFS

    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
    	//unordered_set是hash表实现,用于快速查字符串。
        unordered_set<string> dict(wordList.begin(), wordList.end());
        if (dict.find(endWord) == dict.end()) {
            return 0;
        }
        queue<string> q;
        //初始化队列,将第一个结点加入。
        q.push(beginWord);
        int step = 1;
        while(!q.empty()) {
        	//q存有当前层级的所有结点,因为上此while循环中还要加入下一层的结点,所以在这里要先保当前层结点的数目保存下来,一次while循环只遍历一层结点。
            int n = q.size();
            //遍历当前层
            for(int i = 0; i < n; i++) {
           		// 取队首节点扩展
                string word = q.front();
                q.pop();
                //找到目前字符串则直接返回
                if (word == endWord) {
                    return step;
                }
                //访问过的结点标记一下,这里是直接删除。
                dict.erase(word);
                //找到可变一个字符的单词
                for(int j = 0; j < word.size(); j++) {
                    char oldC = word[j];
                    for(char c = 'a'; c <= 'z'; c++) {
                        word[j] = c;
                        if (dict.find(word) != dict.end()) {
                        	//加入下一层结点
                            q.push(word);
                        }
                    }
                    //restore
                    word[j] = oldC;
                }
            }
            //层级数+1
            step++;
        }
        //not found
        return 0;
    }

双向BFS

双向BFS是BFS的扩展,指从起点和终点同时搜索,直接两者有交点,表明搜索成功。
BFS搜索过程示例(与当前题输入/输出无关):
在这里插入图片描述
双向BFS搜索过程示例(与当前题输入/输出无关),可以很明显的看到减少了起码一半的时间。以当前题来看是(1372 ms->44ms)的差距,差距非常明显。
在这里插入图片描述

    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //双向BFS
        unordered_set<string> dict(wordList.begin(), wordList.end()), head, tail;
        if (dict.find(endWord) == dict.end()) {
            return 0;
        }
        head.insert(beginWord);
        tail.insert(endWord);
        int step = 2;
        while(!head.empty() && !tail.empty()) {
            //保持两边队列大小平衡,有更好的搜索效果。
            if (head.size() > tail.size()) {
                swap(head, tail);
            }
            //保存下一层结点
            unordered_set<string> nextLevel;
            //把当前层结点(head)遍历完
            for(auto it = head.begin(); it != head.end(); ++it) {
                string word = *it;
                //word在加入前已经检查过不是交点,直接去搜索下一层结点(可变一个字符的单词)
                for(int j = 0; j < word.size(); j++) {
                    char oldC = word[j];
                    for(char c = 'a'; c <= 'z'; c++) {
                        word[j] = c;
                        //查看与另一队列是否有交点
                        if (tail.find(word) != tail.end()) {
                            return step;
                        }
                        if (dict.find(word) != dict.end()) {
                            dict.erase(word);
                            nextLevel.insert(word);
                        }
                    }
                    //restore
                    word[j] = oldC;
                }
            }
            swap(head, nextLevel);
            step++;
        }
        //not found
        return 0;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值