在排序数组列表中查找2个最接近的先前值和2个最接近的下一个值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在排序数组列表中查找2个最接近的先前值和2个最接近的下一个值相关的知识,希望对你有一定的参考价值。
这是一个修改后的二进制搜索,它将排序数组列表中最接近的元素返回给定值。我如何调整它以便它可以返回2个最接近的前2个和2个最接近的下一个元素?
private static Long search(long value, ArrayList<Long> a) {
if(value < a.get(0)) {
return a.get(0);
}
if(value > a.get(a.size()-1)) {
return a.get(a.size()-1);
}
int lo = 0;
int hi = a.size() - 1;
while (lo <= hi) {
int mid = (hi + lo) / 2;
if (value < a.get(mid)) {
hi = mid - 1;
} else if (value > a.get(mid)) {
lo = mid + 1;
} else {
return a.get(mid);
}
}
return (a.get(lo) - value) < (value - a.get(hi)) ? a.get(lo) : a.get(hi);
}
例如,让我们考虑我的数组列表由以下元素组成:
[101, 201, 301, 401, 501, 601, 701, 801, 901, 1001]
我被赋予了730的值。我希望搜索返回一个由4个元素组成的数组,其中包含601,701作为前一个值,801和901作为下一个值。
答案
使用非常简单的方法,此代码根据lo
,hi
和mid
值之间的差异将元素添加到结果列表中。
在边缘情况下,返回的元素数量可以小于4.例如,如果左侧或右侧没有元素(由于列表边界),返回的列表大小可以是2或3,具体取决于最接近的值的位置。
如果这是你想要的,那么这里是代码:
private static List<Long> search(long value, List<Long> a) {
if (a.size() < 3) return new ArrayList<>(a);
List<Long> result = new ArrayList<>();
if (value < a.get(0)) {
result.add(a.get(0));
result.add(a.get(1));
return result;
}
if (value > a.get(a.size() - 1)) {
result.add(a.get(a.size() - 2));
result.add(a.get(a.size() - 1));
return result;
}
int lo = 0;
int hi = a.size() - 1;
int match = -1;
while (lo <= hi) {
int mid = (hi + lo) / 2;
if (value < a.get(mid)) {
hi = mid - 1;
} else if (value > a.get(mid)) {
lo = mid + 1;
} else {
match = mid;
break;
}
}
if (match >= 0) {
if (match > 1) result.add(a.get(match - 2));
if (match > 0) result.add(a.get(match - 1));
if (match < a.size() - 1) result.add(a.get(match + 1));
if (match < a.size() - 2) result.add(a.get(match + 2));
} else if (a.get(lo) < value) {
result.add(a.get(hi));
result.add(a.get(lo));
if (lo < a.size() - 1) result.add(a.get(lo + 1));
if (lo < a.size() - 2) result.add(a.get(lo + 2));
} else if (a.get(hi) > value) {
if (hi > 1) result.add(a.get(hi - 2));
if (hi > 0) result.add(a.get(hi - 1));
result.add(a.get(hi));
result.add(a.get(lo));
} else {
if (hi > 0) result.add(a.get(hi - 1));
result.add(a.get(hi));
result.add(a.get(lo));
if (lo < a.size() - 1) result.add(a.get(lo + 1));
}
return result;
}
另一答案
有一种简单的方法来扩展原始代码以适应返回四个值的列表,并且它相对容易:
private static List<Long> search(long value, ArrayList<Long> a) {
List<Long> returnList = new ArrayList<>();
if (null == a) {
return null;
}
if (a.isEmpty()) {
return a;
}
if (a.size()==1) {
return a;
}
if(value < a.get(0)) {
returnList.add(a.get(0));
returnList.add(a.get(1));
return returnList;
}
if(value > a.get(a.size()-1)) {
returnList.add(a.get(a.size()-1));
returnList.add(a.get(a.size()-2));
return returnList;
}
int lo = 0;
int hi = a.size() - 1;
while (lo <= hi) {
int mid = (hi + lo) / 2;
if (value < a.get(mid)) {
hi = mid - 1;
} else if (value > a.get(mid)) {
lo = mid + 1;
} else {
if (mid>1) returnList.add(a.get(mid-2));
if (mid>0) returnList.add(a.get(mid-1));
if (mid<=a.size()-1) returnList.add(a.get(mid+1));
if (mid<=a.size()-2) returnList.add(a.get(mid+2));
return returnList;
}
}
if ((a.get(lo) - value) < (value - a.get(hi))) {
if (lo > 0) returnList.add(a.get(lo-1));
returnList.add(a.get(lo));
if (lo<=a.size()-1) returnList.add(a.get(lo+1));
if (lo<=a.size()-2) returnList.add(a.get(lo+2));
} else {
if (lo > 1) returnList.add(a.get(hi-2));
if (lo > 0) returnList.add(a.get(hi-1));
ReturnList.add(a.get(hi));
if (hi<=a.size()-1) returnList.add(a.get(hi+1));
}
return returnList;
}
但是,如果我们扩展代码,那么可能是进行一些小型重构的最佳时机,以使其更具可读性。
private static List<Long> addNumbersAroundIndex (int index, Long searchedNum, int numOfElements, List<Long> list) {
List<Long> returnList = new ArrayList<Long>();
int before = numOfElements/2;
int after = numOfElements - before;
if (list.get(index)>searchedNum) {
after --;
} else if(list.get(index)<searchedNum) {
before--;
}
for (int i=before; i>0; i--) {
if (index>i+1) returnList.add(list.get(index-i));
}
if (!list.get(index).equals(searchedNum)) {
returnList.add(list.get(index));
}
for (int i=1; i< after+1; i++) {
if (index+i<=list.size()-1) returnList.add(list.get(index+i));
}
return returnList;
}
private static List<Long> search(long value, int numOfElements, ArrayList<Long> a) {
if (null == a) {
return null;
}
if (a.isEmpty()) {
return a;
}
if (a.size()==1) {
return a;
}
if(value < a.get(0)) {
return addNumbersAroundIndex(0, value, numOfElements,a);
}
if(value > a.get(a.size()-1)) {
return addNumbersAroundIndex(a.size()-1, value,numOfElements,a);
}
int lo = 0;
int hi = a.size() - 1;
while (lo <= hi) {
int mid = (hi + lo) / 2;
if (value < a.get(mid)) {
hi = mid - 1;
} else if (value > a.get(mid)) {
lo = mid + 1;
} else {
return addNumbersAroundIndex(mid,value,numOfElements,a);
}
}
if ((a.get(lo) - value) < (value - a.get(hi))) {
return addNumbersAroundIndex(lo,value,numOfElements,a);
} else {
return addNumbersAroundIndex(hi,value,numOfElements,a);
}
}
使用您的一些原始列表进行测试:
public static void main(String[] args) {
ArrayList<Long> list = new ArrayList(Arrays.asList(101l, 201l, 301l, 401l, 501l, 601l, 701l, 801l, 901l, 1001l));
System.out.println(search(1020l,5,list));
}
[801, 901, 1001]
System.out.println(search(730l,4,list));
[601, 701, 801, 901]
System.out.println(search(601l,5,list));
[401, 501, 701, 801, 901]
以上是关于在排序数组列表中查找2个最接近的先前值和2个最接近的下一个值的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 1460. 通过翻转子数组使两个数组相等 / 658. 找到 K 个最接近的元素 / 1464. 数组中两元素的最大乘积
LeetCode 1460. 通过翻转子数组使两个数组相等 / 658. 找到 K 个最接近的元素 / 1464. 数组中两元素的最大乘积