php 对应的值,如何快速取出所对应的值

一个php的索引数组,数组里面的值为从1到100之间的整数(不重复),并且数值可能是断续,也就是可能有就7,9但是没有8。并且顺序是打乱的,也就是,不是从1排到100这样的

现在假设$a=50, 怎样最快的取出==$a或者是跟$a最相邻的两个数值呢?

对了其中数组中的值不一定有等于$a的

回复内容:

一个php的索引数组,数组里面的值为从1到100之间的整数(不重复),并且数值可能是断续,也就是可能有就7,9但是没有8。并且顺序是打乱的,也就是,不是从1排到100这样的

现在假设$a=50, 怎样最快的取出==$a或者是跟$a最相邻的两个数值呢?

对了其中数组中的值不一定有等于$a的

array_search — 在数组中搜索给定的值,如果成功则返回相应的键名

获得键名,$arr[$key-1], $arr[$key+1]即可

楼上的已经非常简单了,不过需要是如果没有找到这个数,就找最接近的,而原数组顺序是打乱的,所以上下两个并不一定就是最接近的,当然,二分查找也是一种思路,我提供一下自己用算法的思路,我的想法是先用木桶排序(我目前所了解的在正整数中的排序的最快方式)

//这个是要求的数组

$arr = [1,2,3...];

//填充一个1-100范围的数组

$search_arr = array_fill(0 , 99 , 0);

//遍历数组

foreach($search_arr as $k=>$v){

if(in_array($k , $arr)){

++ $v;

}

}

//此时search_arr数组里面值是1的就是要找的,同时已经排序好了

foreach($search_arr as $k=>$v){

if($v >= 1){

$new_arr[] = $k;

}

}

//此时的new_arr就是一个键从0自增,同时值是排序的数组,然后再结合楼上的写法,便可求出。

不知道这样效率怎么样

$arr = range(1, 100); // 要求的数组

$target = 10; // 目标值

shuffle($arr); // 打乱顺序

$val_key = array_search($target, $arr);

// 测试 $target 不存在的情况去掉以下注释

// array_splice($arr, $val_key, 1);

// $val_key = '';

if ($val_key) {

echo "这个值是:{$arr[$val_key]}";

} else {

sort($arr);

foreach ($arr as $key => $value) {

if (($value < $target) && ($arr[$key+1] > $target)) {

echo "左边:{$value}

";

echo "右边:{$arr[$key+1]}";

exit;

}

}

}

不带修改的静态查询

将它排序(升序),复杂度nlogn(一次排序)

然后二分快速定位,复杂度logn(一次查询)

// 在有序数组$arr中得到大于等于$val的第一个下标

// 如果想要获得离$val最近的值,通过返回值判断

// 如果大于最大的值,返回数组的长度

function binary_search($arr, $val){

$n = count($arr) - 1;

$ans = $n + 1;

$l = 0; $r = $n;

while($l <= $r){

$mid = ($l + $r) >> 1;

if($arr[$mid] >= $val){

$ans = $mid;

$r = $mid -1;

}

else $l = $mid + 1;

}

return $ans;

}

$arr = [1,5,9,3,8,7,10,12];

sort($arr);

foreach($arr as $key => $val){

printf("%d ", $val);

}

printf("\n");

$search_num = 6;

printf("%d\n", binary_search($arr, $search_num));

仅带添加操作的动态查询,不改变顺序

1-100有100个数,且其值也为1-100,若询问69所在位置下标,可以以69为中心,二分查找到它附近的点的下标,若某个位置存在数,则标为1,否则标为0,那么以69为中心,往左边二分找最长的区间和为0,往右边二分找最长的区间和为0,快速求区间和可以用了树状数组,更新查询复杂度为logn,添加数的复杂度为logn。

要求和目的:

树状数组保存区间标志和(某个区间的值是否出现),更新和查询复杂度logn

