剑指Offer刷题笔记——数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

 

可以把当前序列当成是一个下标和下标对应值是相同的数组(时间复杂度为O(n),空间复杂度为O(1)); 遍历数组,判断当前位的值和下标是否相等:
若相等,则遍历下一位;
若不等,则将当前位置i上的元素和a[i]位置上的元素比较:若它们相等,则找到了第一个相同的元素;若不等,则将它们两交换。换完之后a[i]位置上的值和它的下标是对应的,但i位置上的元素和下标并不一定对应;重复操作,直到当前位置i的值也为i,将i向后移一位,再重复。

假如某个位置在数组里就没有它对应的数,在找它对应数字的时候就会找到相等的两个数字。如果是重复数字的位置,如果没找到对应数字之前就找到两个相同的就返回,如果先找到对应的数字就把它先放进去,剩下一个相同的数字还在其他位置上,等到别的位置操作的时候,就会找出这个数字。

数字是0~n-1,数组长度为n(位置索引是0~n-1),如果所有数字没有重复的,这个数组可以变成某个位置存储的数字就是它的位置索引。如果某个位置索引对应两个数字了,那这个数字肯定是重复的了。

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        n = len(numbers)
        if n == 0:
            return False
        for i in range(n):
            if numbers[i] < 0 or numbers[i] > n-1:
                return False
        # 遍历满足条件的列表
        for i in range(n):
            # 让所有数字按他们的数字所指的位置“入座”
            while numbers[i] != i:
                # numbers[i] != i时候, numbers[i] = numbers[numbers[i]]说明找到了两个重复的数字
                if numbers[i] == numbers[numbers[i]]:
                    # 这是为了满足题的要求
                    duplication[0] = numbers[i]
                    return True
                # 没满足数值和位置相等,目前也没找到重复的结点,就继续找下去
                numbers[numbers[i]], numbers[i] = numbers[i], numbers[numbers[i]]
        return False

 

还有一种思路就是根据数值的规律来判断: 题目里写了数组里数字的范围保证在0 ~ n-1 之间,所以可以利用现有数组设置标志,当一个数字被访问过后,可以设置对应位上的数 + n,之后再遇到相同的数时,会发现对应位上的数已经大于等于n了,那么直接返回这个数即可。

其实就是通过给对应位置的数字+n,来记录那些数字被遍历过了。

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        n = len(numbers)
        if n == 0:
            return False

        for i in range(n):
            # 取出来数值是当作标签的
            index = numbers[i]
            # index>=n说明这个位置索引作为数字已经出现一次了
            # 但是现在index要当作索引使用,要-n
            if index >= n:
                index -= n
            # 指向的位置数字>=n,说明这个位置已经被指向过一次了
            # 这个位置(不是位置上的数字)是重复的
            if numbers[index] >= n:
                duplication[0] = index
                return True
            # +n代表这个index被指向一次了
            numbers[index] += n
        return False

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值