> 文章列表 > Golang每日一练(leetDay0033)

Golang每日一练(leetDay0033)

Golang每日一练(leetDay0033)

目录

97. 交错字符串 Interleaving String  🌟🌟

98. 验证二叉搜索树 Validate Binary Search Tree  🌟🌟

99. 恢复二叉搜索树 Recover Binary Search Tree  🌟🌟

🌟 每日一练刷题专栏 🌟

Golang每日一练 专栏

Python每日一练 专栏

C/C++每日一练 专栏

Java每日一练 专栏


97. 交错字符串 Interleaving String

给定三个字符串 s1s2s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。

两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:

  • s = s1 + s2 + ... + sn
  • t = t1 + t2 + ... + tm
  • |n - m| <= 1
  • 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + ... 或者 t1 + s1 + t2 + s2 + t3 + s3 + ...

注意:a + b 意味着字符串 a 和 b 连接。

示例 1:

输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出:true

示例 2:

输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出:false

示例 3:

输入:s1 = "", s2 = "", s3 = ""
输出:true

提示:

  • 0 <= s1.length, s2.length <= 100
  • 0 <= s3.length <= 200
  • s1s2、和 s3 都由小写英文字母组成

进阶:您能否仅使用 O(s2.length) 额外的内存空间来解决它?

代码1:动态规划

package mainimport ("fmt"
)func isInterleave(s1 string, s2 string, s3 string) bool {if len(s1)+len(s2) != len(s3) {return false}dp := make([][]bool, len(s1)+1)for i := range dp {dp[i] = make([]bool, len(s2)+1)}dp[0][0] = truefor i := 1; i <= len(s1); i++ {dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1]}for j := 1; j <= len(s2); j++ {dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1]}for i := 1; i <= len(s1); i++ {for j := 1; j <= len(s2); j++ {if s1[i-1] == s3[i+j-1] {dp[i][j] = dp[i][j] || dp[i-1][j]}if s2[j-1] == s3[i+j-1] {dp[i][j] = dp[i][j] || dp[i][j-1]}}}return dp[len(s1)][len(s2)]
}func main() {s1 := "aabcc"s2 := "dbbca"s3 := "aadbbcbcac"fmt.Println(isInterleave(s1, s2, s3))s1 = "aabcc"s2 = "dbbca"s3 = "aadbbbaccc"fmt.Println(isInterleave(s1, s2, s3))s1 = ""s2 = ""s3 = ""fmt.Println(isInterleave(s1, s2, s3))
}

输出:

true
false
true

代码2:广度优先搜索

package mainimport ("fmt"
)func isInterleave(s1 string, s2 string, s3 string) bool {if len(s1)+len(s2) != len(s3) {return false}queue := [][]int{{0, 0}}visited := make([][]bool, len(s1)+1)for i := range visited {visited[i] = make([]bool, len(s2)+1)}for len(queue) > 0 {i, j := queue[0][0], queue[0][1]queue = queue[1:]if visited[i][j] {continue}visited[i][j] = trueif i == len(s1) && j == len(s2) {return true}if i < len(s1) && s1[i] == s3[i+j] {queue = append(queue, []int{i + 1, j})}if j < len(s2) && s2[j] == s3[i+j] {queue = append(queue, []int{i, j + 1})}}return false
}func main() {s1 := "aabcc"s2 := "dbbca"s3 := "aadbbcbcac"fmt.Println(isInterleave(s1, s2, s3))s1 = "aabcc"s2 = "dbbca"s3 = "aadbbbaccc"fmt.Println(isInterleave(s1, s2, s3))s1 = ""s2 = ""s3 = ""fmt.Println(isInterleave(s1, s2, s3))
}

98. 验证二叉搜索树 Validate Binary Search Tree

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:root = [2,1,3]
输出:true

示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 10^4] 内
  • -2^31 <= Node.val <= 2^31 - 1

代码1:

package mainimport ("fmt"
)const null = -1 << 31type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}func isValidBST(root *TreeNode) bool {var pre *TreeNodereturn validate(root, &pre)
}func validate(node *TreeNode, pre **TreeNode) bool {if node == nil {return true}if !validate(node.Left, pre) {return false}if *pre != nil && node.Val <= (*pre).Val {return false}*pre = nodereturn validate(node.Right, pre)
}func buildTree(nums []int) *TreeNode {if len(nums) == 0 {return nil}root := &TreeNode{Val: nums[0]}Queue := []*TreeNode{root}idx := 1for idx < len(nums) {node := Queue[0]Queue = Queue[1:]if nums[idx] != null {node.Left = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Left)}idx++if idx < len(nums) && nums[idx] != null {node.Right = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Right)}idx++}return root
}func (root *TreeNode) LevelOrder() []int {var res []intif root == nil {return res}Queue := []*TreeNode{root}for len(Queue) > 0 {cur := Queue[0]Queue = Queue[1:]res = append(res, cur.Val)if cur.Left != nil {Queue = append(Queue, cur.Left)}if cur.Right != nil {Queue = append(Queue, cur.Right)}}return res
}func main() {nums := []int{2, 1, 3}root := buildTree(nums)fmt.Println(isValidBST(root))nums = []int{5, 1, 4, null, null, 3, 6}root = buildTree(nums)fmt.Println(isValidBST(root))nums = []int{3, 1, 5, null, null, 4, 6}root = buildTree(nums)fmt.Println(isValidBST(root))
}

输出:

true
false
true

代码2: 递归法

package mainimport ("fmt"
)const null = -1 << 31type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}func isValidBST(root *TreeNode) bool {return validate(root, nil, nil)
}func validate(node *TreeNode, min *int, max *int) bool {if node == nil {return true}if (min != nil && node.Val <= *min) || (max != nil && node.Val >= *max) {return false}return validate(node.Left, min, &node.Val) && validate(node.Right, &node.Val, max)
}func buildTree(nums []int) *TreeNode {if len(nums) == 0 {return nil}root := &TreeNode{Val: nums[0]}Queue := []*TreeNode{root}idx := 1for idx < len(nums) {node := Queue[0]Queue = Queue[1:]if nums[idx] != null {node.Left = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Left)}idx++if idx < len(nums) && nums[idx] != null {node.Right = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Right)}idx++}return root
}func main() {nums := []int{2, 1, 3}root := buildTree(nums)fmt.Println(isValidBST(root))nums = []int{5, 1, 4, null, null, 3, 6}root = buildTree(nums)fmt.Println(isValidBST(root))nums = []int{3, 1, 5, null, null, 4, 6}root = buildTree(nums)fmt.Println(isValidBST(root))
}

 代码3: 中序遍历+判断

package mainimport ("fmt"
)const null = -1 << 31type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}func isValidBST(root *TreeNode) bool {var pre *TreeNodestack := []*TreeNode{}for root != nil || len(stack) > 0 {for root != nil {stack = append(stack, root)root = root.Left}node := stack[len(stack)-1]stack = stack[:len(stack)-1]if pre != nil && node.Val <= pre.Val {return false}pre = noderoot = node.Right}return true
}func buildTree(nums []int) *TreeNode {if len(nums) == 0 {return nil}root := &TreeNode{Val: nums[0]}Queue := []*TreeNode{root}idx := 1for idx < len(nums) {node := Queue[0]Queue = Queue[1:]if nums[idx] != null {node.Left = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Left)}idx++if idx < len(nums) && nums[idx] != null {node.Right = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Right)}idx++}return root
}func main() {nums := []int{2, 1, 3}root := buildTree(nums)fmt.Println(isValidBST(root))nums = []int{5, 1, 4, null, null, 3, 6}root = buildTree(nums)fmt.Println(isValidBST(root))nums = []int{3, 1, 5, null, null, 4, 6}root = buildTree(nums)fmt.Println(isValidBST(root))
}

99. 恢复二叉搜索树 Recover Binary Search Tree

给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 

示例 1:

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

示例 2:

输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。

提示:

  • 树上节点的数目在范围 [2, 1000] 内
  • -2^31 <= Node.val <= 2^31 - 1

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗?

代码1:中序遍历+交换节点值

对于二叉搜索树,中序遍历得到的序列是递增的。因此,如果有两个节点的值被错误地交换了,那么在中序遍历序列中一定存在两个相邻的逆序对。具体做法是,在中序遍历的过程中,用一个变量pre记录上一个遍历到的节点,每次遍历到一个节点时,判断其值是否小于pre的值,如果小于,则说明存在逆序对,记录下这两个节点,并继续遍历。最后,交换这两个节点的值即可。