以某值为中心查找离它最近的值,然后返回其下标,二分查,复杂度logn

以空间换时间,保存值->下标的映射。

可以在数组末尾添加数,不要求按顺序添加

以下代码解决以下问题

假设有一个数组[5,9,3,8,7,10,12]

询问离12最近的坐标,返回6

询问离2最近的坐标,返回2

添加一个不重复的数15

添加一个不重复的数18

添加一个不重复的数16

添加一个不重复的数13

询问离13最近的坐标,返回10

询问离17最近的坐标,返回9

// 树状数组初始化长度为106,赋空值为0

$arr_bit = array();

for($i = 0;$i <= 105;$i ++){

$arr_bit[$i] = 0;

}

// 查询1-$x之间的和

function query($x){

global $arr_bit;

$sum = 0;

while($x > 0){

$sum += $arr_bit[$x];

$x -= $x & -$x;

}

return $sum;

}

// 更新第$x位的标志

function add($x, $val){

global $arr_bit;

while($x <= 105){

$arr_bit[$x] += $val;

$x += $x & -$x;

}

}

$arr = [5,9,3,8,7,10,12];

$arr_tmp = array();

foreach($arr as $key => $val){

$arr_tmp[$val] = $key;

printf("%d ",$val);

add($val, 1);

}

printf("\n");

// 查找离某值最近的下标

// 先查找左边 然后再找右边,若不存在,返回-1

function find_val_pos($val){

if($val < 1 || $val > 100){

return -1;

}

global $arr_tmp;

$n = count($arr);

$l = 1; $r = $val; $ans_l = -1;

// 得到$val左边最靠近的

while($l <= $r){

$mid = ($l + $r) >> 1;

// 获得$val到$mid的标志区间和

$mid_val = query($val) - query($mid - 1);

// 若标志区间和大于1,记录答案,l往右移继续查

if($mid_val >= 1){

$ans_l = $mid;

$l = $mid + 1;

}

else $r = $mid - 1;

}

$l = $val; $r = 101; $ans_r = -1;

// 得到$val右边最靠近的

while($l <= $r){

$mid = ($l + $r) >> 1;

// 获得$mid到$val的标志区间和

$mid_val = query($mid) - query($val - 1);

if($mid_val >= 1){

$ans_r = $mid;

$r = $mid - 1;

}

else $l = $mid + 1;

}

if($ans_l == -1) return $arr_tmp[$ans_r];

elseif ($ans_r == -1) return $arr_tmp[$ans_l];

else {

if($val - $ans_l > $ans_r - $val)

return $arr_tmp[$ans_r];

else

return $arr_tmp[$ans_l];

}

}

function add_num($val){

if($val < 1 || $val > 100) return false;

global $arr_tmp;

if(isset($arr_tmp[$val])){

return false;

}

else {

global $arr;

$arr_n = count($arr);

$arr_tmp[$val] = $arr_n;

$arr[$arr_n] = $val;

add($val, 1);

return true;

}

}

// 查询12最近的坐标

printf("%d\n",find_val_pos(12)); // 结果为6

// 查询2最近的坐标

printf("%d\n",find_val_pos(2)); // 结果为2

add_num(15); // 15位于7

add_num(18); // 18位于8

add_num(16); // 16位于9

add_num(13); // 13位于10

// 查询13最近的坐标

printf("%d\n",find_val_pos(13)); // 结果为10

// 查询17最近的坐标

printf("%d\n",find_val_pos(17)); // 结果为9

// 查询15最近的坐标

printf("%d\n",find_val_pos(15)); // 结果为7

printf("hh\n");

// 查询100最近的坐标

printf("%d\n",find_val_pos(100)); // 结果为8,因为第8个位置是18,是最大的数

带添加删除操作(较大数)的动态查询

需要额外维护一个下标占用的区间值,然后套一个平衡二叉树,查询复杂度logn,添加删除复杂度logn。

相关标签:算法 php

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值