阵练练习

时间:2012-07-06 17:35:14

标签: arrays algorithm language-agnostic

我试图解决这个问题: 给定一个排序数组,其中包含从0开始的连续整数(一个整数可能重复多次),例如 - 0,0,0,1,2,3,3,3,4,4(也可能很长 - 这是只是一个例子),有效地找到给定整数的起始和结束索引。

我正在考虑使用

1)遍历(复杂度= O(n)

2)修改后的二进制搜索(复杂度= O(log n))。 [n =总阵列长度]

然后想知道是否可以利用连续整数属性来解决它。 有什么不同的想法或建议吗?

4 个答案:

答案 0 :(得分:1)

你可以查看开始和结束元素,看看数组中有多少元素 k ,然后对每个边界进行修改后的二元搜索,检查元素及其左右。我认为你不能比O( k log( n ))更快。

如果按从左到右(或从右到左)的顺序搜索边界,则应该减少平均时间,因为您可以在数组的较小子集内搜索,但我不认为这会影响最糟糕的情况。

即检查索引 i 及其相邻元素,搜索0-1边界:

|0|0|0|1|1|1|1|1|2|2|2
         \ i /

然后左转:

|0|0|0|1|1|1|1|1|2|2|2
   \ i /

自从你找到它之后,现在在它右边的集合中查找1和2之间的边界:

1|1|1|1|1|2|2|2
    \ i /

1|1|1|1|1|2|2|2
        \ i /

你已经完成了,因为你知道你正在寻找多少边界。

编辑:对不起,我没有意识到你只想要其中一个界限。过程类似 - 您找到要搜索的元素(即O(log( n )))然后使用相同的修改搜索向左和向右搜索以检查边界。根据数组的整体大小与数组中项目的数量,实际上可能更快只检查一侧或另一侧。

答案 1 :(得分:1)

首先,让我们忽略“连续性”属性

只要问题是找到处理单个个别请求的最有效方法,直接的一般解决方案就是执行两个连续的二进制搜索:第一个找到的开始序列,第二个查找序列的结尾。第二次搜索在数组的其余部分中执行,即在先前找到的序列开头的右侧。

但是,如果你以某种方式知道序列的平均长度相对较小,那么用线性搜索替换第二个二进制搜索就有意义了。 (这与合并两个相似长度的排序序列时的原理相同:线性搜索优于二分搜索,因为输入结构保证平均搜索目标位于序列的开头附近)。 / p>

更正式地说,如果整个数组的长度为n且数组中不同整数值的数量(变量指标)为k,则线性搜索开始平均优于二进制搜索当n/k小于log2(n)时(可能需要一些与实现相关的常数因子来建立实际关系)。

说明此效果的极端示例是n=k时的情况,即数组中的所有值都不同时的情况。显然,使用线性搜索找到每个序列的结尾(一旦你知道了开头)将比使用二进制搜索更有效。

但这需要额外了解输入数组的属性:我们需要知道k

这就是你的“连续性”属性发挥作用的时候了!

由于数字是连续的,数组中的最后一个值减去数组中的第一个值等于k-1,这意味着

k = array[n-1] - array[0] + 1

此规则也可以应用于原始数组的任何子数组,以计算该子数组的多样性指标。

这已经为您提供了一种非常可行且有效的查找序列的算法:首先对序列的开头执行二进制搜索,然后执行二进制线性搜索取决于nk之间的关系(或者更好的是,在右子阵列的长度与右子阵列的变化度量之间)。

P.S。同样的技术也可以应用于第一次搜索。如果您正在寻找i的序列,那么您立即知道它是数组中的j - 序列,其中j = i - array[0]。这意味着对该序列开头的线性搜索平均需要j * n/k步。如果此值小于log2(n),则线性搜索可能比二分搜索更好。

答案 2 :(得分:0)

您的数组已排序,因此您可以使用二分法搜索。假设n是数组A的大小,将A1中的A和A2除以大小(n / 2)或分别为(n / 2)和(n / 2)如果n是奇数,则+ 1。您正在寻找j的起始索引。 (j在A中)

 1. if A1(n/2) < j, then you know that j is in A2. 
 2. if A2(1) > j, then you know that j is in A1. 
 3. If A2(1) = j, then j may be in A1 and A2. Just check A1(n/2).
     if A1(n/2) < j then 2. Do the same recursively on A2 to find the last index
     else apply dichotomic search to find the starting index and ending index in both arrays

答案 3 :(得分:0)

它必须是算法吗?你的问题只是说找到了位置,但是如果它确实是某种形式的算法方法让我知道,因为我已经提供了一个以相当标准的方式处理这个问题的PHP函数。

$numbers = array(0,0,0,1,2,3,3,4,4,4,4);
function get_boundaries($array,$number)
{
    $keys = array_keys($array,$number);
    $found = count($keys);
    if($found == 0)
    {
        $ret = false;
    }
    else if($found == 1)
    {
        $ret = array($keys[0],$keys[0]);
    }
    else if($found > 1)
    {
        $ret = array($keys[0],$keys[$found-1]);
    }
    return $ret;
}

$result = get_boundaries($numbers,1);
print_r($result);


//Result when looking for 0
Array
(
    [0] => 0
    [1] => 2
)

//Result when looking for 1
Array
(
    [0] => 3
    [1] => 3
)

//Result when looking for 9
(boolean) false