代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素。

704.二分查找

题目链接:https://leetcode.cn/problems/binary-search/

题目要求:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入:nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入:nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

总结:1.首先二分查找的条件是满足数组是有序且不重复的。2.区间是全闭还是左闭右开,定好后要保持不变,left < right,还是left<=right,包括后面缩小空间时,是right = mid 还是 right = mid - 1,都要根据区间的选择来看。3.同时要注意给的target值小于有序数组最左边,大于有序数组最右边的情况。4.当算mid 位置时,正常是(left+right)/2,但是可能会存在溢出,故用left+((right-left)/2)代替 ,同时可进一步优化为位运算,右移1位,代表/2操作。变为left+((right-left) >> 1)。

区间全闭:

class Solution {
    public int search(int[] nums, int target) {
        if(target < nums[0] || target > nums[nums.length - 1]){
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            int mid = left + ((right - left) >> 1);
            if(nums[mid] == target){
                return mid;
            }
            if(nums[mid] > target){
                right = mid - 1;
            }
            if(nums[mid] < target){
                left = mid + 1;
            }
        }
        return -1;
    }
}

此种情况,left = right时存在意义,故 left <=right ,当mid值大于target值时,已经知道mid值肯定不是target,故right = mid -1

区间为左闭右开:

class Solution {
    //左闭右开区间
   public int search(int[] nums,int target){
       //考虑target值不在有序数组的区间内的情况
       if(nums[0] > target || nums[nums.length-1] < target){
           return -1;
       }
       int left = 0;
       int right = nums.length;//左闭右开
       //left=right此时区间没有意义
       while(left < right){
           int mid = left + ((right - left)/2);
           if(target < nums[mid]){
               right = mid;
           }
           else if(target > nums[mid]){
               left = mid + 1;
           }
           else if(target == nums[mid] ){
               return mid;
           }
       }
       return -1;
   }
}

注意此时right指针初始定义为nums.length,该指针指向数组最右元素的右边一个位置,故右为开区间,当left = right时已经无意义,故为left < right,当nums[mid] > target时,mid已经确定不是了,故此时right = mid,因为右为开区间,正好把mid排除在外。

27. 移除元素

题目链接:https://leetcode.cn/problems/remove-element/

题目要求:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

输入:nums = [3,2,2,3], val = 3

输出:2, nums = [2,2]

解释:函数应该返回新的长度 2, 并且 nums中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

总结:本题目可以使用暴力的两层for循环得出结果,一层循环遍历数组,再一层循环负责删除元素后移动后面其余元素。注意i--是因为当删除一个元素后,所有元素的索引都向前提了一位,故需要让遍历整个数组的i向前移一位,防止漏掉最左边的那一个元素。

双指针法,快指针用来遍历数组,慢指针用来确定不含目标值的“新数组”的最后一位。当遇到不为目标值时,两个指针一起向后走,当遇到为目标值时,慢指针不走,快指针继续向后遍历,然后用快指针指向的值覆盖慢指针此时指向的目标值元素。

暴力法:

class Solution {
    //暴力法解决,两层for循环
    public int removeElement(int[] nums,int val){
        int len = nums.length;
        for(int i = 0;i < len;i++){
            if(nums[i] == val){
                for(int j = i + 1;j < len;j++){
                    nums[j-1] = nums[j];
                }
                i--;
                len--;
            }
        }
        return len;
    }
}

双指针法:

class Solution {
    //双指针法,快慢指针
    public int removeElement(int[] nums,int val){
        int slowindex = 0;
        for(int fastindex = 0;fastindex < nums.length;fastindex++){
            if(nums[fastindex] != val){
                nums[slowindex] = nums[fastindex];
                slowindex++;
            }
        }
        return slowindex;
    }

}

你可能感兴趣的:(算法)