• 【LeetCode】BFS 总结


    BFS(广度优先搜索) 常用来解决最短路径问题。

    第一次便利到目的节点时,所经过的路径是最短路径。

    几个要点:

    • 只能用来求解无权图的最短路径问题
    • 队列:用来存储每一层便利得到的节点
    • 标记:对于遍历过的结点,应将其标记,以防重复访问

    279. 完全平方数

    题目描述

    给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

    示例 1:

    输入: n = 12
    输出: 3 
    解释: 12 = 4 + 4 + 4.
    

    示例 2:

    输入: n = 13
    输出: 2
    解释: 13 = 4 + 9.
    

    解题思路

    从 0 到 n 有 n+1 个整数,把这 n+1 个整数看做是节点。如果两个节点之间的差是一个完全平方数,我们就说这两个节点之间是有连接的。通过这个思路我们就可以建立一张图。

    找到 n 到 0 的最短路径,我们就找到了 n 至少需要几个完全平方数组成。

    public int numSquares(int n) {
        List<Integer> squares = generateSquares(n);
        Queue<Integer> queue = new LinkedList<>();
        boolean[] marked = new boolean[n + 1];
        queue.add(n);
        marked[n] = true;
        int level = 0;
        while(!queue.isEmpty()){
            int size = queue.size();
            level++;
            while(size-- >0){
                int cur = queue.poll();
                for (int s : squares){
                    int next = cur - s;
                    if (next < 0)
                        break;
                    if (next == 0)
                        return level;
                    if (marked[next])
                        continue;
                    queue.add(next);
                    marked[next] = true;
                }
            }
        }
        return n;
    }
    
    private List<Integer> generateSquares(int n){
        List<Integer> squares = new ArrayList<>();
        int square = 1;
        int diff = 3;
        while(square <= n){
            squares.add(square);
            square += diff;
            diff += 2;
        }
    
        return squares;
    }
    

    127. 单词接龙

    题目描述

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

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

    说明:

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

    示例 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" 不在字典中,所以无法进行转换。
    

    解题思路

    如果两个单词在对应位置上只有一个字母是不同的,我们就说这两个单词是连接的。按照这个定义,我们可以建立一张图。对这张图进行 BFS 就可以找到从 beginWordendWord 的最短转换序列的长度。

    注意,字典中是不包含beginWord的,我们需要将其手动加入再建立图。

    public int ladderLength (String beginWord, String endWord, List<String> wordList) {
        wordList.add(beginWord);  // 手动加入起始单词
        int N  = wordList.size();
        int start = N -1;
        int end = 0;
        while (end < N && !wordList.get(end).equals(endWord)) {
            end++;
        }
        if (end == N) // 目标单词不在字典中
            return 0;
        List<Integer>[] graphic = buildGraphic(wordList);
        return getShortestPath(graphic,start,end);
    }
    
    private List<Integer>[] buildGraphic (List<String> wordList) {
        int N = wordList.size();
        List<Integer>[] graphic = new List[N];
        for (int i = 0; i < N; i++) {
            graphic[i] = new ArrayList<>();
            for (int j = 0; j < N; j++) {
                if (isConnect(wordList.get(i), wordList.get(j))) {
                    graphic[i].add(j);
                }
            }
        }
        return graphic;
    }
    
    private boolean isConnect (String s1, String s2) {
        int diff = 0;
        for (int i = 0; i < s1.length() && diff <= 1; i++) {
            if (s1.charAt(i) != s2.charAt(i)) {
                diff++;
            }
        }
        return diff == 1;
    }
    
    private int getShortestPath (List<Integer>[] graphic, int start, int end) {
        Queue<Integer> queue = new LinkedList<>();
        boolean[] marked = new boolean[graphic.length];
        queue.add(start);
        marked[start] = true;
        int pathLength = 1;
        while (!queue.isEmpty()) {
            int size = queue.size();
            pathLength++;
            while (size-- > 0) {
                int cur = queue.poll();
                for (int next : graphic[cur]) {
                    if (next == end) {
                        return pathLength;
                    }
                    if (marked[next]) {
                        continue;
                    }
                    queue.add(next);
                    marked[next] = true;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Sqlserver中的触发器
    Memcache在.Net中的使用
    Sqlserver中的储存过程
    Ado.NET基础必备
    MVC项目报错 ”基础提供程序在 Open 上失败”
    【Darwin学习笔记】之获取系统处理器数量的方法
    Wireshark抓包工具--TCP数据包seq ack等解读
    TCP:WireShark分析,序列号Seq和确认号Ack
    【Darwin学习笔记】之TaskThread
    boost::asio::io_context类
  • 原文地址:https://www.cnblogs.com/yuzhenzero/p/10730860.html
Copyright © 2020-2023  润新知