package mainimport ("fmt""strconv"
)const null = -1 << 31type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}func recoverTree(root *TreeNode) {var pre, first, second *TreeNodevar stack []*TreeNodefor root != nil || len(stack) > 0 {for root != nil {stack = append(stack, root)root = root.Left}node := stack[len(stack)-1]stack = stack[:len(stack)-1]if pre != nil && node.Val < pre.Val {if first == nil {first = pre}second = node}pre = noderoot = node.Right}first.Val, second.Val = second.Val, first.Val
}func buildTree(nums []int) *TreeNode {if len(nums) == 0 {return nil}root := &TreeNode{Val: nums[0]}Queue := []*TreeNode{root}idx := 1for idx < len(nums) {node := Queue[0]Queue = Queue[1:]if nums[idx] != null {node.Left = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Left)}idx++if idx < len(nums) && nums[idx] != null {node.Right = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Right)}idx++}return root
}func levelOrder(root *TreeNode) string {if root == nil {return "[]"}arr := []int{}que := []*TreeNode{root}for len(que) > 0 {levelSize := len(que)for i := 0; i < levelSize; i++ {node := que[0]que = que[1:]if node == nil {arr = append(arr, null)continue}arr = append(arr, node.Val)que = append(que, node.Left, node.Right)}}size := len(arr)for size > 0 && arr[size-1] == null {arr = arr[:size-1]size = len(arr)}result := "["for i, n := range arr {if n == null {result += "null"} else {result += strconv.FormatInt(int64(n), 10)}if i < size-1 {result += ","} else {result += "]"}}return result
}func main() {nums := []int{1, 3, null, null, 2}root := buildTree(nums)fmt.Println(levelOrder(root))recoverTree(root)fmt.Println(levelOrder(root))nums = []int{3, 1, 4, null, null, 2}root = buildTree(nums)fmt.Println(levelOrder(root))recoverTree(root)fmt.Println(levelOrder(root))
}

输出:

[1,3,null,null,2]
[3,1,null,null,2]

[3,1,4,null,null,2]
[2,1,4,null,null,3]

代码2:Morris遍历

Morris遍历是一种不需要额外空间的遍历二叉树的方法,它的核心思想是利用叶子节点的空指针来存储遍历中的临时信息。对于二叉搜索树,Morris中序遍历的过程中,每个节点的左子树都已经被遍历完毕,因此可以在遍历到每个节点时,比较它的值和它的前驱节点的值,如果它的值小于前驱节点的值,那么就找到了一个逆序对。我们用两个指针first和second来记录这两个节点,最后交换它们的值即可。

package mainimport ("fmt""strconv"
)const null = -1 << 31type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}func recoverTree(root *TreeNode) {var first, second, pre *TreeNodevar temp *TreeNodefor root != nil {if root.Left != nil {temp = root.Leftfor temp.Right != nil && temp.Right != root {temp = temp.Right}if temp.Right == nil {temp.Right = rootroot = root.Left} else {if pre != nil && root.Val < pre.Val {if first == nil {first = pre}second = root}pre = roottemp.Right = nilroot = root.Right}} else {if pre != nil && root.Val < pre.Val {if first == nil {first = pre}second = root}pre = rootroot = root.Right}}first.Val, second.Val = second.Val, first.Val
}func buildTree(nums []int) *TreeNode {if len(nums) == 0 {return nil}root := &TreeNode{Val: nums[0]}Queue := []*TreeNode{root}idx := 1for idx < len(nums) {node := Queue[0]Queue = Queue[1:]if nums[idx] != null {node.Left = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Left)}idx++if idx < len(nums) && nums[idx] != null {node.Right = &TreeNode{Val: nums[idx]}Queue = append(Queue, node.Right)}idx++}return root
}func levelOrder(root *TreeNode) string {if root == nil {return "[]"}arr := []int{}que := []*TreeNode{root}for len(que) > 0 {levelSize := len(que)for i := 0; i < levelSize; i++ {node := que[0]que = que[1:]if node == nil {arr = append(arr, null)continue}arr = append(arr, node.Val)que = append(que, node.Left, node.Right)}}size := len(arr)for size > 0 && arr[size-1] == null {arr = arr[:size-1]size = len(arr)}result := "["for i, n := range arr {if n == null {result += "null"} else {result += strconv.FormatInt(int64(n), 10)}if i < size-1 {result += ","} else {result += "]"}}return result
}func main() {nums := []int{1, 3, null, null, 2}root := buildTree(nums)fmt.Println(levelOrder(root))recoverTree(root)fmt.Println(levelOrder(root))nums = []int{3, 1, 4, null, null, 2}root = buildTree(nums)fmt.Println(levelOrder(root))recoverTree(root)fmt.Println(levelOrder(root))
}

🌟 每日一练刷题专栏 🌟

持续,努力奋斗做强刷题搬运工!

👍 点赞,你的认可是我坚持的动力! 

🌟 收藏,你的青睐是我努力的方向! 

评论,你的意见是我进步的财富!  

 主页:https://hannyang.blog.csdn.net/ 

Golang每日一练 专栏

Python每日一练 专栏

C/C++每日一练 专栏

Java每日一练 专栏

摩托车部落