Golang每日一练(leetDay0026)

简介: Golang每日一练(leetDay0026)

76. 最小覆盖子串 Minimum Window Substring


给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""


注意:


   对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

   如果 s 中存在这样的子串,我们保证它是唯一的答案。


示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"

输出:"BANC"


示例 2:

输入:s = "a", t = "a"

输出:"a"


示例 3:

输入: s = "a", t = "aa"

输出: ""

解释: t 中两个字符 'a' 均应包含在 s 的子串中,

因此没有符合条件的子字符串,返回空字符串。


提示:

   1 <= s.length, t.length <= 10^5

   s 和 t 由英文字母组成

进阶:你能设计一个在 o(n) 时间内解决此问题的算法吗?

代码1: 滑动窗口

package main
import (
  "fmt"
)
func minWindow(s string, t string) string {
  if len(s) < len(t) {
    return ""
  }
  need := make(map[byte]int) // 存储t中每个字符的出现次数
  for i := 0; i < len(t); i++ {
    need[t[i]]++
  }
  left, right := 0, 0  // 滑动窗口的左右指针
  count := len(t)      // 记录滑动窗口中还需要的字符数
  minLen := len(s) + 1 // 记录最小覆盖子串的长度
  start := 0           // 记录最小覆盖子串的起始位置
  for right < len(s) {
    // 当右指针指向的字符是需要的字符,count减一
    if _, ok := need[s[right]]; ok {
      if need[s[right]] > 0 {
        count--
      }
      need[s[right]]--
    }
    right++
    // 当count为0时,说明滑动窗口中已经包含t中的所有字符
    for count == 0 {
      // 如果当前的覆盖子串更小,则更新最小覆盖子串的长度和起始位置
      if right-left < minLen {
        minLen = right - left
        start = left
      }
      // 当左指针指向的字符是需要的字符,count加一
      if _, ok := need[s[left]]; ok {
        need[s[left]]++
        if need[s[left]] > 0 {
          count++
        }
      }
      left++
    }
  }
  if minLen == len(s)+1 {
    return ""
  }
  return s[start : start+minLen]
}
func main() {
  fmt.Println(minWindow("ADOBECODEBANC", "ABC"))
  fmt.Println(minWindow("a", "a"))
  fmt.Println(minWindow("a", "aa"))
}

代码2:双指针

package main
import (
  "fmt"
)
func minWindow(s string, t string) string {
  if len(s) < len(t) {
    return ""
  }
  need := make(map[byte]int) // 存储t中每个字符的出现次数
  for i := 0; i < len(t); i++ {
    need[t[i]]++
  }
  left, right := 0, 0  // 滑动窗口的左右指针
  count := len(t)      // 记录滑动窗口中还需要的字符数
  minLen := len(s) + 1 // 记录最小覆盖子串的长度
  start := 0           // 记录最小覆盖子串的起始位置
  for right < len(s) {
    // 当右指针指向的字符是需要的字符,count减一
    if _, ok := need[s[right]]; ok {
      if need[s[right]] > 0 {
        count--
      }
      need[s[right]]--
    }
    right++
    // 当count为0时,说明滑动窗口中已经包含t中的所有字符
    for count == 0 {
      // 如果当前的覆盖子串更小,则更新最小覆盖子串的长度和起始位置
      if right-left < minLen {
        minLen = right - left
        start = left
      }
      // 当左指针指向的字符是需要的字符,count加一
      if _, ok := need[s[left]]; ok {
        need[s[left]]++
        if need[s[left]] > 0 {
          count++
        }
      }
      left++
    }
  }
  if minLen == len(s)+1 {
    return ""
  }
  return s[start : start+minLen]
}
func main() {
  fmt.Println(minWindow("ADOBECODEBANC", "ABC"))
  fmt.Println(minWindow("a", "a"))
  fmt.Println(minWindow("a", "aa"))
}

输出:

BANC

a

//空行


77. 组合 Combinations


给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。


你可以按 任何顺序 返回答案。


示例 1:

输入:n = 4, k = 2

输出:

[

 [2,4],

 [3,4],

 [2,3],

 [1,2],

 [1,3],

 [1,4],

]


示例 2:

输入:n = 1, k = 1

输出:[[1]]

提示:

   1 <= n <= 20

   1 <= k <= n


代码1: 回溯法


package main
import (
  "fmt"
)
func combine(n int, k int) [][]int {
  var res [][]int               // 存储所有组合
  var path []int                // 存储当前组合
  var backtrack func(start int) // 定义回溯函数
  backtrack = func(start int) {
    if len(path) == k { // 当前组合长度为k,加入结果中
      temp := make([]int, k)
      copy(temp, path)
      res = append(res, temp)
      return
    }
    for i := start; i <= n; i++ { // 枚举可选的数字
      path = append(path, i)    // 加入当前数字
      backtrack(i + 1)          // 从i+1开始枚举下一个数字
      path = path[:len(path)-1] // 撤销当前数字
    }
  }
  backtrack(1) // 从1开始枚举第一个数字
  return res
}
func main() {
  fmt.Println(combine(4, 2))
  fmt.Println(combine(1, 1))
}

