Java算法(八):力扣:数组专题:二分查找、移除元素、有序数组的平方、长度最短的子数组

本篇博客练习数组专题:

1.二分查找

本题的关键在于处理好边界问题,例如

  1. 进行循环时,到底是 while(left < right) ,还是 while(left <= right)?
  2. 区间指针移动时,到底是 right=middle,还是right=middle - 1?

答案是:

  1. 如果target 是在一个在左闭右闭的区间里,也就是[left, right], 此时就是while (left <=right),right = middle - 1。
  2. 如果target 是在一个在左闭右开的区间里,也就是[left, right), 此时就是while (left <right),right = middle。

弄明白了这个问题,二分查找的题就比较清楚了。以下给出第一种写法:

/*
        给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target,
        写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
     */
    
    public static void main(String[] args) {
        search(new int[]{-1,0,3,5,9,12}, 9);
        search(new int[]{-1,0,3,5,9,12}, 2);
    }

    // 双指针,一左一右
    public static int search(int[] nums, int target) {
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }

        int l = 0;
        int r = nums.length -1;
        // target 是在一个在左闭右闭的区间里,也就是[left, right]
        // 决定了middle指针如何移动
        while (l <= r) {
            int middle = (int) Math.floor(l + r);
            if (nums[middle] > target) {
                r = middle - 1;
            } else if (nums[middle] < target) {
                l = middle + 1;
            } else {
                System.out.println(middle);
                return middle;
            }
        }
        System.out.println("-1");
        return -1;
    }

2.移除元素

本题采用快、慢双指针解法。
快指针指向不需要删除的元素,放入到新数组中;
慢指针指向新数组元素的下标。

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

        不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
        元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
     */

    public int removeElement(int[] nums, int val) {
        // 双指针:
        // fast指针:指向不需要删除的元素,放入到新数组中
        // slow指针:指向新数组元素的下标
        int slow = 0;
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast]; //把fast指针指向的元素 赋值给slow指针指向的元素
                slow++;
            }
        }
        return slow; //slow的大小即为新数组长度
    }

3.有序数组的平方

本题给出两种解法:
(1)暴力求解: 先把数组全部元素平方,再排序;
(2)双指针解法: 同样是左、右两指针,分别指向数组的头、尾元素。与上题移除元素类似的是, 本题往新数组里更新元素时,先更新值最大的元素(也就是从下标最大处倒着更新)

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

    // 1.双指针
    public int[] sortedSquares(int[] nums) {
        int l = 0;
        int r = nums.length - 1;
        // 往新数组里更新元素时,先更新值最大的元素
        // 也就是从下标最大处倒着更新
        int[] result = new int[nums.length];
        int index = nums.length - 1;
        while (l <= r) {
            if (nums[l] * nums[l] > nums[r] * nums[r]) {
                result[index] = nums[l] * nums[l];
                index--;
                l++; //l往右走
            } else {
                result[index] = nums[r] * nums[r];
                index--;
                r--; //r往左走
            }
        }
        return result;
    }

    // 2.暴力求解
    public int[] sortedSquares2(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            nums[i] *= nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }

4.长度最短的子数组

本题采用的是滑动窗口的思想:

  1. 滑动窗口就是 满足其和 ≥ target 的长度最小的 连续 子数组。
  2. 窗口的起始位置如何移动?
    如果当前窗口的所以元素的和大于target了,窗口就要向前移动了(也就是该缩小了)。
  3. 窗口的结束位置如何移动?
    窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
/*
        给定一个含有 n 个正整数的数组和一个正整数 target。
        找出该数组中满足其总和>=target的长度最小的 连续 子数组,并返回其长度。

        如果不存在符合条件的子数组,返回 0 。
     */

    // 滑动窗口(双指针)
    public int minSubArrayLen(int target, int[] nums) {
        int l = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        // 先移动窗口终止位置
        for (int r = 0; r < nums.length; r++) {
            sum += nums[r];
            while (sum >= target) {
                // 统计满足条件的 子数组长度
                result = Math.min(result, r - l + 1);
                // sum先减去起始位置的值,再移动起始指针
                sum -= nums[l++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值