牛客算法题(二分查找篇)

前言

今天接着学习牛客网的二分查找算法,不断刷类似的题目,让我们能够更快的掌握这种方法。

二分查找法的主要思路:
1.从数组首尾开始,每次取中点值。
2.如果中间值等于目标即找到了,可返回下标,如果中点值大于目标,说明中点以后的都大于目标,因此目标在中点左半区间,如果中点值小于目标,则相反。
3.根据比较进入对应的区间,直到区间左右端相遇,意味着没有找到。

1.BM17 二分查找-I

描述
请实现无重复数字的升序数组的二分查找

给定一个 元素升序的、无重复数字的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标(下标从 0 开始),否则返回 -1

进阶:时间复杂度 O(\log n)O(logn) ,空间复杂度 O(1)O(1)

实例1

输入:
[-1,0,3,4,6,10,13,14],13

返回值:
6

说明:
13 出现在nums中并且下标为 6  

实例2

输入:
[],3
 
返回值:
-1

说明:
nums为空,返回-1   

我的答案

import java.util.*;

public class Solution {
    public int search (int[] nums, int target) {
        // 定义左右两个指针
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            int mid = (left + right)/2;
            if(nums[mid] == target){
                return mid;
            }
            //如果target比nums[mid]大,说明在mid右边区域,需要移到右半部分
            else if(nums[mid] < target){
                left = mid + 1;
            }
            //如果target比nums[mid]小,说明在mid左边区域,需要移到左半部分
            else{
                right = mid - 1;
            }
        }
        //如果循环结束之后,都没有出现,说明数组为空或者这个数不存在
        return -1;
    }
}

2.BM18 二维数组中的查找

描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。

给定 target = 3,返回 false。

进阶:空间复杂度 O(1)O(1) ,时间复杂度 O(n+m)O(n+m)

示例1

输入:
7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值:
true

说明:
存在7,返回true  

示例2

输入:
1,[[2]]

返回值:
false

实例3

输入:
3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值:
false

说明:
不存在3,返回false 

我的答案:

public class Solution {
    public boolean Find(int target, int [][] array) {
        //没啥好说的,和上一题基本思路一样,就是在提交之后加了对空数组的判断
        //然后因为是二维数组,多加了一次遍历,从上一个数组到下一个数组
        if (array.length == 0 || array[0].length == 0){
            return false;
        }
        for(int i = 0; i < array.length; i++){
            int left = 0;
            int right = array[i].length - 1;
            while(left <= right){
            int mid = (left + right)/2;
            if(target == array[i][mid]){
                return true;
            }
            else if(target > array[i][mid]){
                left = mid + 1;
            }
            else{
                right = mid - 1;
            }
            }
        }
        return false;
    }
}

3.BM19 寻找峰值

描述
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = -\infty−∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?

如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:

示例1

输入:
[2,4,1,2,7,8,4]

返回值:
1

说明:
4和8都是峰值元素,返回4的索引1或者8的索引5都可以     

示例2
输入:

[1,2,3,1]

返回值:
2

说明:
3 是峰值元素,返回其索引 2     

我的答案:

import java.util.*;


public class Solution {
    public int findPeakElement (int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left < right){
            int mid = (left + right)/2;
            //如果mid比right大,说明峰值在左边
            if(nums[mid] > nums[right]){
                right = mid;
            }
            //如果mid比right大,说明峰值在右边
            else{
                left = mid + 1;
            }
        }
        return right;
    }
}

4.BM21 旋转数组的最小数字

描述
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)

示例1:

输入:[3,4,5,1,2]

返回值:1

示例2:

输入:[3,100,200,3]

返回值:3

我的答案:

import java.util.*;
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        //其实找最小数字就是找旋转点,因为在旋转之前数组是有序的
        //定义两个指针
        int left = 0;
        int right = array.length - 1;
        while (left < right){
            int mid = (left + right)/2;
            //说明旋转点在右边
            if(array[mid] > array[right]){
                left = mid + 1;
            }
            //缩小范围判断,因为这是个旋转数组
            else if(array[mid] == array[right]){
                right--;
            }
            //说明旋转点在左边
            else{
                right = mid;
            }
        }
        return array[right];
    }
}

总结:

其实二分查找法整体来说还是一种比较简单的算法,只要在使用过程中注意区间的开闭即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十三豆啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值