檢測一個已經排序好的陣列中任意兩個元素的和是否存在等於某個值
檢測一個已經排序好的陣列中任意兩個元素之和是否等於某個值
題目的要求是檢測一個已經按照從小到大的方式排序的陣列中,檢測任意兩個數的和是否存在某個值,多個也可,只有一個存在就成立。
例子
這有一個數組:
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;
}