剑指offer 专项突破版 108、单词演变

题目链接

思路
  • 这种可以抽象成最短路径问题 每个单词是一个结点,如果两个单词只有一个字母的差距,那么他们之间有一条边,最终的目的是寻找开始单词和结束单词的最短路径
  • 因此这个题可以用BFS来解决 通过用队列辅助BFS 每一轮遍历结束后都给count++ 这样直到某一次队列中出现了target,就算是最终找到了
  • 因此我们可以用一个函数来获取某个单词可以转换为的所有的单词,也就是说在获取所有和该结点相邻的结点,注意这个函数要返回所有相邻的结点,不管是否遍历过
class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
		
        Queue<String> queue1 = new LinkedList<>() , queue2 = new LinkedList<>();
		Set<String> notVisited = new HashSet(wordList);
        int min = 1;
		queue1.offer(beginWord);
        
        while(!queue1.isEmpty()){
            String word = queue1.poll();
			if(word.equals(endWord))
            	return min;

            List<String> neighbors = getNeighbors(word);

            for(String neighbor :neighbors){
				if(notVisited.contains(neighbor)){
                    notVisited.remove(neighbor);
                    queue2.offer(neighbor);
                }
            }

            if(queue1.isEmpty()){
                queue1 = queue2;
                queue2 = new LinkedList<>();
                min++;
            }
        }

        return 0;
    }

	
    // 返回所有的和word相差一个字母的单词
    private List<String> getNeighbors(String word){
		List<String> neighbors = new ArrayList<>();
		char[] words = word.toCharArray();
		
        for(int i = 0 ; i < words.length ; i++){
            char oldChar = words[i];
            for(int j = 0 ; j < 26 ; j++){
            	char newChar = (char)('a' + j);
                if(newChar != oldChar){
                    words[i] = newChar;
                    neighbors.add(new String(words));
                }
                words[i] = oldChar;
            }
        }

        return neighbors;
    }
}
  • 在此基础上可以有一个优化~ 就是双向奔赴!
  • 上一种做法是用一个队列 从开始单词结点搜索 直到搜索到target结点
  • 现在我们可以用两个集合来保存,一开始set1存开始结点 set2存结束结点,然后把set1当上一种做法的队列使用
  • 每次在开始遍历set找临近结点时,选择set1和set2中小的那个遍历~ 如果某一步出现了另一个集合中的元素,那么就说明已经找到啦!
class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
		
		Set<String> notVisited = new HashSet(wordList),set1 = new HashSet<>(),set2 = new HashSet<>(),set3;
		set1.add(beginWord);
        set2.add(endWord);
        int min = 2;

        if(!notVisited.contains(endWord))
            return 0;

        while(!set1.isEmpty() && !set2.isEmpty()){
            if(set1.size() > set2.size()){
                set3 = set1;
                set1 = set2;
                set2 = set3;  
            }

            set3 = new HashSet();
            for(String word: set1){
                List<String> neighbors = getNeighbors(word);
                for(String neighbor : neighbors){
                    if(set2.contains(neighbor))
                        return min;
                    if(notVisited.contains(neighbor)){
                        notVisited.remove(neighbor);
                        set3.add(neighbor);
                    }
                }
            }

            set1 = set3;
            min++;
        }

        return 0;
    }

	
    // 返回所有的和word相差一个字母的单词
    private List<String> getNeighbors(String word){
		List<String> neighbors = new ArrayList<>();
		char[] words = word.toCharArray();
		
        for(int i = 0 ; i < words.length ; i++){
            char oldChar = words[i];
            for(int j = 0 ; j < 26 ; j++){
            	char newChar = (char)('a' + j);
                if(newChar != oldChar){
                    words[i] = newChar;
                    neighbors.add(new String(words));
                }
                words[i] = oldChar;
            }
        }

        return neighbors;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值