代码随想录算法训练营第一天 | 704.二分查找、27.移除元素、977.有序数组的平方

今天是代码随想录算法训练营的第一天,关于数组的,有一些基础知识,备份如下:

数组是存放在连续内存空间上的相同类型的数据集合;

数组可以通过下标很方便的获取到元素;

数组下标是从0开始;

由于数组在内存地址上是连续的,所以在删除或者添加数组元素时,难免要移动其他元素的地址;

数组元素不能删除,只能覆盖。

704.二分查找

其实断断续续学习过很多次二分查找,思想能够理解,但是代码实现上其实是有需要注意的。

就是二分查找的while条件里,左右区间,可以分为左闭右开和左闭右闭两种方式。

如果是左闭右开的区间,while条件里,left 就不能包括=right,因为left=right没有实际意义,此时while条件应该是while(left < right),这里的right = nums.length;

而在数值判断的if else里,如果target > nums[mid]时,right就应该=mid

代码如下:

class Solution {
    public int search(int[] nums, int target) {
        //二分查找主要是每次通过与中间值进行比较,决定程序是返回还是在左边或者右边查找
        //所以我认为二分查找的重点是如何确认中间值
        int left = 0;
        int right = nums.length;

        //终止条件是left和right指针到一起了
        while(left < right) {//这里right我取的是数组长度,所以这里是左闭右开的区间,因为此时left=right是没有意义的,left最多等于right-1,区间是[left,right-1]
            int mid = left + (right -left) / 2;
            if(nums[mid] == target) {
                return mid;
            }else if(nums[mid] > target) {//去左边查找
                right = mid; //区间是[lelft,middle)
            }else {//去右边查找
                left = mid + 1;//区间是[mid+1,right)
            }
        }
        return -1;

        // //如果是闭区间,要注意的是right的变化,需要mid -1
        // int left = 0;
        // int right = nums.length - 1;
        // while(left <= right) {
        //     int mid = left + (right - left)/ 2;
        //     if(nums[mid] == target) {
        //         return mid;
        //     }if(nums[mid] > target) {//target 在左区间,[left,mid-1]是有意义的
        //         right = mid - 1;
        //     }else {
        //         left = mid;
        //     }
        // }

        // return -1;
    }
}

而在左闭右闭的区间情况下,right = nums.length -1; 此时left = right是有意义的,所以while(left <= right) ,在内层的if else判断中,如果target < nums[mid],此时,right应该等于mid -1;

代码片段如下:

//如果是闭区间,要注意的是right的变化,需要mid -1
        int left = 0;
        int right = nums.length - 1;
        while(left <= right) {
            int mid = left + (right - left)/ 2;
            if(nums[mid] == target) {
                return mid;
            }if(nums[mid] > target) {//target 在左区间,[left,mid-1]是有意义的
                right = mid - 1;
            }else {
                left = mid;
            }
        }

        return -1;

27.移除元素

这题原先我的思路是设定左右两个指针,通过比较两个指针值和target的值,相等或者不相等时移动相应的指针,调试过程中有个别case未通过,看了算法讲解,才明白两种解法都比我的思路要好,贴上相应代码:

暴力解代码片段:

int size = nums.length;
        for (int i = 0; i < size; i++) {
            if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

快慢指针法:

这个方法我看了很长时间,原来是仅仅用慢指针来标记新数组的长度,通过前面的快指针和target做判断,只要快指针对应下标的数组值不等于目标值,就移动慢指针一次,如果快指针下标对应的值是目标值,那慢指针就停下来,等快指针寻找到下一个非目标值的元素,此时慢指针再继续移动,太绝了!

//这里快慢指针的做法太有新意了,慢指针更新新数组的位置,返回满指针的基数就行了。
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
        if (val != nums[fastIndex]) {
              nums[slowIndex++] = nums[fastIndex];
           }
        }
        return slowIndex;

977.数组元素的平方

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

简单粗暴的写法,上来直接数组对应下标上的元素直接平方,最后排序一下即可。

public int[] sortedSquares(int[] nums) {
        //我这里做复杂了,其实都不需要创建一个新数组,直接在原数组上修改就好了
        int[] result = new int[nums.length];

        for(int i = 0; i < result.length; i++) {
            result[i] = nums[i] * nums[i];
            nums[i] *= nums[i];
        }

        Arrays.sort(result);
        //Arrays.sort(nums);
        return result;
}

另一种解法,针对有负数的情况,其实只要判断首尾元素平方后谁大,再按照顺序排入即可。

class Solution {
    public int[] sortedSquares(int[] nums) {
        //我这里做复杂了,其实都不需要创建一个新数组,直接在原数组上修改就好了
        // int[] result = new int[nums.length];

        // for(int i = 0; i < result.length; i++) {
        //     result[i] = nums[i] * nums[i];
        //     nums[i] *= nums[i];
        // }

        // Arrays.sort(result);
        // //Arrays.sort(nums);
        // return result;

        int[] result = new int[nums.length];
        index k = result.length;
        int left = 0;
        int right = nums.length - 1;
        //更快的做法,比较数组前后数字平方的大小,再对应移动较大的那个指针
        while(left <= right) {
            if(nums[left] * nums[left] < nums[right] * nums[right]) {
                result[k--] = nums[right] * nums[right];
                right--;
            }else {
                result[k--] = nums[left] * nums[left];
                left++;
            }
        }
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值