在数组中搜索连续数字相差+ 1 / -1的键

时间:2013-05-12 03:25:18

标签: algorithm data-structures

给出一维数组。该数组的每个数字与前一个数字相差+1或-1。示例:数组{5,6,7,6,5,6,7,8,9,8}

您将获得一个数字来搜索此数组中的第一个匹配项(例如:搜索8 - 您的代码应返回7)。不要使用线性搜索。

如果没有线性搜索,我可以尝试如下:

Check if (array[0] == Key)
{
        YES:
           return 0;
}

Take a variable: Diff = array[0]

// Keep on traversing the array, if Next Number>Current Number
   Diff += 1
   Else
   Diff -= 1

if (Diff==key)
{
    return current_index+1;
}

但这种方法过于通用。即使键之间的差异不是+ -1而是其他东西,这种方法也可以解决这个问题。

有什么特别关于+ -1差异,这可以给我一个更好的解决方案?

感谢。

3 个答案:

答案 0 :(得分:8)

假设您正在搜索16,并且数组[0] = 8.这意味着您搜索的数字不会出现在数组[8]之前,即(目标 - 数组[0])。所以你读了数组[8],它有13个;这意味着目标不能出现在数组[11]之前。等等。 +/- 1差异允许您在搜索中向前跳过,因为您知道如果array [x] =(target +/- N)目标数字不能出现在array [x + N]之前。

答案 1 :(得分:5)

您无需查看列表中的每个数字。假设您正在寻找8,第一个数字是5。您可以安全地执行步骤3,因为8不能在少于三个步骤中发生。您可能会考虑稍微多一点 - 比如6 - 因为可能有一些-1,但我不知道这是否会更有效,因为您不确定它是否是“第一次”发生。所以我们坚持使用原文:

当你到达新的号码时,你确定下一步要采取的步骤 - 如果你已经采取了3步,你会找到6,再步2(8-6),你又找到6,再走2,你找到8 - 你在那里!你知道这是第一次出现,因为你跳过的数字不能是8.而且它只需要三步而不是七步。

答案 2 :(得分:5)

所选答案不是最佳选择。如果您正在尝试最小化探测次数(数组查找),那么您可以做得比从头开始搜索更好,并采取小到`target - array[i]的步骤

由于您被允许使用索引查找进行随机访问,因此您可以进行更大的步幅。例如,如果您在以a[0] = 0开头的数组中查找 9 ,则可以检查a[16]以查看它是否小于或等于 0 < / em>的。如果没有,那么a[0 .. 16]都不能达到 9

更大的步幅为每个探针提供更多信息(每个探针都允许您排除左侧和右侧的指示)。与从左侧搜索时的最小步幅相比,这使得每个探测器获得的信息量增加了两倍。

为了展示从左边搜索到中间搜索的优势,这里有一些用Python编程语言编写的工作代码:

def find(arr, value, bias=2):
    # With the bias at 2, new probes are in the middle of the range.
    # Increase the bias to force the search leftwards.
    # A very large bias does the same as searching from left side of the range.
    todo = [(0, len(arr)-1)]  # list of ranges where the value is possible
    while todo:
        low, high = todo.pop()
        if low == high:
            if arr[low] == value: return low
            else: continue
        mid = low + (high - low) // bias
        diff = abs(arr[mid] - value)
        if mid+diff <= high: todo.append([mid + diff, high])
        if mid-diff >= low: todo.append([low, mid - diff])
    raise ValueError('Value is not in the array')

从概念上讲,算法正在尝试获取每个探测可能获得的最大信息量。有时,它会变得幸运并且同时排除大范围;有时,这将是不吉利的,只能排除一个微小的子范围。无论运气如何,它的禁区都将是左侧搜索区域的两倍。

简单的测试代码:

arr = [10, 11, 12, 13, 14, 13, 12, 11, 10, 9, 8, 7, 6, 7, 8]
for i in range(min(arr), max(arr)+1):
    assert arr.index(i) == find(arr, i)