代码随想录训练营day2|34、排序数组中查找元素的第一和最后一个位置;35、搜索插入位置;977、有序数组的平方;209、长度最小的子数组

34、排序数组中查找元素的第一和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[]{-1, -1};
        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){
                right = mid - 1;
            }else{
                if(mid == 0 || nums[mid-1] != nums[mid]){
                    res[0] = mid;
                    break;
                }else{
                    right = mid - 1;
                }
            }
        }

        
        int left1 = 0;
        int right1 = nums.length - 1;
        // 寻找右边界
        while(left1 <= right1){
            int mid1 = left1 + (right1 - left1) / 2;
            if(nums[mid1] < target){
                left1 = mid1 + 1;
            }else if(nums[mid1] > target){
                right1 = mid1 - 1;
            }else{
                if(mid1 == nums.length - 1 || nums[mid1] != nums[mid1+1]){
                    res[1] = mid1;
                    break;
                }else{
                    left1 = mid1 + 1;
                }
            }
        }

        return res;
    }
}

 注意:| 和 ||的区别,前者还要判断后一个条件;后者若第一个条件是true,则不会判断第二个条件。

35、搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

class Solution {
    public int searchInsert(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){
                if(mid == nums.length-1){
                    return nums.length;
                }else if(nums[mid+1] > target){
                    return mid+1;
                }else{
                    left = mid + 1;
                }
            }else{
                if(mid == 0){
                    return 0;
                }else if(nums[mid-1] < target){
                    return mid;
                }else{
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}

注意:

1、先写出二分搜索的框架,再在框架中考虑特殊情况(搜索不到/到达边界)

2、最后一定要return -1???

另:

class Solution {
    public int searchInsert(int[] nums, int target) {
        int n = nums.length;

        // 定义target在左闭右闭的区间,[low, high]
        int low = 0;
        int high = n - 1;

        while (low <= high) { // 当low==high,区间[low, high]依然有效
            int mid = low + (high - low) / 2; // 防止溢出
            if (nums[mid] > target) {
                high = mid - 1; // target 在左区间,所以[low, mid - 1]
            } else if (nums[mid] < target) {
                low = mid + 1; // target 在右区间,所以[mid + 1, high]
            } else {
                // 1. 目标值等于数组中某一个元素  return mid;
                return mid;
            }
        }
        // 2.目标值在数组所有元素之前 3.目标值插入数组中 4.目标值在数组所有元素之后 return right + 1;
        return high + 1;
    }
}
//第二种二分法:左闭右开
public int searchInsert(int[] nums, int target) {
    int left = 0;
    int right = nums.length; 
    while (left < right) { //左闭右开 [left, right)
        int middle = left + ((right - left) >> 1);
        if (nums[middle] > target) {
            right = middle; // target 在左区间,在[left, middle)中
        } else if (nums[middle] < target) {
            left = middle + 1; // target 在右区间,在 [middle+1, right)中
        } else { // nums[middle] == target
            return middle; // 数组中找到目标值的情况,直接返回下标
        }
    }
    // 目标值在数组所有元素之前 [0,0)
    // 目标值插入数组中的位置 [left, right) ,return right 即可
    // 目标值在数组所有元素之后的情况 [left, right),因为是右开区间,所以 return right
    return right;
}

这两种方法绝了,写出了精髓

977、有序数组的平方

给你一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int lenth = nums.length;
        int[] res = new int[lenth];
        int cnt = nums.length-1; 
        // 两个指针分别向两边搜索较大的那个值
        int left = 0;
        int right = nums.length-1;
        while(left <= right){
            if(Math.abs(nums[left]) <= Math.abs(nums[right])){
                res[cnt] = nums[right] * nums[right];
                cnt--;
                right--;
            }else{
                res[cnt] = nums[left] * nums[left];
                cnt--;
                left++;
            }
        }
        return res;       
    }
}

其实就是简单的双指针的思想。 不过可以把++和--放到赋值运算中去,使代码更简洁。

res[cnt--] = nums[right] * nums[right--];

209、长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target。

找出该数组中满足其和 ≥ target 的长度最小的连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i = 0; //滑动窗口起始位置
        int sum = 0;
        int result = Integer.MAX_VALUE;
        for(int j = 0; j < nums.length; j++){
            sum += nums[j];
            while(sum >= target){
                result = Math.min(result, j - i + 1);
                sum -= nums[i++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

注意滑动窗口的思想,确定窗口终止位置,改变起始位置

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值