0
点赞
收藏
分享

微信扫一扫

二分查找之基础题目

郝春妮 2022-04-19 阅读 34
golang算法

文章目录

二分查找之基础题目

1.二分查找

1.1暴力解法

func search(nums []int, target int) int {
if nums==nil {
       return -1
}
for i :=0; i<len(nums);i++{
    if  nums[i]==target{
        return i
    }
}
return -1
}

1.2左闭右闭区间二分查找

func search(nums []int, target int) int {
    high := len(nums)-1// 定义target在左闭右闭的区间里,[left, right]
    low := 0
    for low <= high {// 当left==right,区间[left, right]依然有效,所以用 <=
        mid := low + (high-low)/2   // 防止溢出 等同于(left + right)/2
        if nums[mid] == target { // 数组中找到目标值,直接返回下标
            return mid
        } else if nums[mid] > target {
            high = mid-1// target 在左区间,所以[left, middle - 1]
        } else {// target 在右区间,所以[middle + 1, right]
            low = mid+1
        }
    }
    return -1 // 未找到目标值
}
//可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10}中的3;正好low==high,mid右往右移动了
//注:不管是奇数个元素,还是偶数个元素,算的都是中间值
//可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10},寻找-1,最终high=-1,low=0,退出循环
可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10},寻找100,最终high=6,low=7,退出循环

image-20220205220821345

image-20220205220837364
在这里插入图片描述

1.3左闭右开区间二分查找

func search(nums []int, target int) int {
    high := len(nums)// 定义target在左闭右开的区间里,即:[left, right)
    low := 0
    for low < high {// 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
        //假如数组长度有4个元素,则mid=1;则num是第二个元素
        //假如数组长度有5个元素,则mid=2;则num是第三个元素
        mid := low + (high-low)/2
        if nums[mid] == target { // 数组中找到目标值,直接返回下标
            return mid
        } else if nums[mid] > target {// target 在左区间,在[left, middle)中
            high = mid
        } else {// target 在右区间,在[middle + 1, right)中
            low = mid+1
        }
    }
    return -1// 未找到目标值
}
//可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10}中的3;正好low < high,差一点接近于low===high
//可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10},寻找-1,最终high=0,low=0,退出循环
可以debug尝试一下查[]int{1, 2, 3, 4, 7, 9, 10},寻找100,最终high=7,low=7,退出循环                                     

image-20220205220904873
在这里插入图片描述
在这里插入图片描述

1.4递归左闭右闭区间二分查找

func search(nums []int, target int) int {
   return  BinarySearch(nums,target,0,len(nums)-1)
}
func BinarySearch(array []int, target int, l, r int) int {
	if l > r {
		// 出界了,找不到
		return -1
	}
	// 从中间开始找
	mid := (l + r) / 2
	middleNum := array[mid]
	if middleNum == target {
		return mid // 找到了
	} else if middleNum > target {
		// 中间的数比目标还大,从左边找
		return BinarySearch(array, target, 0, mid-1)
	} else {
		// 中间的数比目标还小,从右边找
		return BinarySearch(array, target, mid+1, r)
	}
}

1.5递归左闭右开区间二分查找

func search(nums []int, target int) int {
   return  BinarySearch(nums,target,0,len(nums))
}
func BinarySearch(array []int, target int, l, r int) int {
	if l >= r {
		return -1
	}
	mid := (l + r) / 2
	middleNum := array[mid]
	if middleNum == target {
		return mid 
	} else if middleNum > target {
		return BinarySearch(array, target, 0, mid)
	} else {
		return BinarySearch(array, target, mid+1, r)
	}
}

704.二分查找

在这里插入图片描述

2.搜索插入位置

2.1暴力解法

func searchInsert(nums []int, target int) int {
   for i:=0;i<len(nums);i++{
    // 分别处理如下三种情况
        // 目标值在数组所有元素之前,返回0
        // 目标值等于数组中某一个元素
        // 目标值插入数组中的位置
       if target <= nums[i]{
           return i
       }
   }
   // 目标值在数组所有元素之后的情况
    return len(nums)// 如果target是最大的,或者 nums为空,则返回nums的长度
}
//时间复杂度:O(n)  空间复杂度:O(1)

image-20220205222147224
在这里插入图片描述

2.2左闭右闭区间二分查找

