【golang】leetcode中级-子集&单词搜索

第一题 子集

题目

【golang】leetcode中级-子集&单词搜索_第1张图片

解题思路

长度为n的数组的幂集

首先我们可以想到
长度为零的空数组和长度为一单元素解都一定是数组的幂集

剩下的子集都可以在单一解的基础上组合而成
例如

nums = [1,2,3]
则其多元素解
[1,2]由[1]和[2]组成
[1,3]由[1]和[3]组成
[2,3]由[2]和[3]组成
[1,2,3]长度与nums等长,故只有一种可能

再看看长度为4的情况
nums = [1,2,3,4]
单元素解有[1],[2],[3],[4]
双元素解有[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]
三要素解为
[1,2]+[3]=[1,2,3]
[1,2]+[4]=[1,2,4]
[1,3]+[2]=[1,3,2]
[1,3]+[4]=[1,3,4]
........略
共能得到不同顺序的组合四种
[1,2,3],[1,2,4],[1,3,4],[2,3,4]
其中例如[1,2,3]与[1,3,2]本质上是重复的

这样我们就需要加入一个对其辨别筛选的函数
同时大量重复的计算也占了很大的代价

.

为了减少重复
我们引入一个数组用来存储元素的使用情况
鉴于元素的使用情况只有两种, 使用 或者 不被使用 可以用0或者1来表示
这样存储元素使用情况的数组就变成了一串二进制数
且对应的二进制数正好从 0 到 2^n - 1 ,
这样
我们只需遍历从0到2^n - 1的数,将其二进制表示时数值为1的位加入到数组,就得到了所有不重复的幂集
【golang】leetcode中级-子集&单词搜索_第2张图片

当然

我们也可以考虑标记元素的状态之后再进行递归
【golang】leetcode中级-子集&单词搜索_第3张图片
其中 用剩余元素序列存储元素的使用情况
https://leetcode-cn.com/probl...

代码

func subsets(nums []int) (ans [][]int) {
    n := len(nums)
    for mask := 0; mask < 1<>i&1 > 0 {
                set = append(set, v)
            }
        }
        ans = append(ans,set)
    }
    return
}

复杂度分析

时间复杂度:O(n×2^n)。一共 2^n个状态,每种状态需要 O(n) 的时间来构造子集。

空间复杂度:O(n)。即构造子集使用的临时数组 set 的空间代价。

第二题 单词搜索

题目

【golang】leetcode中级-子集&单词搜索_第4张图片

思路

dfs+回溯
【golang】leetcode中级-子集&单词搜索_第5张图片

另外

同一个单元格内的字母不允许被重复使用。

因此 ,我们需要在使用一个字母之后 将其置为非字母的元素

同时将其存储在一个临时变量

如果递归失败,再将其还原,继续下一次递归查找

代码

func exist(board [][]byte, word string) bool {
    var words []byte
    for _,v:=range word{
        words=append(words,byte(v))
    }
    for i := 0; i < len(board); i++ {
        for j := 0; j < len(board[0]); j++ {
            //从[i,j]这个坐标开始查找
            if dfs(board, words, i, j, 0) {
                return true
            }
        }
    }
    return false
}

func dfs(board [][]byte, word []byte,i int,j int,index int)bool {

    //边界的判断,如果越界直接返回false。index表示的是查找到字符串word的第几个字符,
    if i >= len(board) || i < 0 || j >= len(board[0]) || j < 0 {
        return false
    }

    //如果这个字符不等于board[i][j],说明验证这个坐标路径是走不通的,直接返回false
    if board[i][j] != word[index] {
        return false
    }

    //如果word的每个字符都查找完了,直接返回true
    if index == len(word) - 1 {
        return true
    }

    //把当前坐标的值保存下来,为了在最后复原
    tmp := board[i][j]

    //然后修改当前坐标的值
    board[i][j] = '.'

    //走递归,沿着当前坐标的上下左右4个方向查找
    res := dfs(board, word, i + 1, j, index + 1) || dfs(board, word, i - 1, j, index + 1) || dfs(board, word, i, j + 1, index + 1) || dfs(board, word, i, j - 1, index + 1)

    //递归之后再把当前的坐标复原
    board[i][j] = tmp

    return res
}

结果

【golang】leetcode中级-子集&单词搜索_第6张图片

复杂度分析

复杂度分析

时间复杂度:O(MN⋅4^L),其中 M,N 为网格的长度与宽度,分别对网格的每个点使用一次dfs函
数,但绝大部分情况下调用函数只进行了一次判断 boardi != word[index] 便返回了结
果,很少有极端情况全都是相等的,因此这是一个非常宽松的上界。L 为字符串 word 的长度。dfs每次递归调用四次dfs,刚好搜索到单词的时间复杂度为 O(4^L),而我们要执行 O(MN) 次检查。然而,真正达到L深度的只有成功搜索到单词返回true的一次调用。因此,实际的时间复杂度会远远小于 Θ(MN⋅4^L)。

空间复杂度:O(L)。栈的深度最大为 O(L),每次只声明了临时变量tmp。

你可能感兴趣的:(【golang】leetcode中级-子集&单词搜索)