输出:

[[1 2] [1 3] [1 4] [2 3] [2 4] [3 4]]

[[1]]

代码2: 枚举法

package main
import (
  "fmt"
)
func combine(n int, k int) [][]int {
  var res [][]int                   // 存储所有组合
  for i := 0; i < 1<<uint(n); i++ { // 枚举所有二进制数
    var path []int            // 存储当前组合
    for j := 1; j <= n; j++ { // 枚举n个数字
      if i&(1<<uint(j-1)) != 0 { // 当前数字被选中
        path = append(path, j)
      }
    }
    if len(path) == k { // 当前组合长度为k,加入结果中
      res = append(res, path)
    }
  }
  return res
}
func main() {
  fmt.Println(combine(4, 2))
  fmt.Println(combine(1, 1))
}



78. 子集 Subsets


给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。


示例 1:

输入:nums = [1,2,3]

输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]


示例 2:

输入:nums = [0]

输出:[[],[0]]


提示:

   1 <= nums.length <= 10

   -10 <= nums[i] <= 10


   nums 中的所有元素 互不相同


代码1:回溯法

go

输出:

[[] [1] [1 2] [1 2 3] [1 3] [2] [2 3] [3]]

[[] [0]]

代码2:

package main
import (
  "fmt"
)
func subsets(nums []int) [][]int {
  var res [][]int                  // 存储所有子集
  res = append(res, []int{})       // 初始为空集
  for i := 0; i < len(nums); i++ { // 枚举每个数字
    for _, sub := range res { // 枚举已有的子集
      temp := append([]int{}, sub...)
      temp = append(temp, nums[i]) // 加入当前数字
      res = append(res, temp)      // 加入新的子集
    }
  }
  return res
}
func main() {
  nums := []int{1, 2, 3}
  fmt.Println(subsets(nums))
  nums = []int{0}
  fmt.Println(subsets(nums))
}



输出:

[[] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]]

[[] [0]]

代码3: 位运算

package main
import (
  "fmt"
)
func subsets(nums []int) [][]int {
  var res [][]int // 存储所有子集
  n := len(nums)
  for i := 0; i < (1 << n); i++ { // 枚举所有二进制数
    var path []int           // 存储当前子集
    for j := 0; j < n; j++ { // 枚举n个数字
      if i&(1<<j) != 0 { // 当前数字被选中
        path = append(path, nums[j])
      }
    }
    res = append(res, path) // 加入当前子集
  }
  return res
}
func main() {
  nums := []int{1, 2, 3}
  fmt.Println(subsets(nums))
  nums = []int{0}
  fmt.Println(subsets(nums))
}



输出:

[[] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]]

[[] [0]]



目录
相关文章
|
Shell Linux 算法
Shell编程——弱数据类型的脚本语言快速入门指南
Shell编程——弱数据类型的脚本语言快速入门指南
182 0
Shell编程——弱数据类型的脚本语言快速入门指南
|
Go Linux Shell
Linux 终端命令之文件浏览(2) more
Linux 终端命令之文件浏览(2) more
136 0
Linux 终端命令之文件浏览(2) more
|
Shell 机器学习/深度学习 Linux
Linux 终端操作命令(2)内部命令
Linux 终端操作命令(2)内部命令
243 0
Linux 终端操作命令(2)内部命令
|
C++ 算法 存储
力扣 C++|一题多解之动态规划专题(2)
力扣 C++|一题多解之动态规划专题(2)
193 0
力扣 C++|一题多解之动态规划专题(2)
|
Python 索引
Python Numpy入门基础(一)创建数组
Python Numpy入门基础(一)创建数组
225 0
Python Numpy入门基础(一)创建数组
|
Java 容器 程序员
Java语言程序设计试卷6套
Java语言程序设计试卷6套
1121 0
Java语言程序设计试卷6套
|
Java Go C++
Golang每日一练(leetDay0120) 反转字符串中的元音字母、前K个高频元素
Golang每日一练(leetDay0120) 反转字符串中的元音字母、前K个高频元素
188 0
Golang每日一练(leetDay0120) 反转字符串中的元音字母、前K个高频元素
|
Go 机器学习/深度学习 Rust
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
279 0
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
|
16天前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
68 1
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
522 4
Golang语言之管道channel快速入门篇

热门文章

最新文章

推荐镜像

更多