二分法查找算法


前言

排序数组的查找问题首先考虑使用二分法解决,可以将遍历法的线性级别时间复杂度降低至对数级别。当数据量很大适宜采用该方法。采用二分法查找时,数据需是有序不重复的。


一、二分法查找的标准形式

基本思想:假设数据是按升序排序的,对于给定值 x,从序列的中间位置开始比较,如果当前位置值等于 x,则查找成功;若 x 小于当前位置值,则在数列的前半段中查找;若 x 大于当前位置值则在数列的后半段中继续查找,直到找到为止。

假设有一个数组 { 12, 23, 34, 45, 56, 67, 77, 89, 90 },现要求采用二分法找出指定的数值并将其在数组的索引返回,如果没有找到则返回 -1。代码如下:

public class BinarySearch{
	public static void main(String[] args){
		int [] arr = new int[] {12,23,34,45,56,67,77,89,90};
		System.out.println(search(arr , 78);
	}
	public static int search(int[] arr , int key){
		int start = 0;
		int end = arr.length - 1;
		while(start <= end){
			int middle = (start + end) / 2;
			if(key < arr[middle]){
				end = middle - 1;
			}else if(key > arr[middle]){
				start = middle + 1;
			}else{
				return middle;
			}
		}
		return -1;
	}
}

二、题目背景及要求

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。请编写一个函数,输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

在这里插入图片描述

三、题目解析

如下图所示,寻找旋转数组的最小元素即为寻找 右排序数组 的首个元素 nums[x]nums[x] ,称 xx 为 旋转点 。
在这里插入图片描述

四、算法流程

1.初始化:声明 i , j 双指针分别指向nums数组左右两端
2.循环二分:设 m = (i + j) / 2 为每次二分法的中点
分一下三种情况

if nums[m] > nums[j]
----------------------------------then min在左排序数组中,即旋转点 x 一定在[m+1,j]闭区间中,因此执行 i = m+1;
if nums[m] < nums[j]
----------------------------------then min在右排序数组中,即旋转点 x 一定在[i , m]闭区间中,因此执行 j = m;
if nums[m] = nums[j]
----------------------------------then min不确定,执行 j–

返回值:当 i = j 时跳出循环,并返回旋转点的值 nums[i]

五、Java代码实现

1.二分法查找

class Solution {
    public int minArray(int[] numbers) {
        int i = 0,j = numbers.length - 1;
        while(i < j){
            int m = (i + j)/2;
            if(numbers[m] > numbers[j]) i = m+1;
            else if(numbers[m] < numbers[j]) j = m;
            else j--;
        }
        return numbers[i];

    }
}

2.改进后的二分法查找

class Solution {
    public int minArray(int[] numbers) {
        int i = 0,j = numbers.length - 1;
        while(i < j){
            int m = (i + j)/2;
            if(numbers[m] > numbers[j]) i = m+1;
            else if(numbers[m] < numbers[j]) j = m;
            else{
                int x = i;
                for(int k = i+1;k < j;k++){
                    if(numbers[k] < numbers[x]) x = k;
                }
                return numbers[x];
            }
        }
        return numbers[i];

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

远方上&肖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值