求解數組中任意兩個元素的和最接近某一個數

題意是這樣的:求解一個數組中元素a和b,其和sum=a+b,sum最接近num的數兩個。array是一個整型數組。

其求解方式如下:

//求解數組中元素a和b,其和sum=a+b,sum最接近num的數兩個。
//求解思想是:對數組進行順序排序,然後對數組中的每個數遍歷每個數能求得一個最優值,然後對每對值大小sum與給出的這個數num做比較,找出絕對值相差最小的那個數。
//以下程序是對以上的一個簡單變化,其比較的是兩個值sum-num的絕對值大小,找到絕對值最小的值。
//這個過程就是流水式的,在一次流水式的比較和判定過程就能確定下來,將對應的值存儲在變量中,這裏是c_1和c_2。
//這裏還有帶說明的是,在固定一個值查找另外一個值時,我使用的是$tmp=$num - $array[$i]查出與該數最接近的數,並返回其下標,獲取對應的值最終就可以得到最小的最優值。
//只要該最優值最小,就可以確定該組數值。
$array = [5,67,56,32,16,19];
//$c_1,$c_2是存放找到的兩個數值。
$c_1 = 0;
$c_2 = 0;
//最優值,在這裏其
$opt = 0;
//輸入的數
$num = 33;
//開始:
//分兩步
//1.先排序
//2.判定
//3.查找
sort($array);
//依次遍歷數組中的數其每個值的最優值
$length = count($array);
//數組元素個數大於2個
if($length < 2) exit("error array length");
//判斷端數值
if($num <= ($array[0] + $array[0])){
    $c_1 = $array[0];
    $c_2 = $array[1];
}
else if($num >= ($array[$length - 1]+$array[$length-1]))
{
    $c_1 = $array[$length-1];
    $c_2 = $array[$length-2];
}
else {
    //初始化最優值
    $opt = $array[0] + $array[$length - 1] - $num;
    if($opt < 0) $opt = -$opt;
    for($i=0;$i<$length;$i++)
    {
        //獲取相對的num跟接近的數。
        $tmp = $num - $array[$i];
        if($tmp <= 0) $tmp = -$tmp;
        $node = search($i,$tmp, $array);
        //當前查找的最優值的記錄
        $opt2 = $node + $array[$i] - $num;
        //取其絕對值,也可用abs()取絕對值$opt2 = abs($opt2);
        if( $opt2  < 0) $opt2 = -$opt2;
        //判定做比較,找出最小的絕對值,並將其賦值給$c_1和$c_2
        if($opt2 < $opt) {
            $opt = $opt2;
            $c_1 = $array[$i];
            $c_2 = $node;
        }
    }
}
print_r($array);
echo "find ".$num." in array,".$c_1." and ".$c_2." sub more close";
//給定一個值求出和它最接近的數
//採用折半查找,查找該元素數值
function search($key,$num, $array)
{
    //lft,$right左右折半下標指針
    $left = 0;
    unset($array[$key]);
    //$tmpKeys = array_keys($array);
    $array = array_merge($array,[]);
    $right = count($array) - 1;
    //中間指針
    $half = floor(($left + $right) / 2);
    //current爲當前指針
    $current = $left;
    //跳出循環的標誌符號,其只要在最後一輪,能判定已經是相鄰的兩個數,就能結束循環了。
    $next = 0;
    while($left <= $right)
    {
        $half = floor(($left + $right) / 2);
        $next = $right - $left;
        if($num == $array[$half])
        {
            $current = $half;
            break;
        }
        elseif ($num > $array[$half]) {
            $left = $half;
        }

以上是找一個數組中任意兩個數的和最接近,但這也只是記錄單對數字,其實要優化也可以將其他多對相關的數字記錄下來。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

爲了search()返回以前下標,並非數字結果,我們可以這樣做。

//求解數組中元素a和b,其和sum=a+b,sum最接近num的數兩個。
//求解思想是:對數組進行順序排序,然後對數組中的每個數遍歷每個數能求得一個最優值,然後對每對值大小sum與給出的這個數num做比較,找出絕對值相差最小的那個數。
//以下程序是對以上的一個簡單變化,其比較的是兩個值sum-num的絕對值大小,找到絕對值最小的值。
//這個過程就是流水式的,在一次流水式的比較和判定過程就能確定下來,將對應的值存儲在變量中,這裏是c_1和c_2。
//這裏還有帶說明的是,在固定一個值查找另外一個值時,我使用的是$tmp=$num - $array[$i]查出與該數最接近的數,並返回其下標,獲取對應的值最終就可以得到最小的最優值。
//只要該最優值最小,就可以確定該組數值。
$array = [5,12,34];
//$c_1,$c_2是存放找到的兩個數值。
$c_1 = 0;
$c_2 = 0;
//最優值,在這裏其
$opt = 0;
//輸入的數
$num = 33;
//開始:
//分兩步
//1.先排序
//2.判定
//3.查找
sort($array);
//依次遍歷數組中的數其每個值的最優值
$length = count($array);
//數組元素個數大於2個
if($length < 2) exit("error array length");
//判斷端數值
if($num <= ($array[0] + $array[0])){
    $c_1 = $array[0];
    $c_2 = $array[1];
}
else if($num >= ($array[$length - 1]+$array[$length-1]))
{
    $c_1 = $array[$length-1];
    $c_2 = $array[$length-2];
}
else {
    //初始化最優值
    $opt = $array[0] + $array[$length - 1] - $num;
    if($opt < 0) $opt = -$opt;
    for($i=0;$i<$length;$i++)
    {
        //獲取相對的num跟接近的數。
        $tmp = $num - $array[$i];
        if($tmp <= 0) $tmp = -$tmp;
        $node = search($i,$tmp, $array);
        echo $node."\n";
        //當前查找的最優值的記錄
        $opt2 = $array[$node] + $array[$i] - $num;
        //取其絕對值,也可用abs()取絕對值$opt2 = abs($opt2);
        if( $opt2  < 0) $opt2 = -$opt2;
        //判定做比較,找出最小的絕對值,並將其賦值給$c_1和$c_2
        if($opt2 <= $opt) {
            $opt = $opt2;
            $c_1 = $array[$i];
            $c_2 = $array[$node];
        }
    }
}
print_r($array);
echo "find ".$num." in array,".$c_1." and ".$c_2." sub more close";
//給定一個值求出和它最接近的數
//採用折半查找,查找該元素數值
function search($key,$num, $array)
{
    //lft,$right左右折半下標指針
    $left = 0;
    unset($array[$key]);
    $tmpArray = [];
    $j = 0;
    foreach($array as $k => $v){
        $tmpArray[$j]['key'] = $k;
        $tmpArray[$j]['val'] = $v;
        $j++;
    }
    $right = count($tmpArray) - 1;
    //中間指針
    $half = floor(($left + $right) / 2);
    //current爲當前指針
    $current = $left;
    //跳出循環的標誌符號,其只要在最後一輪,能判定已經是相鄰的兩個數,就能結束循環了。
    $next = 0;
    while($left <= $right)
    {
        $half = floor(($left + $right) / 2);
        $next = $right - $left;
        if($num == $tmpArray[$half]['val'])
        {
            $current = $half;
            break;
        }
        elseif ($num > $tmpArray[$half]['val']) {
            $left = $half;
        }
        elseif($num < $tmpArray[$half]['val']) {
            $right = $half;
        }
        
        if(($num - $tmpArray[$left]['val']) <= ($tmpArray[$right]['val'] - $num)){
            $current = $left;
        }
        else{
            $current = $right;
        }
        if($next <= 1) break;
    }
    return $tmpArray[$current]['key'];
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章