704.二分查找和27. 移除元素

704.二分查找

题目链接为:

704.二分查找

要求:

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

解答:

二分查找是针对于排好序的数组,如果数组没有排好序,则不能用二分查找算法,二分查找的时间复杂度为 O(n)。

二分查找的难点在于边界条件,边界如何确定关键在于你是选择的什么区间,你是选择的左闭右开,还是左闭右闭呢?选择不同的区间,写法会稍微有点不同。

当选择左闭右闭的时候,首先要确定的是 left = 0, right = nums.length - 1,因为两边都是有效值,所以在 while 条件中,left ≤ right,当判断如果 nums[middle] > targetright = middle - 1 还是等于 middle 呢?还是看右边界,因为我们现在是右闭的,所以 middle 已经进行了判断,这个时候就是 right = middle - 1

当选择左闭右闭的时候,因为右侧是无效值,也就是永远取不到,所以 left = 0, right = nums.length ,并且在 while 条件中,left ≠ right,所以是left < right,当判断如果 nums[middle] > targetright = middle - 1 还是等于 middle 呢?还是看右边界,因为我们现在是右开的,所以就是 right = middle

/**
     * 题目要求使用二分查找,二分查找最关键的就是边界问题,先使用左闭右闭的写法
     * 我这边的想法是 left 为 0, right 为最大索引,然后取中间值,因为题目中已经排好序,所以这边不用重复排序
     * 根据中间值判断就有三中情况:
     * 1. 相等,则返回索引
     * 2. 大于,说明目标值在左半部分,所以 right = middle - 1,为什么不是 middle,因为 middle 已经判断过了,下面是相同的道理
     * 3. 小于,说明目标值在右半部分,所以 left = middle + 1
     * @param nums  有序数组
     * @param target  目标值
     * @return 目标值的索引
     */
    public static int search(int[] nums, int target) {
        // 不同点 1
        int left = 0, right = nums.length - 1;
        // 不同点 2
        while (left <= right) {
            int middle = (left + right) / 2;
            if (nums[middle] == target) {
                return middle;
            }
            if (nums[middle] < target) {
                left = middle + 1;
            } else {
                // 不同点 3
                right = middle - 1;
            }
        }
        return -1;
    }

/**
     * 左闭右开 的写法
     */
    public static int search2(int[] nums, int target) {
        int left = 0, right = nums.length;
        while (left < right) {
            int middle = (left + right) / 2;
            if (nums[middle] == target) {
                return middle;
            }
            if (nums[middle] < target) {
                left = middle + 1;
            } else {
                right = middle;
            }
        }
        return -1;
    }

27. 移除元素

题目链接为:

27. 移除元素

要求:

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

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

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

解答:

这道题目就是原地删除,如果不考虑题目要求,我们可以使用另外一个集合,然后在遍历原数组的时候把不相等的放入另外一个集合,现在有了要求,不是用额外的空间,并且不需要考虑数组中超出新长度后面的元素,那我们可以用双指针的写法,思路就是两个指针,碰到不等于 target 的,就把左指针的元素替换为右指针,如果等于 target,则将右指针元素 + 1,下面右两种不同的写法,后一种更为简单。

public static int removeElement(int[] nums, int val) {
        int left = -1, right = 0;
        while (right < nums.length) {
            if (nums[right] == val && left == -1) {
                left = right;
            }
            if (nums[right] != val && left != -1) {
                nums[left ++] = nums[right];
            }
            right ++;
        }
        return left == -1 ? nums.length : left;
    }

    /**
     * 更简单的写法
     * @param nums 原数组
     * @param val  目标元素
     * @return 移除后数组的新长度
     */
    public static int removeElement2(int[] nums, int val) {
        int left = 0, right = 0;
        for (int num : nums) {
            if (num == val) {
                right ++;
            } else {
                nums[left ++] = nums[right ++];
            }
        }
        return left;
    }
posted @ 2023-12-12 22:59  庄子游世  阅读(27)  评论(0编辑  收藏  举报