Golang每日一练(leetDay0012)

简介: Golang每日一练(leetDay0012)

34. 查找元素的首末位置 Find-first-and-last-position-of-element-in-sorted-array  🌟🌟




原标题:在排序数组中查找元素的第一个和最后一个位置


给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

   你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?


示例 1:

输入:nums = [5,7,7,8,8,10], target = 8

输出:[3,4]


示例 2:

输入:nums = [5,7,7,8,8,10], target = 6

输出:[-1,-1]


示例 3:

输入:nums = [], target = 0

输出:[-1,-1]


提示:

   0 <= nums.length <= 10^5

   -10^9 <= nums[i] <= 10^9

   nums 是一个非递减数组

   -10^9 <= target <= 10^9



代码:二分法


对于查找左边界,设置一个变量 left,初始值为 -1,表示目标值在数组中不存在。然后用二分法查找目标值,如果找到目标值,就更新 left 的值,并继续在左半边查找,直到找到最左边的目标值。对于查找右边界,设置另一个变量 right,初始值为 -1,然后用类似的方法查找目标值的右边界。 最后,判断 left 是否等于 -1,如果是,说明目标值在数组中不存在,直接返回 [-1, -1]。 否则,返回 [left, right]。

package main
import "fmt"
func searchRange(nums []int, target int) []int {
  left, right := -1, -1
  // 查找左边界
  l, r := 0, len(nums)-1
  for l <= r {
    mid := (l + r) / 2
    if nums[mid] == target {
      left = mid
      r = mid - 1
    } else if nums[mid] > target {
      r = mid - 1
    } else {
      l = mid + 1
    }
  }
  // 如果左边界没找到,直接返回
  if left == -1 {
    return []int{-1, -1}
  }
  // 查找右边界
  l, r = 0, len(nums)-1
  for l <= r {
    mid := (l + r) / 2
    if nums[mid] == target {
      right = mid
      l = mid + 1
    } else if nums[mid] > target {
      r = mid - 1
    } else {
      l = mid + 1
    }
  }
  return []int{left, right}
}
func main() {
  nums := []int{5, 7, 7, 8, 8, 10}
  fmt.Println(searchRange(nums, 8))
  fmt.Println(searchRange(nums, 6))
  nums = []int{}
  fmt.Println(searchRange(nums, 0))
}


输出:

[3 4]

[-1 -1]

[-1 -1]


35. 搜索插入位置 Search Insert Position  🌟


给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。


请必须使用时间复杂度为 O(log n) 的算法。


示例 1:

输入: nums = [1,3,5,6], target = 5

输出: 2


示例 2:

输入: nums = [1,3,5,6], target = 2

输出: 1


示例 3:

输入: nums = [1,3,5,6], target = 7

输出: 4


提示:

   1 <= nums.length <= 10^4

   -10^4 <= nums[i] <= 10^4

   nums 为 无重复元素 的 升序 排列数组

   -10^4 <= target <= 10^4


代码:

用二分法查找目标值,如果找到目标值,就返回其索引;如果目标值不在数组中,就返回它应该插入的位置。


具体实现:用两个指针 l 和 r,分别指向数组的左边界和右边界。然后用二分法查找目标值。每次查找时,取中间位置 mid,然后将目标值与 nums[mid] 进行比较。如果相等,就返回 mid;如果目标值小于 nums[mid],就将右边界 r 更新为 mid-1;如果目标值大于 nums[mid],就将左边界 l 更新为 mid+1。最后,如果目标值不在数组中,就返回左边界 l。


package main
import "fmt"
func searchInsert(nums []int, target int) int {
  l, r := 0, len(nums)-1
  for l <= r {
    mid := (l + r) / 2
    if nums[mid] == target {
      return mid
    } else if nums[mid] > target {
      r = mid - 1
    } else {
      l = mid + 1
    }
  }
  return l
}
func main() {
  nums := []int{1, 3, 5, 6}
  fmt.Println(searchInsert(nums, 5))
  fmt.Println(searchInsert(nums, 2))
  fmt.Println(searchInsert(nums, 7))
}


输出:

2

1

4

另一种写法:

func searchInsert(nums []int, target int) int {
    l, r := 0, len(nums)-1
    for l <= r {
        mid := l + (r-l)>>1   //等价于: mid := (l + r) / 2
        if nums[mid] >= target {
            r = mid - 1
        } else {
            if (mid == len(nums)-1) || (nums[mid+1] >= target) {
                return mid + 1
            }
            l = mid + 1
        }
    }
    return 0
}




完整代码:

package main
import "fmt"
func searchInsert(nums []int, target int) int {
  l, r := 0, len(nums)-1
  for l <= r {
    mid := l + (r-l)>>1 //等价于: mid := (l + r) / 2
    if nums[mid] >= target {
      r = mid - 1
    } else {
      if (mid == len(nums)-1) || (nums[mid+1] >= target) {
        return mid + 1
      }
      l = mid + 1
    }
  }
  return 0
}
func main() {
  nums := []int{1, 3, 5, 6}
  fmt.Println(searchInsert(nums, 5))
  fmt.Println(searchInsert(nums, 2))
  fmt.Println(searchInsert(nums, 7))
}




