Algorithm 在连续数字相差+;1/-1
给定一个一维数组。此数组的每个数与前一个数的差值为+1或-1。示例:数组{5,6,7,6,5,6,7,8,9,8} 您将获得一个数字来搜索它在此数组中的第一个匹配项(例如:搜索8——您的代码应返回7)。不要使用线性搜索 如果没有线性搜索,我可以按如下方式进行尝试:Algorithm 在连续数字相差+;1/-1,algorithm,data-structures,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 traver
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差异,有什么特别的地方可以给我一个更好的解决方案
谢谢。假设您正在搜索16,数组[0]=8。这意味着您正在搜索的数字不能出现在数组[8]之前,即(target-array[0])。所以你读数组[8],它有13个;这意味着目标不能出现在数组[11]之前。等等+/-1差异使您可以在搜索中提前跳过,因为您知道如果数组[x]=(目标+/-N),则目标编号不能出现在数组[x+N]之前。您不需要查看列表中的每个编号。假设您正在查找
8
,第一个数字是5
。您可以安全地执行步骤3,因为8不能在少于三个步骤中发生。你可能会考虑稍微多说一点——比如说6——因为可能有大约1个,但我不知道这是否会更有效率,因为你不确定那是“第一次”的发生。所以,让我们坚持原来的观点:
当你到达新的数字时,你决定下一步要走多大的步-在上面,如果你走了3步,你会找到6步,再走2步(8-6),你会再次找到6步,再走2步,你会找到8步-你就到了!您知道这是第一次出现,因为您跳过的数字不可能是8。而且它只需要三步而不是七步。选择的答案不是最佳答案。如果你想尽量减少探测的数量(数组查找),你可以做得比从一开始就搜索和采取像
`target-array[i]
因为您可以使用索引查找进行随机访问,所以您可以取得更大的进步。例如,如果在以a[0]=0
开头的数组中查找9,则可以检查a[16]
以查看它是否小于或等于0。如果不是,则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')
您所描述的“过于通用”的方法仍然是阵列的线性扫描。Zim Zam的anwer就是你要找的。听起来像是家庭作业,所以我给你一个提示。如果数组[a]小于您的密钥,而数组[b]大于您的密钥,您发现了什么?现在要完成这个解决方案,可以使用递归或循环(因为这两种方法是等价的)。请注意,此答案与Zim Zam的不同。@Mitch Wheat:很抱歉,我错过了,更正了格式。@minopret:不,不是作业。@Sandepsing不要选得太快,你可以做得比选择的答案好得多。在我完成我的答案后看到你的答案-iPhone不适合在答案出现时更新答案…此解决方案不是最优的,可以在必要时采取更大的步幅和回溯来改进(仅在不利的情况下)。搜索16,如果
arr[0]=8
,则可以测试arr[13]
。如果是8或更少,那么你可以再次向前跳13;否则,您需要回溯到arr[8]
和arr[13差异]
@RaymondHettinger之间的某个位置-您给出的代码应用于您选择的示例,性能更差。请参阅我对您的解决方案的评论。可以通过一个常数因子来改进搜索,例如N/(2t),而不是N/t,其中t是目标数,但我认为渐进性不可能比线性时间更好-您总是被限制在向前跳过(或回溯)t因子,所以类似于二进制搜索的东西是不可能的;在最坏的情况下,所有的值(除了您检查的最后一个)都是(t-1)或(t-2),或者是(t+1)或(t+2),在这两种情况下,您都必须检查至少N/2的数组元素。例如:0,1,2,1,0,1,0,1,1,0,1,0,1,1,0,0,1,0-如果搜索2,代码会更糟。因此,“最坏的情况并不比其他算法更糟”是错误的。一般的想法是,从范围的中间位置搜索提供的信息是从范围开始搜索的两倍。在100个元素的数组中,探测arr[50]
会在两个方向上给出一个排除带,而探测arr[0]
只会在一个方向上排除标记。使用您给出的示例,我得到了您的“平分”算法与@Zim-ZamO'Pootertoot“至少一步”算法的以下结果:顺序=[找到这个值,你的算法需要N次评估,Zim的需要M次评估]:[6 4 3*],[7 4],[8 4 4],[9 5],[10 3 1*],[11 4 2*],[12 5 2*],[13 5 2*],[14 4 2*])。ZimZam的方法总是比你的好或更好(*),所以我仍然不相信。可能有更好的方法,但不是你用代码给出的方法。
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)