单词接龙

题目描述

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例1

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。

示例2

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。

思路

两端搜索。本题是需要从beginWord转换为endWord。上一份笔记严格按照这个要求,进行转换,结果为88ms

本条笔记采用两端搜索对上一份笔记进行了优化。两端搜索也就是说:“一头从beginWord转换为endWord,另外一头从endWord转换为beginWord。”为什么要这么做呢?有什么意义呢?

举个例子:

  • 假设从beginWord转换为endWord,存在于字典中的,(第一个)中间结果有30个。

  • 而,从endWord转换为beginWord,存在于字典中的,(第一个)中间结果只有2个。

  • 那么,很显然。从endWord开始会更快。所以,每次都从个数少的那块开始替换一位。

因此,我们每次都从中间结果少的那一端出发,这样就能剪枝掉很多不必要的搜索过程。

实现1

bool isOneChar(string& word1, string& word2) {
	if (word1.length() != word2.length())
	{
		return false;
	}

	int count = 0;
	int len = word1.length();
	for (int i = 0; i < len; i++)
	{
		if (word1[i] != word2[i])
		{
			count++;
		}
	}

	return count == 1;
}

void getResultWord(string beginWord, string endWord, vector<string>& wordList, vector<string>& vecList, int& minLen){

	if (beginWord == endWord)
	{
		if (vecList.size() < minLen)
		{
			minLen = vecList.size();
		}
	} else if (isOneChar(beginWord, endWord))
	{
		vecList.push_back(endWord);
		if (vecList.size() < minLen)
		{
			minLen = vecList.size();
		}
	} else {

		int startCount = 0;
		int endCount = 0;

		for (int i = 0; i < wordList.size(); i++)
		{
			if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end())
			{
				if(isOneChar(beginWord, wordList[i])) {
					startCount++;
				}
				if (isOneChar(endWord, wordList[i]))
				{
					endCount++;
				}
			}
		}

		if (startCount <= endCount)
		{
			for (int i = 0; i < wordList.size(); i++)
			{
				if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end() && isOneChar(beginWord, wordList[i])) {
					vecList.push_back(wordList[i]);
					getResultWord(wordList[i], endWord, wordList, vecList, minLen);
					vecList.pop_back();
				}
			}
		} else {
			for (int i = 0; i < wordList.size(); i++)
			{
				if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end() && isOneChar(endWord, wordList[i])) {
					vecList.push_back(endWord);
					getResultWord(beginWord, wordList[i], wordList, vecList, minLen);
					vecList.pop_back();
				}
			}
		}


		
	}
}


int ladderLength(string beginWord, string endWord, vector<string>& wordList) {

	if (find(wordList.begin(), wordList.end(), endWord) == wordList.end())
	{
		return 0;
	}

	vector<string> vecList;
	int minLen = INT_MAX;
	vecList.push_back(beginWord);
	getResultWord(beginWord, endWord, wordList, vecList, minLen);

	if (minLen == INT_MAX)
	{
		minLen = 0;
	}

	return minLen;
}

 实现2

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
    unordered_set<string> wordDict(wordList.begin(), wordList.end());
    if (wordDict.find(endWord) == wordDict.end()){
        return 0;
    }
    unordered_set<string> beginSet{beginWord};
    unordered_set<string> endSet{endWord};
    int step = 1;
    for (; !beginSet.empty();){
        unordered_set<string> tempSet;
        ++step;
        for (auto s : beginSet) {
            wordDict.erase(s);
        }
        for (auto s : beginSet) {
            for (int i = 0; i < s.size(); ++i){
                string str = s;
                for (char c = 'a'; c <= 'z'; ++c){
                    str[i] = c;
                    if (wordDict.find(str) == wordDict.end()){
                        continue;
                    }
                    if (endSet.find(str) != endSet.end()){
                        return step;
                    }
                    tempSet.insert(str);
                }
            }
        }
        if (tempSet.size() < endSet.size()){
            beginSet = tempSet;
        } else {
            beginSet = endSet;
            endSet = tempSet;
        }
    }
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值