36. 有效的数独 Valid Sudoku  🌟🌟

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。



   数字 1-9 在每一行只能出现一次。

   数字 1-9 在每一列只能出现一次。

   数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

   一个有效的数独(部分已被填充)不一定是可解的。

   只需要根据以上规则,验证已经填入的数字是否有效即可。

   空白格用 '.' 表示。

示例 1:


7074a9e737d5f6caf945355f4ba05a6d.png



输入:board =  

[["5","3",".",".","7",".",".",".","."],

["6",".",".","1","9","5",".",".","."],

[".","9","8",".",".",".",".","6","."],

["8",".",".",".","6",".",".",".","3"],

["4",".",".","8",".","3",".",".","1"],

["7",".",".",".","2",".",".",".","6"],

[".","6",".",".",".",".","2","8","."],

[".",".",".","4","1","9",".",".","5"],

[".",".",".",".","8",".",".","7","9"]]

输出:true

示例 2:

输入:board =  

[["8","3",".",".","7",".",".",".","."],

["6",".",".","1","9","5",".",".","."],

[".","9","8",".",".",".",".","6","."],

["8",".",".",".","6",".",".",".","3"],

["4",".",".","8",".","3",".",".","1"],

["7",".",".",".","2",".",".",".","6"],

[".","6",".",".",".",".","2","8","."],

[".",".",".","4","1","9",".",".","5"],

[".",".",".",".","8",".",".","7","9"]]

输出:false

解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。


提示:

   board.length == 9

   board[i].length == 9

   board[i][j] 是一位数字(1-9)或者 '.'


代码:


用三个数组来表示行、列、小九宫: rows、cols 和 boxs。

其中,rows[i][num] 表示第 i 行是否出现过数字 num,

cols[j][num] 表示第 j 列是否出现过数字 num,

boxs[k][num] 表示第 k 个子数独是否出现过数字 num。

遍历数独每一个位置,如果该位置为数字,则判断该数字在当前位置所在的行、列、小九宫中是否已经出现过。如果已经出现过,则该数独无效;否则,将其记录在对应的数组中。


package main
import "fmt"
func isValidSudoku(board [][]byte) bool {
  rows := make([]map[byte]bool, 9)
  cols := make([]map[byte]bool, 9)
  boxs := make([]map[byte]bool, 9)
  for i := 0; i < 9; i++ {
    rows[i] = make(map[byte]bool)
    cols[i] = make(map[byte]bool)
    boxs[i] = make(map[byte]bool)
  }
  for i := 0; i < 9; i++ {
    for j := 0; j < 9; j++ {
      if board[i][j] == '.' {
        continue
      }
      num := board[i][j]
      if rows[i][num] || cols[j][num] || boxs[(i/3)*3+j/3][num] {
        return false
      }
      rows[i][num] = true
      cols[j][num] = true
      boxs[(i/3)*3+j/3][num] = true
    }
  }
  return true
}
func main() {
  board := [][]byte{
    {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
    {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
    {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
    {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
    {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
    {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
    {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
    {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
    {'.', '.', '.', '.', '8', '.', '.', '7', '9'}}
  fmt.Println(isValidSudoku(board))
  board = [][]byte{
    {'8', '3', '.', '.', '7', '.', '.', '.', '.'},
    {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
    {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
    {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
    {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
    {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
    {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
    {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
    {'.', '.', '.', '.', '8', '.', '.', '7', '9'}}
  fmt.Println(isValidSudoku(board))
}

输出:

true

false

循环暴力:分别对行、列、小九宫循环判断

package main
import (
  "fmt"
  "strconv"
)
func isValidSudoku(board [][]byte) bool {
  for i := 0; i < 9; i++ {
    tmp := [10]int{}
    for j := 0; j < 9; j++ {
      cellVal := board[i][j : j+1]
      if string(cellVal) != "." {
        index, _ := strconv.Atoi(string(cellVal))
        if index > 9 || index < 1 {
          return false
        }
        if tmp[index] == 1 {
          return false
        }
        tmp[index] = 1
      }
    }
  }
  for i := 0; i < 9; i++ {
    tmp := [10]int{}
    for j := 0; j < 9; j++ {
      cellVal := board[j][i]
      if string(cellVal) != "." {
        index, _ := strconv.Atoi(string(cellVal))
        if index > 9 || index < 1 {
          return false
        }
        if tmp[index] == 1 {
          return false
        }
        tmp[index] = 1
      }
    }
  }
  for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
      tmp := [10]int{}
      for ii := i * 3; ii < i*3+3; ii++ {
        for jj := j * 3; jj < j*3+3; jj++ {
          cellVal := board[ii][jj]
          if string(cellVal) != "." {
            index, _ := strconv.Atoi(string(cellVal))
            if tmp[index] == 1 {
              return false
            }
            tmp[index] = 1
          }
        }
      }
    }
  }
  return true
}
func main() {
  board := [][]byte{
    {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
    {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
    {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
    {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
    {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
    {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
    {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
    {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
    {'.', '.', '.', '.', '8', '.', '.', '7', '9'}}
  fmt.Println(isValidSudoku(board))
  board = [][]byte{
    {'8', '3', '.', '.', '7', '.', '.', '.', '.'},
    {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
    {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
    {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
    {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
    {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
    {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
    {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
    {'.', '.', '.', '.', '8', '.', '.', '7', '9'}}
  fmt.Println(isValidSudoku(board))
}


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