func searchInsert(nums []int, target int) int {
	left, right := 0, len(nums)-1// 定义target在左闭右闭的区间里,[left, right]
	for left <= right {// 当left==right,区间[left, right]依然有效
		mid := left + (right-left)/ 2  //也可以写成mid := left + (right-left) >> 1,防止溢出 等同于(left + right)/2
		if nums[mid] < target {
			left = mid + 1// target 在右区间,所以[middle + 1, right]
		} else if nums[mid] > target {
			right = mid -1 // target 在左区间,所以[left, middle - 1]
		} else {// nums[middle] == target
			return mid
		}
	}
	    // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1]
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1
        // 目标值在数组所有元素之后的情况 [left, right], return right + 1
	return left
}
//时间复杂度:O(log n)
//空间复杂度:O(1)

二分法

image-20220205224122234
在这里插入图片描述
左闭右闭二分查找

在这里插入图片描述

2.3左闭右开区间二分查找

func searchInsert(nums []int, target int) int {
	left, right := 0, len(nums)// 定义target在左闭右开的区间里,[left, right)  target
	for left < right {// 因为left == right的时候,在[left, right)是无效的空间
		mid := left + (right-left)/ 2  //也可以写成mid := left + (right-left) >> 1
		if nums[mid] < target {// target 在右区间,在 [middle+1, right)中
			left = mid + 1
		} else if nums[mid] > target {
			right = mid // target 在左区间,在[left, middle)中
		} else {// nums[middle] == target
			return mid// 数组中找到目标值的情况,直接返回下标
		}
	}
	   // 分别处理如下四种情况
        // 目标值在数组所有元素之前 [0,0)
        // 目标值等于数组中某一个元素 return middle
        // 目标值插入数组中的位置 [left, right) ,return right 即可
        // 目标值在数组所有元素之后的情况 [left, right),return right 即可
	return left
}
//时间复杂度:O(log n)
//空间复杂度:O(1)

在这里插入图片描述
在这里插入图片描述

image-20220115124112401

image-20220205222842746

3.在排序数组中查找元素的第一个和最后一个位置

3.1左闭右闭区间二分查找

func searchRange(nums []int, target int) []int {
    return []int{searchFirst(nums, target), searchLast(nums, target)}
}

//寻找左边界
// 二分查找,寻找target的左边界leftBorder(不包括target)
// 如果leftBorder没有被赋值(即target在数组范围的右边,例如数组[3,3],target为4),为了处理情况一
func searchFirst(nums []int, target int) int {
	left, right := 0, len(nums)-1// 定义target在左闭右闭的区间里,[left, right]
	for left <= right {
		mid := left + (right-left)>>1
		if nums[mid] >= target {// 寻找左边界,就要在nums[middle] == target的时候更新right
			right = mid - 1
		} else {
			left = mid + 1
		}
	}
	if left = len(nums) || nums[left] != target { // 判断一下是否越界,或者不相等
		return -1
	}
	return left
}
//寻找右边界
// 二分查找,寻找target的右边界(不包括target)
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
func searchLast(nums []int, target int) int {
	left, right := 0, len(nums)-1// 定义target在左闭右闭的区间里,[left, right]
	for left <= right {// 当left==right,区间[left, right]依然有效
		mid := left + (right-left)>>1
		if nums[mid] > target { // 这里是 > 而不是 >=
			right = mid - 1 // target 在左区间,所以[left, middle - 1]
		} else {// 当nums[middle] == target的时候,更新left,这样才能得到target的右边界
			left = mid + 1
		}
	}
	if right == -1 || nums[right] != target { // 判断一下是否越界,或者不相等
		return -1
	}
	return right // 这里返回 right 而不是 left
}

在这里插入图片描述
00

在这里插入图片描述

4.二分查找第一个元素

4.1左闭右闭区间二分查找

func main() {
	fmt.Println(searchFirst([]int{5, 7, 7, 8, 8, 10}, 1))  //输出-1;最终left=0,right=-1
	fmt.Println(searchFirst([]int{5, 7, 7, 8, 8, 10}, 8))  //输出3;最终left=3,right=2
	fmt.Println(searchFirst([]int{5, 7, 7, 8, 8, 10}, 19)) //输出-1;最终,left=6,right==5
	fmt.Println(searchFirst([]int{5, 7, 7, 8, 8, 10}, 6))  //输出-1;最终:left=1,right=0
	fmt.Println(searchFirst([]int{5, 7, 7, 8, 8, 10}, 5))  //输出0;最终:left=0,right=-1
}
func searchFirst(nums []int, target int) int {
	left, right := 0, len(nums)-1
	for left <= right {
		mid := left + (right-left)>>1
		if nums[mid] >= target {
			right = mid - 1
		} else {
			left = mid + 1
		}
	}
	if left = len(nums) || nums[left] != target { // 判断一下是否越界,或者不相等
		return -1
	}
	return left
}

