插值查找法

class Solution {
    public int search(int[] nums, int target) {
        if(nums==null) return -1;
        if(nums.length==1) return target==nums[0]? 0:-1;
        
        int l = 0;
        int r = nums.length-1;
        int m=0;
        
        while(l<r)
        {
            m = l+ (r-l)*(target-nums[l])/(nums[r]-nums[l]);
            int t = nums[m]-target;
            if(t==0)
            {
                return m;
            }else if(t>0)
            {
                r = m-1;
            }else{
                l = m+1;
            }
        }
        return -1;
        
    }
}

leetCode 704题
在这里插入图片描述

然而,这个题写的插值查找法是有bug的
比如说:当 arr[l]==arr[r]时,会出现除0的异常,有一些如果没有检查边界的话,还会出现数组越界异常,这是要小心的地方
所有,二分法也有二分法的好处,插值查找也有其好处,还是要具体问题具体分析

下面给出LeetCode34题 的解法
34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
     public int[] searchRange(int[] nums, int target) {
        if(nums==null||nums.length==0) return new int[]{-1,-1};
        if(target<nums[0]||target>nums[nums.length-1]) return new int[]{-1,-1};

        int l=0,r = nums.length-1,m;
        int count=0;

        while(l<r)
        {
            
            int t = (nums[r]-nums[l]);
            if(t==0)
            {
                if(target<nums[l]||target>nums[r]) break;
                if(nums[l]==target)
                {
                    while(l>=0&&nums[l]==target) --l;
                    while(r<nums.length&&nums[r]==target) ++r;
                    return new int[]{l+1,r-1};
                }
            }
            m = l + (r-l)*(target-nums[l])/t;
            if(nums[m]==target)
            {
                l = m;
                r = m;

                while(l>=0&&nums[l]==target) --l;
                while(r<nums.length&&nums[r]==target) ++r;
                return new int[]{l+1,r-1};

            }else
            {
                int temp = nums[m]-target;
                if(temp>0)
                {
                    r = m-1;
                }else{
                    l = m+1;
                }
            }
            if(++count>7)
            {
                break;
            }
        }
         
        if(nums.length==1&&nums[0]==target)
        {
            return new int[]{0,0};
        }

        return new int[]{-1,-1};


    }
}

这个题我是取了巧,引入一个计数变量 count,如果 count>7就会break
因为如果不break的话,可能会陷入死循环

插值查找
基本思想:基于二分查找,将查找点的选择改进为自适应选择,可以提高查找效率。 将二分查找的插值计算公式改为

mid = low + \tfrac{(value - a[low])}{(a[high] -
a[low])}(high-low)mid=low+(a[high]−a[low])(value−a[low])​(high−low)
时间复杂度:平均情况O(loglog(n)),最坏O(log(n))

注:对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找的平均性能比折半查找要好。

这里我是以最优复杂度来计算的,长度为128的数组,取log 就是7,再取一次 log,就是0.845,总之,如果是最优复杂度来计算的话,用例不多的情况下7次循环内就查出来了

我想了一下,插值查找看看就行了

class Solution {
    public  int[] searchRange(int[] nums, int target) {
        if(nums==null||nums.length==0) return new int[]{-1,-1};
        if(target<nums[0]||target>nums[nums.length-1]) return new int[]{-1,-1};

        int i = index(nums,target);
        if(i==-1)
        {
            return new int[]{-1,-1};
        }

        return expand(nums,i,target);



    }

    private  final int index(int[] nums, int target) {
        if(nums==null) return -1;
        if(nums.length==1) return target==nums[0]? 0:-1;
        int count=0;

        int l = 0;
        int r = nums.length-1;
        int m=0;
        int carry;

        while(l<=r)
        {
            carry = nums[r]-nums[l];
            if(carry!=0)
            {
                m = l+ (r-l)*(target-nums[l])/(nums[r]-nums[l]);
            }else {
                if(nums[l]==target) return l;
                break;
            }
            int t = nums[m]-target;
            if(t==0)
            {
                return m;
            }else if(t>0)
            {
                
                r = m-1;
            }else{
                
                l = m+1;
            }
            if(++count>4) break;
        }
        return -1;

    }

    private final int[] expand(int[] nums,int l,int target)
    {
        int r = l+1;
        while(l>=0&&nums[l]==target) --l;
        while (r<nums.length&&nums[r]==target) ++r;

        return new int[]{l+1,r-1};
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值