美文网首页
算法4:搜索

算法4:搜索

作者: HYIndex | 来源:发表于2021-03-18 23:23 被阅读0次

3.1 深度优先DFS

问题1:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。


image.png

Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]

思路:深度优先搜索,从根节点到每个叶子节点的所有路径即结果,深度为子串的长度

示例代码:

var (
    letterMap = []string{
        " ",    //0
        "",     //1
        "abc",  //2
        "def",  //3
        "ghi",  //4
        "jkl",  //5
        "mno",  //6
        "pqrs", //7
        "tuv",  //8
        "wxyz", //9
    }
    res   = []string{}
)

func letterCombinations(digits string) []string {
    if digits == "" {
        return []string{}
    }
    res = []string{}
    dfs(digits, 0, "")
    return res
}

func dfs(digits string, i int, s string) {
    if i == len(digits) {
        res = append(res, s)
        return
    }
    curs := letterMap[digits[i] - '0']
    for _, ch := range curs {
        dfs(digits, i+1, s + string(ch))
    }
}

问题2:给定一个数组,要求在这个数组中找出 k 个数之和为 target 的所有组合。
Input: nums = [1, 0, -1, 0, -2, 2], and target = 0.
Output: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

思路:深度优先搜索,层数为k。注意去重的处理。

示例代码:

import "sort"

var res = [][]int{}

func fourSum(nums []int, target int) [][]int {
    if len(nums) == 0 {
        return [][]int{}
    }
    sort.Ints(nums)
    res = [][]int{}
    r := []int{}
    dfs_sum(nums, 0, r, target)
    return res
}

func dfs_sum(nums []int, i int, r []int, target int)  {
    if i == 4 || 0 == len(nums) {
        if len(r) >= 4 && r[0] + r[1] + r[2] + r[3] == target {
            res = append(res, []int{r[0], r[1], r[2], r[3]})
        }
        return
    }
    for j := 0; j < len(nums); j++ {
        if j > 0 && nums[j] == nums[j-1] {
            continue
        }
        r = append(r, nums[j])
        dfs_sum(nums[j+1:], i + 1, r, target)
        if len(r) >= 1 {
            r = r[:len(r)-1]
        }
    }
}

3.2 宽度优先搜索 BFS

宽度优先搜索通常用在求最短路径,按层遍历,第一次满足要求的层数就是最短的路径。BFS需要借助队列来保存每一层的节点,访问过的节点要做标记避免重复访问。

3.2.1 二进制矩阵中的最短路径

LeetCode No.1091

题目描述:给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:
1 路径途经的所有单元格都的值都是 0 。
2 路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
畅通路径的长度 是该路径途经的单元格总数。

思路:从左上角开始,遍历所有可以走的方向,BFS方式求到达右下角的最小层数。

示例代码:

type Pos struct {
    x, y int
}

func shortestPathBinaryMatrix(grid [][]int) int {
    if len(grid) == 0 || len(grid[0]) == 0 {
        return -1
    }
    M, N := len(grid), len(grid[0])
    direction := []Pos{{1, -1}, {1, 0}, {1, 1}, {0, -1}, {0, 1}, {-1, -1}, {-1, 0}, {-1, 1}}
    Q := list.New()
    // 根节点入队
    Q.PushBack(Pos{0, 0})
    path_len := 0
    for Q.Len() != 0 {
        // 保存当前层的长度
        level_size := Q.Len()
        path_len++
        // 依次处理当前层的所有节点
        for i := 0; i < level_size; i++ {
            cur_pos := Q.Front().Value.(Pos)
            Q.Remove(Q.Front())
            if grid[cur_pos.x][cur_pos.y] == 1 {
                continue
            }
            // 如果到达右下角返回结果
            if cur_pos.x == (M - 1) && cur_pos.y == (N - 1) {
                return path_len
            }
            // 访问过的位置标记为1
            grid[cur_pos.x][cur_pos.y] = 1
            // 遍历所有能走的方向,加入队列
            for _, dr := range direction {
                nx, ny := cur_pos.x + dr.x, cur_pos.y + dr.y
                if nx < 0 || nx >= M || ny < 0 || ny >= N {
                    continue
                }
                Q.PushBack(Pos{nx, ny})
            }
        }
    }
    return -1
}

3.2.2 完全平方数

LeetCode No.279

题目描述:给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

思路:转化为BFS问题模型,从1到根号n的所有平方数(1,4,9...)为每次所有可能的路径。从n开始遍历,当n=0时即为结果。

示例代码:

func numSquares(n int) int {
    numsqs := []int{}
    for i, ii := 1, 1; ii <= n; i, ii = i + 1, (i + 1) * (i + 1){
        numsqs = append(numsqs, ii)
    }
    mark := map[int]bool{}
    Q := list.New()
    Q.PushBack(n)
    mark[n] = true
    ans := 0
    for Q.Len() != 0 {
        lv_size := Q.Len()
        ans++
        for i := 0; i < lv_size; i++ {
            cur := Q.Front().Value.(int)
            Q.Remove(Q.Front())
            for _, nq := range numsqs {
                if cur == nq {
                    return ans
                }
                if cur < nq {
                    break
                }
                if mark[cur - nq] {
                    continue
                }
                mark[cur - nq] = true
                Q.PushBack(cur - nq)
            }
        }
    }
    return n
}

相关文章

  • 算法4:搜索

    3.1 深度优先DFS 问题1:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。给出数字到字母的...

  • 局部搜索算法简介

    局部搜索算法 目录: 1、数学定义 2、过程描述 3、算法简介 4、总结 1、数学定义 局部搜索是解决最优化问题的...

  • 算法-二分搜索算法

    算法:二分搜索算法(折半查找算法)时间复杂度: 二分搜索算法概述 二分搜索算法伪代码 二分搜索算法实现 二分搜索算...

  • 数据结构与算法--BFS&DFS

    “搜索”算法 深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构。 图上的搜索算法就是,在图中找出从一个...

  • 最佳优先搜索算法(Best-First-Search)

    1、算法原理 最佳优先搜索算法是一种启发式搜索算法(Heuristic Algorithm),其基于广度优先搜索算...

  • 算法(三):图解广度优先搜索算法

    算法简介 广度优先搜索算法(Breadth First Search),又称为"宽度优先搜索"或"横向优先搜索",...

  • 变邻域搜索(VNS)

    1 局部搜索 1.1 局部搜索 局部搜索算法是对一类算法的统称,符合其框架的算法很多,比如爬山法、模拟退火算法和禁...

  • 数据结构与算法--深度和广度优先搜索

    什么是“搜索”算法? 算法是作用于具体数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构...

  • A*算法 和 最佳优先搜索算法(Best-First-Searc

    BFS算法 算法原理 最佳优先搜索算法是一种启发式搜索算法(Heuristic Algorithm),其基于广度优...

  • A* 搜索算法

    启发式搜索算法 要理解 A* 搜寻算法,还得从启发式搜索算法开始谈起。所谓启发式搜索,就在于当前搜索结点往下选择下...

网友评论

      本文标题:算法4:搜索

      本文链接:https://www.haomeiwen.com/subject/apbzfltx.html