代码随想录第一天| 704. 二分查找、27. 移除元素

数组相关知识

数组下标都是从0开始的。
数组内存空间的地址是连续的
因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。
go声明二维数组时,系统会开辟一片连续的内存空间,依次存储所有的元素

一:二分查找

力扣704https://leetcode.cn/problems/binary-search/

之前学习二分查找的时候基本上靠肌肉记忆凭感觉,有两个小的疑惑点基本上就是碰运气。这次系统学习了这两部分的写法和原理,并对相关题目进行了扩展

二分法在写的过程中会出现的两个疑惑点:边界条件的判断
1.for循环时lefrt<=right 还是 left<right
2.mid取值时,是mid还是mid+1/mid-1

为明确解决这两个问题考虑两种区间的定义方法:

1.左闭右闭 [A,B]

在这种情况下,for lefrt<=right符合区间定义,例如[1,1]
此时lfet=0,right=len(nums)-1
在这里插入图片描述

(1)当nums[mid]<target时,例如,target=10。下一步要搜索的区间包含mid,且mid不符合题目要求。所以下次选择时,mid被排除,left=mid+1
(2)当nums[mid]>target时,例如,target=8。下一步要搜索的区间包含mid,且mid不符合题目要求。所以下次选择时,mid被排除,right=mid-1
(3)当nums[mid]=target时,返回mid的值

2.左闭右开 [A,B)

在这种情况下,for lefrt<right符合区间定义,例如[1,2),此时两数相等已经不符合定义
此时lfet=0,right=len(nums)要包含到数组的最后一个值
在这里插入图片描述

(1)当nums[mid]<target时,例如,target=10。往右移动,下一步要搜索的区间包含mid。所以下次选择时,mid被排除,left=mid+1
(2)当nums[mid]>target时,例如,target=8。下一步要搜索的区间不包含mid,所以下次选择时,right=mid,但此时由于左闭右开mid不被包含
(3)当nums[mid]=target时,返回mid的值

变形问题:(有重复元素)

第一个的问题都向前看

1.查找第一个等于目标值的下标 重点是看mid前一个元素是否==target

在这里插入图片描述
在已知nums[mid]=target的情况下
(1)如果nums[mid-1]=target,说明还要继续向前搜寻
(2)如果nums[mid-1]!=target,则找到了第一个等于的元素

//时间复杂度O(logn)
//空间复杂度O(1)
func contains(nums []int,target int){ 
    if nums==nil || len(nums)==0{ 
        return -1 
    }
    left:=0
    right:=len(nums)-1
    for left<=right{ 
        mid:=(right-left)/2+left
        if target==nums[mid]{ 
            //符合下面的两个条件之一就返回mid
            //1.mid是数组的第一个元素
            //2.mid前面的元素不等于target
            if mid==0 || target!=nums[mid-1]{
                return mid
            }else{
                right=mid-1
            }
        }else if target<nums[mid]{ 
            right=mid-1
        }else{
            left=mid+1
        }
    }
    return -1 
}

2.查找第一个大于等于目标值的下标

在nums[mid]>=target的情况下
(1)如果nums[mid-1]>=target,说明还要继续向前搜寻
(2)如果nums[mid-1]<target,则找到了第一个等于的元素

在这里插入图片描述

func search(nums []int, target int) int { 
    if nums==nil || len(nums)==0{ 
        return -1 
    }
    left:=0
    right:=len(nums)-1
    for left<=right{ 
        mid:=(right-left)/2+left
        if target<=nums[mid]{ 
            //符合下面的两个条件之一就返回mid
            //1.mid是数组的第一个元素 
            //2.mid前面的元素小于target
            if mid==0 || nums[mid-1]<target{ 
                return mid
            }else{
                right=mid-1
            }
        }else{
            left=mid+1
        }
    }
    return -1 
}

最后一个往右边看,后看

3.查找最后一个等于目标值的下标

在这里插入图片描述
在已知nums[mid]=target的情况下
(1)如果nums[mid+1]=target,说明还要继续向后搜寻
(2)如果nums[mid+1]!=target,则找到了最后一个等于的元素

func search(nums []int, target int) int { 
    if nums==nil || len(nums)==0{ 
        return -1 
    }
    left:=0
    right:=len(nums)-1
    for left<=right{ 
        mid:=(right-left)/2+left    
        if target==nums[mid]{

            //符合下面的两个条件之一就返回mid
            //1.mid是数组的最后一个元素
            //2.mid后面的元素!=target
            if mid==len(nums)-1 || nums[mid+1]!=target{     
                return mid
            }else{
                left=mid+1 
            }
        }else if target<nums[mid]{ 
            right=mid-1
        }else{
            left=mid+1
        }
    }
    return -1 
}

4.查找最后一个小于等于目标值的下标

在nums[mid]<=target的情况下
(1)如果nums[mid+1]<=target,说明还要继续向后搜寻
(2)如果nums[mid+1]>target,则找到了最后一个大于等于的元素

func search(nums []int, target int) int { 
    if nums==nil || len(nums)==0{ 
        return -1 
    }
    left:=0
    right:=len(nums)-1
    for left<=right{ 
        mid:=(right-left)/2+left
        if target>=nums[mid]{ 

            //符合下面的两个条件之一就返回mid
            //1.mid是数组的第一个元素
            //2.mid前面的元素小于target
            if mid==len(nums)-1 || nums[mid+1]>target{ 
                return mid
            }else{
                left=mid+1
            }

        }else{
            right=mid-1
        }
    }
    return -1 
}

相关题目34 35 69是剑指和top100的题目

简单 lc 704 号算法题:二分查找
中等 lc 34 :排序数组中找元素的第一个和最后一个位置【top100】
简单 lc 35 & 剑指 53-1:搜索插入位置【top100】
简单 lc 69 & 剑指 072 :x 的平方根

二、移动元素

方法一:快慢指针

在这里插入图片描述

func removeElement(nums []int, val int) int { 
    if len(nums)==0{ 
        return 0 
    }
    slow,fast:=0,0
    for fast<len(nums){ 
        if nums[fast]!=val{ 
            nums[slow]=nums[fast]
            slow++
        }
    fast++    
    }
    return slow 
}

方法二:对撞指针

进阶:如果要删除的元素特别少,且是前面的

需要对整个数组的元素重新赋值,很费时

如果left对应的值是需要删除的,就把right的值赋给left,right–
如果不需要删除,left++
在这里插入图片描述

直到left>right

func removeElement(nums []int, val int) int { 
    if len(nums)==0{ 
        return 0 
    }
    left,right:=0,len(nums)-1
    for right>=left{     
        if nums[left]==val{ 
            nums[left]=nums[right]
            right--
        }else{    
            left++
        }
    }
    return right+1     
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值