leetcode之小白python起步笔记——重复字符

题目 剑指 Offer 03. 数组中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

考察的是程序员的沟通能力,先问面试官要时间/空间需求!
只是时间优先就用字典,
还有空间要求,就用指针+原地排序数组,
如果面试官要求空间O(1)并且不能修改原数组,还得写成二分法!!

方法一:排序比较法,时间O(nlogn),空间O(1)。修改原数据。先排序,然后看相邻元素是否有相同的,有直接return。
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        nums.sort()
        pre = nums[0]
        n = len(nums)
        for index in range(1, n):
            if pre == nums[index]:
                return pre
            pre = nums[index]
方法二:集合法:时间O(n),空间O(n),不修改原数据

构建一个新的空集合,然后依次添加元素,当发现某个元素已存在时,则说明该元素重复了。具有普适性,也可用字典替换集合,本质相同。

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        repeatDict = {}
        for num in nums:
            if num not in repeatDict:
                repeatDict[num] = 1
            else:
                return num
方法三:原地哈希法,时间O(n),空间O(1),修改原数据。

因为所有的元素都小于len(nums),所以可以让位置i放置元素值i,如果位置i的元素值不是i,则可以交换nums[i]与nums[nums[i]],这样nums[i]的值就被正确归位了,继续交换直到位置[i]也被正确交换了。如果我们发现nums[i]与nums[nums[i]]的值一致,则发现了重复的元素,返回即可。针对性较强,普适性较弱。时间复杂度的算法:因为每交换一次数组位置,至少有一个元素被放到了该元素值对应的下标的位置,至多2个,所有有n个元素,最坏的考虑就是需要操作n次。所以是O(n)

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        repeatDict = {}
        for num in nums:
            if num not in repeatDict:
                repeatDict[num] = 1
            else:
                return num
方法四:二分查找,时间O(nlongn),空间O(1),不修改原数据。

对0到n-1进行二分查找,时间O(nlogn),空间O(1),不修改原数据,用时间换空间
//该方法需要数字一定有重复的才行,因此如果题目修改在长度为n,数字在1到n-1的情况下,此时数组中至少有一个数字是重复的,该方法可以通过。

class Solution:
    def findRepeatNumber(self, nums:List[int]) -> int:
        # 注意初始值是1
        min_value = 1
        max_value = len(nums) - 1
        while (max_value > min_value):
            mid_value = (max_value + min_value) // 2
            counts = self.countNums(nums, min_value, mid_value);
            if counts > mid_value - min_value + 1:
                max_value = mid_value
            else:
                # 注意这个地方需要加1,不然最后会陷入死循环,比如最后max_value为2,min_value为1,则会一直循环,对应的上面也可以给max_value复制的地方减1
                min_value = mid_value + 1
        # 跳出循环的条件一定是max_value = min_value
        return min_value

    def countNums(self, nums, min_value, max_value):
        count = 0
        for ele in nums:
            if min_value <= ele <= max_value:
                count += 1
        return count
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值