剑指offer:数组中重复的数字
admin
2023-07-10 03:03:21
0

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

# -*- coding: utf-8 -*-
# @Time         : 2019-04-15 17:31
# @Author       : Jayce Wong
# @ProjectName  : job
# @FileName     : duplicate_num_in_array.py
# @Blog         : https://blog.51cto.com/jayce1111
# @Github       : https://github.com/SysuJayce

class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # 完整的做法是先进行输入合法性检查,然后将每个数字放到它应该在的下标,在每次交换之前先检查该下标是否已保存了正确的数字,
        # 如果是则该数字是一个重复数字
        # 时间复杂度O(n),空间复杂度O(1)。由于每个数字最多交换两次就可以放到正确的位置(第一次被从不正确的位置换到另一个不正确的位置,
        # 然后第二次就会专门为它找到属于它的位置,因此最多是两次),也就是最多比较2n次,即时间复杂度是O(n)
        if not numbers:
            return False
        if max(numbers) >= len(numbers) or min(numbers) < 0:
            return False

        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[numbers[i]] == numbers[i]:
                    duplication[0] = numbers[i]
                    return True
                else:
                    # 注意这样交换会出现问题,需要先保存一个中间结果,不能直接交换,
                    # 否则当处理numbers[numbers[i]]的时候会找不到正确的下标
                    # numbers[i], numbers[numbers[i]] = numbers[numbers[i]], numbers[i]
                    temp = numbers[i]
                    numbers[i] = numbers[numbers[i]]
                    numbers[temp] = temp

        return False

    def duplicate2(self, numbers, duplication):
        # duplicate1()需要对输入数组进行修改,假如要求不修改输入数组,那么可以借鉴二分查找的
        # 思想,逐步缩小重复数字所在的区间。

        # 但是这种方法不能确保找到所有重复的数字,
        # 如果counter(left, right) == right - left + 1,不能排除[left, right]有重复
        # 数字的情况,例如[2, 3, 5, 4, 3, 2, 6, 7]中,counter(1, 2) == 2,但是2其实是
        # 重复数字

        # 由于是借鉴了二分查找的思想,因此while需要循环logn次,counter需要n次运算
        # 故时间复杂度O(nlogn), 空间复杂度O(1)
        def counter(start, end):  # 统计numbers中处于[start, end]之间的数字个数
            count = 0
            for num in numbers:
                if start <= num <= end:
                    count += 1
            return count

        if not numbers:  # 输入合法性判断
            return False
        left, right = 0, len(numbers) - 1  # 初始区间为[0, n-1]
        while left <= right:
            mid = (left + right) >> 1
            cnt = counter(left, mid)
            # 需要注意这里的循环出口,如果不在循环内判断left==right的情况的话就需要在循环外面
            # 再判断一次counter(left, left) == 1
            if left == right:
                if cnt > 1:
                    duplication[0] = left
                    return True
                break
            if cnt > mid - left + 1:
                # 由于是判断了 [left, mid]是否存在重复,并不能排除mid就是重复的数字,
                # 因此right不能更新为mid - 1
                right = mid
            else:
                left = mid + 1

        return False

    def duplicate3(self, numbers, duplication):
        # 由于数组中的数字范围已定,可以通过申请一个容量为数字范围的数组然后建立哈希表进行去重
        # 时间复杂度O(n), 空间复杂度O(n)
        arr = [-1] * len(numbers)
        for num in numbers:
            if arr[num] == -1:
                arr[num] = num
            else:
                duplication[0] = num
                return True
        return False

相关内容

热门资讯

美伊谈判濒临破裂之际,伊朗议长... 因为以色列持续对黎巴嫩进行军事打击,伊朗宣布暂停同美国的谈判。不过美国总统特朗普称,对话仍在继续。谈...
罕见!以军政策发生“重大转变” 新华社北京6月1日电 题:罕见纵深推进,以军对黎行动会否搅动美伊谈判新华社记者刘品然 阚静文 席玥以...
山西太原发现一处新石器遗址,出... 山西省太原市文物保护研究院协同相关科研机构,近期在太原市阳曲县西盘威村发现一处新石器时代重要遗址——...
伊媒发布穆杰塔巴罕见照片 伊朗塔斯尼姆通讯社6月1日发布了一张最高领袖穆杰塔巴的照片。照片中,穆杰塔巴面露笑容,抱着一个婴儿。...
福建“泡药杨梅”曝光后,浙江杨... 这两天,浙江本地杨梅少量进入市场。虽然受到此前福建 “泡药杨梅” 事件影响,市场整体销量相比去年同期...
尺素金声 | 前4月规上工业企... 5月27日,国家统计局发布最新数据显示,今年前4月,全国规上工业企业实现利润同比增长18.2%,增速...
郑丽文:台湾民众越来越了解“台... 针对台湾《联合报》民调显示,63%受访者民意希望维持现状,即将访美的中国国民党主席郑丽文1日表示,民...
美前副总统:共和党失去了方向,... 2026年是美国的中期选举年,共和党选情不利,可能在年底的选举中遭遇挫败。美国前副总统彭斯5月31日...
南枝原来去过中国?《给阿嬷的情... 《给阿嬷的情书》票房口碑双丰收,目前票房已突破13亿。凤凰卫视最新一期《问答神州》专访了该片导演蓝鸿...
法国海军扣押一艘俄“影子舰队”... 近日,法国海军在大西洋海域扣押了一艘据称从俄罗斯摩尔曼斯克出发的油轮,引发俄方强烈不满。俄新社6月1...