【一天三道算法题】代码随想录刷题——Day1

找了很多的刷题网站,也看过很多的课,包括之前的牛客,左神的课,老韩的课,都没能坚持下来。

算法这东西,正反馈确实少,忘的确实快。

之前牛客每日一题也没坚持下来,确实是惰性太严重了。

从今天开始,正式一天三道题,刷不完不睡觉。

PS:连这做不到就别想着进大厂了。

代码随想录个人觉得还是挺不错的一个网站,从容易的题开始做也不容易被劝退。

一. 二分查找

题目链接:力扣

思路

        这是很基础的一个题了,大伙儿多少应该都会写。当然也不排除有像我一样的算法小白,还是简单地说一下。

        这类题都有两个先决条件,必须满足。

                1. 有序

                2. 数组中无重复元素

        有同学会问了,那要不满足呢?

        不满足就不能用二分去做,再想想别的招儿。

        思路是很清晰的:取中值,比大小。

        比中值大就说明在小的区间里,比中值小就说明在大的区间里。

        不断地重复该过程,直到元素拥有原子性,不可再次拆分。

        实话说,很简单。但大家可能就经常性地像我一样,一看就会,一做就废。因为它虽然思路简单,但循环边界的判断却是一个难点。

这里按照不同的题型,分为两种情况。

        1. 左闭右闭 [ left, right ]

        2. 左闭右开 [ left, right )

先说左闭右闭的情况。

        - while(left <= right)的判断条件应该为 <= ,因为这种情况下 left == right是有意义的。

        - if(nums[mid] > target) { right = mid - 1} ,因为当前 nums[mid] 的值一定不是 target,那么接下来要寻找的左区间的结束下标就是 mid - 1。

上代码。

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int rigth = nums.length-1;
        while(left <= right){
            //计算中值,这样计算的中值好处就是不会出现负坐标的情况
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                return mid;
            } else if(nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}

再说左闭右开的情况。

        - while(left < right)的判断条件应该为 < ,因为在 [ left,right ) 的这种情况下 left == right变得没有意义。

        - if(nums[mid] > target) {right = mid},此处right应直接赋值为 mid ,因为当前nums[mid]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[mid]。

上代码。 

class Solution {
    public int search(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){
                right = mid;
            } else {
                left = mid+1;
            }
        }
        return -1;
    }
}

二.搜索插入位置

题目链接:力扣

这道题其实就是上面二分查找的应用,我们学会一道题之后,不但要学会解它本身,还要学会把它用起来,玩起来,解决类型题。

思路:

        如果该题目暴力解决的话需要O(n) 的时间复杂度,但是如果二分的话则可以降低到 O(logn) 的时间复杂度。
        整体思路和普通的二分查找几乎没有区别,先设定左侧下标 left 和右侧下标 right,再计算中间下标 mid
        每次根据 nums[mid] 和 target 之间的大小进行判断,相等则直接返回下标,nums[mid] < target 则 left 右移,nums[mid] > target 则 right 左移
        查找结束如果没有相等值则返回 left,该值为插入位置。

        还是和普通二分一样,分两种情况做。

1.左闭右闭

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){
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        //若找不到,返回它将会被顺序插入的位置(下标)
        return left;
    }
}

2.左闭右开 

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){
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        //若找不到,返回它将会被顺序插入的位置(下标)
        return left;
    }
}

三.在排序数组中查找元素的第一个和最后一个位置

题目链接:力扣

思路:

        1. 先使用二分法,判断数组中是否存在target

        2. 分别通过滑动左、右边界的方式去求target的范围(注意不能越界)

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int index = binarySearch(nums, target);
        if(index == -1){
            return new int[]{-1, -1};
        }

        //target存在,滑动边界去寻找区间
        int left = index;
        int right = index;
        //向左滑动,寻找左边界
        while(left - 1 >= 0 && nums[left - 1] == nums[index]){  
            //防止数组越界,逻辑短路 条件顺序不能更改
            left--;
        }
        //向右滑动,寻找右边界
        while(right + 1 < nums.length && nums[right + 1] == nums[index]){
            right++;
        }
        return new int[]{left, right};
    }
    public int binarySearch(int[] nums, int target){
        int left = 0;
        int right = nums.length-1;
        //先使用二分查找确认target存不存在
        while(left <= right){
            int mid = left + (right-left) / 2;
            if(nums[mid] == target){
                return mid;
            } else if(nums[mid] > target){
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        //target不存在
        return -1;
    }
}

第一天顺利结束,我一定,一定要坚持下去。

你可能感兴趣的:(每天三道题,算法)