python准备蓝桥杯之数组(如何找出数组中唯一的重复元素)

数组的重要地位

数组的概念 数组是某种类型数据按照一定的顺序组成的数据的集合。如果将有限个类型相同的变量的集合命名,那么这个称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个变量称为下标。
数组的地位 数组是最基本的数据结构,关于数组的面试笔试题在企业招聘中也是屡见不鲜,求解此类题目,不仅要扎实的编程基础,更需要清晰的思路与方法。下面列出比较有代表性的一些题目。

如何找出数组中唯一的重复元素

【问题描述】
数字1~1000放在含有1001个元素的数组中,其中只有唯一的元素值重复。其他数字均只出现一次。设计一个算法,将重复元素找出来,要求每个数组元素只能被访问一次。如果不使用辅助存储空间,能否使用一个算法实现。
【解决方法1】累加求和法
计算机与数学本身是一家,抛开计算机的专业知识不提,上述问题其实可以回归成一个数学问题。数学问题目标是在一个数字序列寻找重复的那个数。根据题目意思可以看出,1~1000个数中除了唯一一个数重复以外,其他个数仅出现一次,由数学性质可知,这1001个数包括1到1000中每一个数各一次,外加1到1000中某一个数,很显然,1001个数中有1000个数是固定的,唯一一个不固定的数也知道其范围,那么累加求和就可以找出那个数。
以数组序列(1,3,4,2,5,3) 为例,该数组长度为6,除了数字三以外,其他四个数字没有重复。按照上述方法,首先计算数组中所有数字的和sumb,sumb=1+3+4+2+5+3=18,数组中只包含1~5的数,计算1到5一共5个数的和suma=1+2+3+4+5=15,所以重复数字为sumb-suma=3

i=1
result=0
lst=[1,3,4,2,5,3]
while i<6:
    result+=i
    i+=1
print(result)
j=0
result1=0
while j<len(lst):
    result1+=lst[j]
    j+=1
print(result1-result)

算法性能分析:时间复杂度为O(n),空间复杂度为O(1).
【解决方法2】环形相遇法
“判断单链表是否存在环”是一个非常经典的问题,可以转化为“已知一个单链表中存在环,找出环的入口点”这种想法。具体思路如下:将array[i]看作是第i个元素的索引,即array[i]->array[array[i]]->array[array[array[i]]]->…最终形成一个单链表,由于数组a中存在重复元素,则一定存在一个环,且环的入口即为重复元素。

def findDup(array):
	if None==array:
		return -1
	fast=0
	slow=0
	while True:
		fast=array[array[fast]]#fast走两步
		slow=array[slow]#slow走一步
		if fast==slow:#找到相遇点
			break
	fast=0
	#找入口点
	while True:
		fast=array[fast]
		slow=array[slow]
		if fast==slow:#找到入口点
			return slow
if __name__=="__main__":
	lst=[1,3,4,2,5,3]
	print(findDup(lst))

算法性能分析:时间复杂度为O(n),没有申请辅助的存储空间,当数组中的元素不合理时,上述算法可能会有数组越界的可能性。可以在执行fast=array[array[fast]];slow=array[slow];操作的时候分别检查array[slow]与array[fast]是否会越界,如果越界,则说明提供的数据不合法。
【解决方法3】异或法
根据异或运算的性质可知,当相同元素异或时,其运算结果为0,当不同元素异或时,其运算结果为非0,任何数与数字与0异或时,其运算结果为该数。以数组(1,3,4,2,5,3)为例。(1 ^ 3 ^ 4 ^ 2 ^ 5 ^ 3 ) ^ (1^ 2^ 3^ 4^ 5)=0^ 0^ 3^ 0^0.
代码如下:

def findDup(array):
	if None==array:
		return -1
	i=0
	result=0
	#任何数与0异或都是任何数
	while i<len(array):
		result^=array[i]
		i+=1
	j=0
	while j<len(array):
		result^=j
		j+=1
	return result
if __name__=="__main__":
	lst=[2,3,4,5,1,3]
	print(findDup(lst))

算法性能分析:时间复杂度为O(n),没有申请辅助存储空间
【解决方法3】数据映射法
数组取值可以看成是一个特殊的函数f:D—>R,定义域为下标值1~1000,值域为1 ~ 1000,如果对于任何一个数i,f(i)叫做它的后继,i叫f(i)的前驱。0只有后继,没有前驱,其他数字有前驱也有后继,重复的那个数有两个前驱。以数组array=(1,3,4,3,5,2)为例,从下标0开始遍历数组。
(1)array[0]=1,遍历下标为1的元素,同时标记已经遍历过的元素(变为相反数),array=
(-1,3,4,3,5,2)
(2)array[1]=3,遍历下标为3的元素,同时标记已经遍历过的元素,array=(-1,-3,4,3,5,2)
(3)array[3]=3,遍历下标为3的元素,同时标记已经遍历过的元素,array=(-1,-3,4,-3,5,2)
(4)array[3]=-3,3已经遍历过,找到了重复元素。

def findDup(array):
        if None==array:
                return -1
        lens=len(array)
        index=0
        i=0
        while True:
                if array[i]>=lens:
                        return -1
                if array[index]<0:
                        break
                #访问过,变相反数的方法进行标记
                array[index]*=-1
                #index后继为array[index]
                index=-1*array[index]
                if index>=lens:
                        print("非法数字")
                        return -1
        return index

if __name__=="__main__":
	lst=[1,3,4,2,5,3]
	print(findDup(lst))

算法性能分析:时间复杂度为O(n),也没有申请辅助的存储空间。
这种方法的缺点:修改了数组中元素的值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值