一万个有序数查找两个重复数,快速二分查找法 O(logN)

简介:

原题见 莫贝特 的博客,意思是在1-1000的有序数列中,再随机插入一个数,这个数大小还是在1-1000之间,而且插入位置要保证插入后数列仍然有序。

这样我们就有1001个数,按照从小到大的顺序排列,其中只有两个数是重复的。当然,因为有序,装两个数也必定是挨着的。

题目的要求就是用最少的内存开销、最少的时间开销找出这个重复的数字

 
莫贝特 的博客中,他的算法是将(1001个数字的和)- (1000个数字的和)=  重复数字,这种算法思路简单,但是时间复杂度是最高的,共进行了2000次循环,至于留言中的其他算法也基本上属于线性查找,线性查找的时间复杂度是O(N),对于这道题目,运气最好的时候第一次就能找到,运气最差的时候,要找1000次,平均要找500次。

然而,如果我们考虑到这是一个有序数列,而且只有两个重复数,二分折半查找法就一跃而出了,对数据结构和算法有了解的人都知道,二分查找法是有序数列最好的查找算法。
具体思路是:
1)left=0
2)right=10001
3)如果 left 和 right 中间那个位置 pos 的数值等于位置编号 pos,则:
      4)left=pos,否则:
      5)right=pos
6)如果(right-left>1),则重复步骤 3)-6),直到 right-left=1, pos 就是要查找的数


这几天正在看 Python ,就用 Python 实现了一个,1000个数只需查找10次,一万个数13次,十万个数17次,一百万个数20次,时间复杂度 O(logN),速度很快。下面上代码:

复制代码
# !/usr/bin/python
#
 -*- coding: GBK -*-

import  random

#  生成数列,一万个数
arr_length = 100001
list
= range( 1 ,arr_length)

# 插入一个随机数
rnd = random.randrange( 1 ,arr_length)
list.insert(rnd
- 1 ,rnd)

print   ' \n重复数为: ' +  str(rnd)
print ' \n开始查找 '

 
#  正式开始查找算法   
left = 0
right
= arr_length

count
= 0

while  ((right - left) > 1 ):
    pos
= (left + right) / 2
    
    count
= count + 1
    
print   ' 第 %d 次定位:%d '   %  (count,pos)
    
    
if  (list[pos] == pos):
        right
= pos
    
else :
        left
= pos
    

print   ' \n查找结果: ' ,list[left]
复制代码


输出结果如下图:

//==========================================



本文转自左洸博客园博客,原文链接:http://www.cnblogs.com/myqiao/archive/2009/07/21/1528156.html,如需转载请自行联系原作者


目录
相关文章
|
4月前
【Leetcode 2645】构造有效字符串的最小插入数 —— 动态规划
状态定义:`d[i]`为将前 i 个字符拼凑成若干个 abc 所需要的最小插入数。状态转移方程: 如果` word[i]>word[i−1]`,那么`word[i]`可以和`word[i−1]`在同一组 abc 中,`d[i]=d[i−1]−1` ;否则`word[i]`单独存在于一组 abc 中,`d[i]=d[i−1]+2`
|
4月前
|
算法 测试技术 C#
C++二分查找算法:包含每个查询的最小区间
C++二分查找算法:包含每个查询的最小区间
|
4月前
|
设计模式 算法 Java
【数据结构和算法】删掉一个元素以后全为 1 的最长子数组
这是力扣的 1493 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。又又又是一道滑动窗口的典型例题,可以帮助我们巩固滑动窗口算法。这道题很活灵活现,需要加深对题意的变相理解。给你一个二进制数组nums,你需要从中删掉一个元素。 请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。 如果不存在这样的子数组,请返回 0 。
66 1
|
5月前
|
算法 测试技术 C#
C++二分查找算法:查找和最小的 K 对数字
C++二分查找算法:查找和最小的 K 对数字
|
5月前
|
算法
【LeetCode】每日一题&&两数之和&&寻找正序数组的中位数&&找出字符串中第一个匹配项的下标&&在排序数组中查找元素的第一个和最后一个位置
【LeetCode】每日一题&&两数之和&&寻找正序数组的中位数&&找出字符串中第一个匹配项的下标&&在排序数组中查找元素的第一个和最后一个位置
|
8月前
|
算法
arr = [1,2,5,8,9,10,20,30,40] 有一个从小到大排序好的数组,现在输入一个数,要求按照原来的规律插入到数组中
arr = [1,2,5,8,9,10,20,30,40] 有一个从小到大排序好的数组,现在输入一个数,要求按照原来的规律插入到数组中
|
5天前
|
机器学习/深度学习 算法 测试技术
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
|
4月前
|
算法 测试技术 C#
C++二分查找或并集查找:交换得到字典序最小的数组
C++二分查找或并集查找:交换得到字典序最小的数组
|
6月前
|
C语言
【C语言刷题】调整奇数偶数顺序、有序序列合并以及有序序列判断
【C语言刷题】调整奇数偶数顺序、有序序列合并以及有序序列判断
38 0
|
存储 索引
【题型总结】使用双指针+哈希表寻找符合某种条件的字符串/数字的个数
记录第一出现的字符的位置和最后一个出现的字符的位置,如果相减长度为s1的长度,那么证明是连续出现的子串
69 0