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};
}
}