代码随想录day01-数组(二分查找)

力扣:35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

思路:

1.我们可以遍历这个数组把各个元素与目标值target比较,如果相等直接返回对应下标就ok。

2.如果元素不存在,我们就要插入它的对应位置,按顺序的,所以插入到第一个大于它的元素前面就ok,对应位置就是第一个大于它的元素的下标,后面的元素后面移动就好了,此题不用,只用返回下标。

题解:

暴力解法

class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i = 0;i < nums.length;i++){
            if(nums[i]>=target)
            return i;
        }
        return nums.length;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

 二分法:1.元素在里面我们就正常找就是mid,2.目标值在数组所有元素之后right+1(left),3.目标值在数组所有元素之前right会到到下标-1,直接right+1(left)将好,4.需要插入到里面,因为没有这个元素left和right会相等,这个元素是左边以及它是小于目标值target,右边大于目标值target,最后一次循环有left+1或right-1,所以对应位置就是left或rigth+1

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0,right = nums.length - 1;
        while(left<=right){
            int mid = (right - left) / 2 + left;
            int num = nums[mid];
            if(num == target){
                return mid;
            }else if(num > target){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

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

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:你可以设计并实现时间复杂度为 $O(\log n)$ 的算法解决此问题吗?

示例 1:

  • 输入:nums = [5,7,7,8,8,10], target = 8
  • 输出:[3,4]

示例 2:

  • 输入:nums = [5,7,7,8,8,10], target = 6
  • 输出:[-1,-1]

示例 3:

  • 输入:nums = [], target = 0
  • 输出:[-1,-1]

思路:

方式一:1、首先,在 nums 数组中二分查找 target; 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间

方式二:看了好久终于理解了,两步,先找到最右边的,再找到最左边的,右边:我们要一直先移动右边的指针,直到中间值小于等于目标值target  左边:我们要一直先移动左边的指针,直到中间值大于等于目标值target

 题解:

方式一

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int index = binarySearch(nums,target);
        if(index == -1)//没有target值直接返回[-1,-1]
            return new int[]{-1,-1};
        //向左右移动找相同的值
        int left = index,right = index;
        //移动过程中left-1,right+1防止越界
        while(left > 0 && nums[left-1]==nums[index]){
            left--;
        }
        while(right < nums.length-1 && 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; 
    
    while (left <= right) { 
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1; 
        }
    }
    return -1; 
}
}

方式二:

class Solution {
    int[] searchRange(int[] nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一
        if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
        // 情况三
        if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
        // 情况二
        return new int[]{-1, -1};
    }

    int getRightBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }

    int getLeftBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
}

 69.x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

 思路:既然返回值是int类型,从1开始到x,计算i*i和(i+1)*(i+1)在这之间的就等于i。

题解:

暴力方法

class Solution {
    public int mySqrt(int x) {
        int num=0;
        for(int i=1;i<=x;i++){
            if(i*i<=x&&(long)(i+1)*(i+1)>x){
                num=i;
                break;
            }
        }
        return num;
    }
}

二分法:

class Solution {
    public int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long) mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
}

367.有效的完全平方数

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如  sqrt 。

示例 1:

输入:num = 16
输出:true
解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。

示例 2:

输入:num = 14
输出:false
解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。
class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 0, right = num;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            long square = (long) mid * mid;
            if (square < num) {
                left = mid + 1;
            } else if (square > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值