day 1二分查找 移除元素

二分查找

  1. 查找确切值
 public int search(int [] nums, int target){
        int left = 0;
        int right = nums.length-1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(nums[mid] == target){
                return mid;
            }else if (nums[mid] < target) left = mid + 1;
            else if (nums[mid] > target) right = mid - 1;
        }
        return -1;
    }

1.2 寻找模糊值,关键点在于条件判断
69.x 的平方根
(1)用除法代替乘法,防止越界
(2) 367.有效的完全平方数
本题中是找到不精确的平方根,那么条件就是 mid*mid <= target && (mid+1) (mid+1) >target
如果是找精确整数平方根 (mid
mid)==target mid是完全平方根, 但是直接转换为出发 x/mid == mid不能直接判平方根 因为5/2 = 2; if(1.0 * num/mid > mid) left = mid + 1; 排除这种情况

class Solution {
    public int mySqrt(int x) {
        if(x==0 || x==1) return x;
        int left = 1;
        int right = x/2;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(x/mid >= mid && x/(mid+1) < mid +1) return mid;
            if(x/mid > mid) left = mid + 1;
            if(x/mid < mid)  right = mid -1;
        }
        return -1;
    }
}
  1. 查找左边界

34. 在排序数组中查找元素的第一个和最后一个位置
35.搜索插入位置

对于闭区间的搜索 结束条件是 right + 1 == left left要指向大于等于target的元素的第一个位置。
(1)闭区间搜索框架不变
(2)nums[mid] == target时 压缩上边界 也就是 right = mid - 1;新的搜索区间就变成了[left ,mid-1]
疑问为啥最终left就是对的
1.如果数组中有target元素,right会不停的变为target元素左边那一个 到停止条件时 ,right+1left left就是左边界
2. 如果数组中没有该元素
1. target比所有数组元素都大, left一路mid+1,最后left
nums.length
2. target比所有数组元素都小, right一路mid-1,最终 right = -1 left = 0,这时候如果 nums[0] != target, 说明没有该元素
3. target在中间, right+1 == left的时候,num[right]一定时小于target的,num[left]时大于等于target的数,这就需要判断,若num[left] !=target 说明没有 这个可以跟2 合起来

left只有两种情况,一种是一路越界,一种是指向大于等于的第一个位置,第二终情况就可以判断是不是等于从而判断是不是左边界

 public int searchL(int [] nums, int target){
        int left = 0;
        int right = nums.length-1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(nums[mid] == target){
                right = mid - 1;
            }else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        if(left == nums.length || nums[left] != target) return -1;
        return left;
    }
  1. 查找右边界
    结束条件: right + 1 = left
    方法是不断压缩下边界, left = mid +1;left不停成为右边界的下一位置,当结束时,left一定指向一个大于或者是越界的位置,right指向小于等于target的元素,这是由就需要判断,到底有没有我们需要的元素
    当然,如果 target小于所有元素,right一路减小,最后right为-1, 此时也时找步到右边界
 public int searchL(int [] nums, int target){
        int left = 0;
        int right = nums.length-1;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(nums[mid] == target){
               left = mid + 1;
            }else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        if( right == -1 || nums[right] != target) return -1;
        return right;
    }

5.没有target,通过mid和左右两端比较进行空间的缩小
153 寻找旋转排序数组中的最小值

本题关键点:升序数组,且没有相同的元素
在这里插入图片描述
数组旋转结束 要么是第一种 要么就是变回去。
mid存在的三种情况
第一种 最小值肯定是在右边
第二种是本身或者左边
第三种是在左侧
在图一中,因为不存在相同元素,那么num[0] 一定大于num[n-1]。 使用num[mid]与num[right]比较就可以了

class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length-1;
        while(left < right){
            int mid = left + (right - left)/2;
            if(nums[mid] > nums[right]) left = mid + 1;
            else if(nums[mid] <= nums[right]) right = mid;
        }
        return nums[left];
    }
}

154. 寻找旋转排序数组中的最小值 II
关键问题:重复元素

  1. 先把两端的去重,那么大概形状就会回到上一题
class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left < right){
            while(left<right && nums[left] == nums[left+1]) left++;
            while(left<right && nums[right] == nums[right-1]) right--;
            int mid = left + (right - left)/2;
            if(nums[mid] >nums[right]) left = mid + 1;
            else if(nums[mid] <= nums[right]) right = mid;
        }
        return nums[right];
    }
}

移除元素(双指针)

  1. 相向双指针
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0; 
        int right = nums.length-1;
        while(left <= right){
            while(left <= right && nums[left]!=val) left++;
            while(left <= right && nums[right] == val) right--;
            if(left>right) break;
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
        }
        return left;
    }
}

977 有序数组的平方

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] a = new int[nums.length];
        int last = nums.length-1;
        int left = 0;
        int right = last;
        while(left <= right){
            if(Math.abs(nums[left]) >= Math.abs(nums[right])){
                a[last--] = nums[left] * nums[left];
                left++;
            }else{
                a[last--] = nums[right] * nums[right];
                right--;
            }
        }
        return a;
    }
}
  1. 同向双指针(快慢双指针)
    快指针 fast 。遍历作用,寻找合适的元素
    慢指针 slow 。数组下标是0,slow表示符合要求元素个数,slow索引指向的位置是可以进行覆盖的位置,slow-1之前都是符合要求的元素数组
    本质时依次覆盖,合适的往前覆盖,slow一定慢于或者等于fast 那么不需要管覆盖位置的死活

27. 移除元素
不停的将符合要求的元素复制到前面,保持相对顺序

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for(int fast=0; fast<nums.length; fast++){
            if(nums[fast]!=val){
                nums[slow]= nums[fast];
                slow++; 
            }
        }

        return slow ;
    }
}

26.删除排序数组中的重复项
注意点:fast寻找满足要求的元素,需要跟当前已经满足的最后一个元素进行比较
(1)slow依旧指向当前满足要求的最后一个元素,那么要先自增再进行复制
(2)slow指向可以覆盖的位置,那么判断时比较 nums[fast] != nums[slow-1]

class Solution {
    public int removeDuplicates(int[] nums) {
        int slow = 0;
        for(int fast = 1; fast<nums.length; fast++){
            if(nums[fast] != nums[slow]){
                slow ++;
                nums[slow] = nums[fast];
            }
        }
        return slow + 1;
    }
}

844.比较含退格的字符串

模拟栈操作,slow 指向栈顶索引,指向当前可以覆盖的位置
遇到“#” slow进行回退
举例 ab#c
fast指向#时,此时slow=2 也就时覆盖位置为#,但是需要回退一个,slow = 1,也就是可覆盖位置变成b,当fast指向c时,c就可以覆盖b
本题易错点 就是首字母为# 不进行回退,continue掉就行

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        int slow_s = edit(s);
        int slow_t = edit(t);
    
        if(slow_s != slow_t) return false;
        for(int i=0; i < slow_s; i++){
            if(s[i] != t[i]) return false;
        }
        return true;
    }
   int edit(string &s){
        int slow = 0;
        for(int fast = 0; fast < s.length(); fast++){
            if(s[fast] == '#'){
                if(slow == 0) continue;    
                else slow--;   //可以覆盖的位置前移一个
            }
            else {
                s[slow++] = s[fast];
            }
        }
        return slow;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值