二分法(相关题目:704、35、34)
二分法最重要的就是定好区间!!
左开右闭或者左闭右闭
704 二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
第一种 左闭右闭
该解法的关键是 for的条件!
func search(nums []int, target int) int {
//左闭右闭
left,right := 0,len(nums)-1
var mid int
for(right >= left){
mid=(left + right)>>1
if(nums[mid] > target){
//tar在左边区间
right = mid - 1 //[left,mid-1]
}else if(nums[mid] < target){
left = mid + 1 //[mid+1,right]
}else{
return mid
}
}
return -1
}
第二种 左闭右开
func search(nums []int, target int) int {
//左闭右开
left,right := 0,len(nums)
var mid int
for right>left{
mid = (left + right)>>1
if(nums[mid] > target){
right = mid //在左区间[left,mid)
}else if(nums[mid] < target){
left = mid + 1 //在右区间[mid+1,right)
}else {
return mid
}
}
return -1
}
35 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
func searchInsert(nums []int, target int) int {
left,right:=0,len(nums)
var mid int
for right > left{
mid = (right+left)>>1
if(nums[mid]>target){
right=mid //[left,mid)
}else if(nums[mid]<target){
left=mid+1 //[mid+1,right)
}else{
return mid
}
}
return right /*由于区间是[left,right)
分为4种情况:1.目标值存在于数组中 reurn mid
2.目标在数组之前[0,-1] return right
3.目标存在于数组中的某个位置[left,right) return right
4.目标存在于数组之后 return right */
}
34 在排序数组中查找元素的第一个和最后一个位置
这道题的核心思路是要找到这个范围的左边界和右边界
同时在nums[mid]=target的判断需要处理,寻找左边界时需要尽可能往左边区间靠,寻找右边界时往有边界靠
func searchRange(nums []int, target int) []int {
left,right:=getLeftBorder(nums,target),getRightBorder(nums,target)
if(right == -1 || left == -1 || right<=left){
return []int{-1,-1}
}
return []int{left,right-1}
}
func getLeftBorder(nums []int , target int) int{
left,right:=0,len(nums)
var mid,leftBorder int
leftBorder = -1
for right>left{
//左闭右开
//左边界的意义是左边的数都要小于目标值
mid = (left+right)>>1
if(nums[mid]<target){
left = mid + 1 //[mid+1,right)
}else{
right = mid //[left,mid)
leftBorder = right
//在相等的时候区间应该尽可能往左边走
}
}
return leftBorder
}
func getRightBorder(nums []int , target int) int{
left,right:=0,len(nums)
var mid,rightBorder int
rightBorder = -1
for right>left{
//左闭右开
//右边界的意义是左边的数都要小于目标值
mid = (left+right)>>1
if(nums[mid]>target){
right = mid //[left,mid)
}else{
left = mid + 1//[mid+1,right)
rightBorder = left
}
}
return rightBorder
}
27 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
这道题暴力解法始终无法通过… 还没发现问题在哪… 等到后面有机会了再补充…
由于之前做过这道题 直接快慢指针就能解决了
其中的关键是:slow指针的意义是代表这新的数组的末端,照着这个思路去解决
func removeElement(nums []int, val int) int {
fast,slow:=0,0
for fast<len(nums){
if(nums[fast]!=val){
nums[slow]=nums[fast]
slow++
}
fast++
}
return slow
}
总结
今天总体过了2种算法:1.二分法 2.快慢指针 收获不小~~