目录
34. 查找元素首末位置 Find-first-and-last-position-of-element-in-sorted-array 🌟🌟
35. 搜索插入位置 Search Insert Position 🌟
36. 有效的数独 Valid Sudoku 🌟🌟
🌟 每日一练刷题专栏 🌟
Golang每日一练 专栏
Python每日一练 专栏
C/C++每日一练 专栏
Java每日一练 专栏
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:
输入: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))
}
🌟 每日一练刷题专栏 🌟
✨ 持续,努力奋斗做强刷题搬运工!
👍 点赞,你的认可是我坚持的动力!
🌟 收藏,你的青睐是我努力的方向!
✎ 评论,你的意见是我进步的财富!
Golang每日一练 专栏 | |
Python每日一练 专栏 | |
C/C++每日一练 专栏 | |
Java每日一练 专栏 |