您现在的位置是:首页 >学无止境 >代码随想录第一天|二分查找和双指针网站首页学无止境

代码随想录第一天|二分查找和双指针

非科班小白宋宋 2023-05-25 04:00:03
简介代码随想录第一天|二分查找和双指针

Leetcode 704 二分查找

题目链接: 704
自己的思路: 由于是有序数组,所以首先想到使用二分查找,通过取左右两边的中点依次判断与目标值的大小,逐渐缩小判断区间。分左闭右开和左闭右闭两种。
正确思路: 二分查找
左闭右闭

代码:

class Solution {
    public int search(int[] nums, int target) {
        //初始化左右指针为两个端点
        int left = 0;
        int right = nums.length - 1;
        //左闭右闭,right可以取到右边
        while(left <= right){
            //防止数值溢出
            int middle = left + (right-left)/2;
            //左半区间没有目标值(包括middle)
            if (nums[middle]<target) left = middle + 1;
            //右半区间没有目标值(包括middle)
            else if (nums[middle]>target) right = middle - 1;
            //找到目标值
            else return middle;
        }
        //整个数组没有目标值
        return -1;
    }
}

左闭右开
代码:

class Solution {
    public int search(int[] nums, int target) {
        //初始化左右指针为两个端点
        int left = 0;
        int right = nums.length;
        //左闭右开,right取不到右边
        while(left < right){
            //防止数值溢出
            int middle = left + (right-left)/2;
            //左半区间没有目标值(包括middle)
            if (nums[middle]<target) left = middle + 1;
            //右半区间没有目标值(包括middle) 由于right取不到右边,所以设置right为middle
            else if (nums[middle]>target) right = middle;
            //找到目标值
            else return middle;
        }
        //整个数组没有目标值
        return -1;
    }
}

复杂度分析
时间复杂度: O ( log ⁡ ( n ) ) mathcal{O}(log(n)) O(log(n)) n n n为数组的长度
空间复杂度: O ( 1 ) mathcal{O}(1) O(1)

相似题型

Leetcode 35 搜索插入位置

题目链接: 35
自己的思路: 由于是有序数组,所以首先想到使用二分查找,如果找到元素,返回它的索引,如果找不到元素,则找第一个大于target的元素,插在其左边即可。如果在数组中找不到元素的话,那么最终right和left落的位置一定是,left在第一个大于该元素的位置,right在left左边一个位置,所以最终返回left即可
正确思路: 二分查找
左闭右闭

代码:

class Solution {
    public int searchInsert(int[] nums, int target) {
        //定义左右两个指针
        int left = 0;
        int right = nums.length - 1;
        //左闭右闭
        while(left<=right){
            //取中点,防止溢出
            int middle = left + (right - left)/2;
            //右边没有,在左边找
            if (nums[middle] > target) right = middle - 1;
            //左边没有,在右边找
            else if (nums[middle] < target) left = middle + 1;
            //如果在数组中找到元素,返回索引即可
            else return middle;
        }
        //如果找不到元素即返回第一个大于target的索引
        return left;
    }
}

复杂度分析
时间复杂度: O ( log ⁡ ( n ) ) mathcal{O}(log(n)) O(log(n)) n n n表示数组的长度
空间复杂度: O ( 1 ) mathcal{O}(1) O(1)

Leetcode 27 移除元素

题目链接: 27

自己的思路:双指针经典问题,可以定义一个快指针,一个慢指针,快指针在前面判断数组中的值是否等于val,如果不等于则把快指针的值赋给慢指针的位置,然后快慢指针都向前进一步;如果等于,快指针往前进一步,慢指针不动,这样前slow个元素就是移除val以后的数组了,也就是我们想要的。
正确思路:双指针

双指针解法
代码:

class Solution {
    public int removeElement(int[] nums, int val) {
        //定义慢指针
        int slow = 0;
        //快指针遍历,无论fast处的值等不等于val,快指针都前进一步
        for (int fast=0;fast<nums.length;fast++){
            //快指针的值如果不等于val,则将此处的值赋给慢指针位置,慢指针前进一步
            if (nums[fast]!=val){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //因为最后慢指针++了,所以返回前slow个元素即可
        return slow;
    }
}

复杂度分析
时间复杂度: O ( n ) mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) mathcal{O}(1) O(1)

相似题型

Leetcode 26 删除有序数组中的重复项

题目链接: 26

自己的思路:双指针经典问题,可以定义一个快指针,一个慢指针,快指针在前面判断数组中的值是否等于之前慢指针的值,如果不等于则把快指针的值赋给慢指针的位置,然后快慢指针都向前进一步;如果等于,快指针往前进一步,慢指针不动,这样前slow个元素就是移除val以后的数组了,也就是我们想要的。
正确思路:双指针

双指针解法
代码:

class Solution {
    public int removeDuplicates(int[] nums) {
        //定义慢指针,由于要判断慢指针前面一个位置的值作为临时变量,所以慢指针必须从1开始
        int slow = 1;
        //快指针也必须从1开始,无论如何快指针都前进一步
        for (int fast=1;fast<nums.length;fast++){
            //定义临时变量用来记录慢指针前面一个位置的值
            int temp = nums[slow-1];
            //如果快指针不等于之前慢指针的值,则把快指针的值赋给慢指针的位置,慢指针前进一步
            if (nums[fast]!=temp){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //由于最后slow++,所以直接返回slow即可,slow即为新数组的长度
        return slow;
    }
}

复杂度分析
时间复杂度: O ( n ) mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) mathcal{O}(1) O(1)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。