检测一个已经排序好的数组中任意两个元素之和是否等于某个值
题目的要求是检测一个已经按照从小到大的方式排序的数组中,检测任意两个数的和是否存在某个值,多个也可,只有一个存在就成立。
例子
这有一个数组:
var arr = [1,2,3,4,5,6,7,8,9]
现在需要检测该数组的任意两个元素中是否存在两个值相加等于5 如果存在直接返回true
否则返回false
自己想到的第一个方案:
function check(arr,numToCheck){
for(var i = 0 ; i < arr.length; i++){
for(var j = 0; j < arr.length; j++ ){
if(arr[i] + arr[j] === numToCheck){
return true;
}
}
}
return false;
}
var arr = [1,2,3,4,5,6,7,8,9];
var x = check(arr,7);
这个方式的确可以解决问题,但是时间复杂度是最高的,因为遍历了所有的情况,而且某个已经检测过的组合会再检测一次,比如1和8 以及8和1(这是没必要的)而且数组中的元素还有可能是同一个,有悖于问题的要求:
例如:
arr = [1,4,6,8,10]
当出现这样一个数组的时候,假如要检测的任意两个元素和是否存在16的情况,按理来说是不存在的,但是当数组遍历到8这个元素的时候会输出true
修改版本
function check1(arr,numToCheck){
for(var i = 0 ; i < arr.length; i++){
for(var j = i; j < arr.length; j++){
if(arr[i]+arr[j] === numToCheck)return true;
}
}
return false;
}
var value1 = check1(arr,5);
console.log(value1);
这样做,可以满足题目的要求,假如数组长度为n,最糟糕的情况程序将会运行n*(n-1)/2词时间复杂度还是n方。
高级版本
事实上,既然是已经经过排序的数组,其实很多情况是可以被排除的,比如假如这个数组中的最小值加上这个元素的和比要检测的值要大,那么这个最小值加上这个比这个元素还要大的右边的元素就没必要了,因为肯定是要比原来大的,根本不用检测。反之,数组中最大的元素加上这个数组的某个元素比要检测的值更小,那么就不用考虑比这个元素小的元素了,比如以之前的例子,假如数组是[1,2,3,4,5,6,7,8]
,我们平常思维判断,5以后的元素根本不用考虑,因为它本身就比和要大或者相等了,在加上一个即便是最小值的1,也不可能会等于5。因此这样的情况需要全部忽略。
版本3:
function check2(arr,numToCheck){
var i = 0;
var j = arr.length - 1;
var x = 0;//x是为了避免出现死循环--
while(i < j && x < 1000){
if(arr[i] + arr[j] > numToCheck){
j = j - 1;//右边指针往左移动
console.log('数组右边指针向左移动一个单位此时指向的元素索引是'+j)
}
if(arr[i] + arr[j] < numToCheck){
i = i + 1;//左边指针往右移
console.log('数组左边的指针向右移动了一个单位,此时指向的元素索引是'+i)
}
console.log('目前指针情况:左边:'+i+',右边:'+j);
if(arr[i] + arr[j] === numToCheck){
console.log('情况成立')
return true;
}
x = x +1;
}
return false;
}
arr = [1,4,5,8,9,10,11,13,24,33,34];
var value2 = check2(arr,32);
console.log('value2:'+value2);
在每次循环体中指针可能会移动一次或者两次,这个循环最多会进行n次,即不存在的情况。但是到目前为止这个算法过程还稍微有点问题。
假如数组为[1,4,5,8,9,10,10.1,13,24,33,34]
要检测的值是20,这个按理来说是返回false的。而使用上面的算法返回了true,原因是在最后的循环中,指针移动到了一起,在6个元素,即值为10的元素上重叠了,此时10+10 = 20 是成立的,但是这却不是我们想要的,因此在判断相等之前,先确认这两个指针是否重叠。
最终:
function check2(arr,numToCheck){
var i = 0;
var j = arr.length - 1;
var x = 0;
while(i < j && x < 1000){
if(arr[i] + arr[j] > numToCheck){
j = j - 1;//右边指针往左移动
console.log('数组右边指针向左移动一个单位此时指向的元素索引是'+j)
}
if(arr[i] + arr[j] < numToCheck){
i = i + 1;//左边指针往右移
console.log('数组左边的指针向右移动了一个单位,此时指向的元素索引是'+i)
}
console.log('目前指针情况:左边:'+i+',右边:'+j);
if(i === j)return false;//指针重叠的情况
if(arr[i] + arr[j] === numToCheck){
console.log('情况成立')
return true;
}
x = x +1;
}
return false;
}