【劍指offer】二維陣列中的查詢——複雜度為O(n+m)——採用PHP寫法
背景
今天偶然進入牛客網,看到《劍指offer》模組有演算法題,就開始試著答題
題目描述
在一個二維陣列中(每個一維陣列的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
一開始我的思路比較笨,不就直接遍歷二維陣列嘛?
輸入以下程式碼提交了
<?php function Find($target, $array) { // write code here for($i = 0; $i < count($array[0]); $i++){ for($j = 0; $j < count($array[1]); $j++){ if($target === $array[$i][$j]){ return 1; } } } }
雖說第一次直接提交成功了,但是感覺好像這個時間複雜度有點高
仔細審了題,使用另外一種思路作答
思路:
- 由於題目中的二維陣列是有序排列的,而且是根據每一行從左到右遞增,每一列從上到下遞增,那麼在查詢二維陣列的時候,可以通過這個規律來改變實現方法
- 從每一個二維陣列的左下角跟右上角開始查詢比較方便(至於為什麼方便,大家可以自己思考一下)
1、假設從右上角開始查詢
如果$target < $array[$i][$j],則往左邊移動一個單位(即$j--);
如果$target > $array[$i][$j],則往下邊移動一個單位(即$i++);
如果$target = $array[$i][$j],則返回true;
2、假設從左下角開始查詢
如果$target < $array[$i][$j],則往上邊移動一個單位(即$i--);
如果$target > $array[$i][$j],則往右邊移動一個單位(即$j++
如果$target = $array[$i][$j],則返回true;
程式碼實現:
<?php
function Find($target, $array)
{
$length = count($array[0]); //一維陣列的長度
$i = 0; //起始橫座標
$j = $length - 1; //起始縱座標
for($n = 0; $n < ($length - 1) + (count($array) - 1); $n++){ //最多移動$length減1 + 二維陣列長度減1次
if($array[$i][$j] === $target){//查詢到目標,返回true
return true;
}
if($array[$i][$j] < $target){//查詢目標大於右上角元素,則$i++,下移
$i++;
continue;
}
if($array[$i][$j] > $target){//查詢目標小於右上角元素,則$j--,左移
$j--;
continue;
}
}
}
程式碼講解:
for迴圈中,最多隻需要移動$length減1 + 二維陣列長度減1 次,什麼意思呢?
畫個圖你們就明白了
假設有如下二維陣列:
我們從右上角開始查詢22這個數
由於22比8大,所以我們先下移,22比18大,我們繼續下移,由於22比28小,我們需要左移......
最終我們移動了8次才找到22這個數,而且8次是移動次數最多的,為什麼呢?
因為每一次只能下移或者左移,所以
左移次數最多6次(即一維陣列長度減1次)
下移次數最多2次(即二維陣列長度減1次)
這就是為什麼for迴圈中,最多需要迴圈$length減1 + 二維陣列長度減1次,$length就是一維陣列的長度
因此這個演算法的時間複雜度為O(n+m),其中n為一維陣列的長度,m為二維陣列的長度(忽略減去的2次)
相比之前的O(n*m),還是快了些的。
總結
牛客網真的是一個很不錯的網址,上面不僅有大量的試題,而且還有很多大佬的經驗分享,值得大家去好好利用這個資源,相信牛客網能給各位帶來許多幫助,一起加油!