image-20220207093819476

image-20220207093839340

image.png

image-20220207093920154

5.二分查找第二个元素

5.1左闭右闭区间二分查找

func main() {
	fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 1))  //输出-1,最终left==0,right=-1
	fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 8))  //输出4,最终left=5,rught=4
	fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 19)) //输出-1,最终left=6,right=5
    fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 10)) //输出-1,最终left=6,right=5

	fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 6))  //输出-1,left=1,right=0
	fmt.Println(searchLast([]int{5, 7, 7, 8, 8, 10}, 5))  //输出0,left=1,right=0
}
func searchLast(nums []int, target int) int {
	left, right := 0, len(nums)-1
	for left <= right {
		mid := left + (right-left)>>1
		if nums[mid] > target { // 这里是 > 而不是 >=
			right = mid - 1
		} else {
			left = mid + 1
		}
	}
	if right == -1 || nums[right] != target { // 判断一下是否越界,或者不相等
		return -1
	}
	return right // 这里返回 right 而不是 left
}

image-20220207094251658

6.二维数组中的查找

6.1暴力解法

func findNumberIn2DArray(matrix [][]int, target int) bool {
	if matrix == nil || len(matrix) == 0 || len(matrix[0]) == 0 {
		return false
	}
	rows := len(matrix)
	colums := len(matrix[0])
	for i := 0; i < rows; i++ {
		for j := 0; j < colums; j++ {
			if matrix[i][j] == target {
				return true
			}
		}
	}
	return false
}
//时间复杂度:O(nm)
//空间复杂度:O(1)

6.2左闭右闭二分查找


func searchMatrix2(matrix [][]int, target int) bool {
	var m = len(matrix)
	if m == 0 {
		return false
	}
	var n = len(matrix[0])
	var shortDim = min(m, n)
	for i := 0; i < shortDim; i++ {
		var rowFound = binarySearchRow(matrix, i, target)
		var colFount = binarySearchCol(matrix, i, target)
		if rowFound || colFount {
			return true
		}
	}
	return false
}

func min(a, b int) int {
	if a > b {
		return b
	}
	return a
}

func binarySearchRow(matrix [][]int, row int, target int) bool {
	var left, right = row, len(matrix[0]) - 1
	for left <= right {
		var mid = left + (right - left) / 2
		if matrix[row][mid] == target {
			return true
		} else if matrix[row][mid] < target {
			left = mid + 1
		} else {
			right = mid - 1
		}
	}
	return false
}

func binarySearchCol(matrix [][]int, col int, target int) bool {
	var left, right = col, len(matrix) - 1
	for left <= right {
		var mid = left + (right - left) / 2
		if matrix[mid][col] == target {
			return true
		} else if matrix[mid][col] < target {
			left = mid + 1
		} else {
			right = mid - 1
		}
	}
	return false
}

在这里插入图片描述

6.3线性查找

func findNumberIn2DArray(matrix [][]int, target int) bool {
	i, j := len(matrix)-1, 0
	for i >= 0 && j < len(matrix[0]) {
		if target > matrix[i][j] {
			j++
		} else if target < matrix[i][j] {
			i--
		} else {
			return true
		}
	}
	return false
}

在这里插入图片描述

在这里插入图片描述

7.搜索二维矩阵

7.1暴力解法

func searchMatrix(matrix [][]int, target int) bool {
if matrix == nil || len(matrix) == 0 || len(matrix[0]) == 0 {
		return false
	}
	rows := len(matrix)
	colums := len(matrix[0])
	for i := 0; i < rows; i++ {
		for j := 0; j < colums; j++ {
			if matrix[i][j] == target {
				return true
			}
		}
	}
	return false
}
//时间复杂度是 O(n^2)
//空间复杂度是 O(1)

7.2二分查找

func searchMatrix(matrix [][]int, target int) bool {
    var m, n = len(matrix), len(matrix[0])
    var left, right = 0, m * n - 1
    for left <= right {
     // mid 是一维数组的索引
        var mid = left + (right - left) / 2
         // mid / n 是将一维数组的索引转成二维数组的行坐标
        // mid % n 是将一维数组的索引转成二维数组的列坐标
        var num = matrix[mid / n][mid % n]
        if num == target {
            return true
        } else if num < target {
            left = mid + 1
        } else {
            right = mid - 1
        }
    }
    return false
}
//时间复杂度:O(logn)
//空间复杂度:O(1)

在这里插入图片描述

74.搜索二维矩阵
在这里插入图片描述
在这里插入图片描述

举报

相关推荐

0 条评论