求解数组中任意两个元素的和最接近某一个数

13 篇文章 0 订阅

题意是这样的:求解一个数组中元素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'];
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值