【问题标题】:Why am I getting Time Limit Exceeded error on O(n) time complexity code?为什么在 O(n) 时间复杂度代码上出现 Time Limit Exceeded 错误?
【发布时间】:2022-11-07 12:10:06
【问题描述】:

问题https://leetcode.com/problems/first-missing-positive/ 提出:

给定一个未排序的整数数组 nums,返回最小的缺失正整数。

您必须实现一个在 O(n) 时间内运行并使用恒定额外空间的算法。

示例 1:

Input: nums = [1,2,0]
Output: 3
Example 2:

Input: nums = [3,4,-1,1]
Output: 2
Example 3:

Input: nums = [7,8,9,11,12]
Output: 1
 

Constraints:

1 <= nums.length <= 5 * 10**5
-2**31 <= nums[i] <= 2**31 - 1

因此我的代码满足了这一点:

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        nums=sorted(list(filter(lambda x: x>=0, nums)))
        nums= list(dict.fromkeys(nums))
        if 1 not in nums: return 1
        x=nums[0]
        for num in nums:
            if nums.index(num) != 0:
                dif = num - x
                if dif!=1:
                    return x + 1
                x=num
        return num+1
                
        

很高兴有人提供帮助。

【问题讨论】:

  • 那不是 O(n)。你排序了!
  • 你一遍又一遍地打电话给index!
  • 而且您也没有像他们告诉您的那样使用恒定的额外空间!
  • @user2357112supportsMonica 谢谢,我认为排序是 o(n)
  • list.index 是 O(n)。您将其称为最坏情况 n 次。所以这个算法变成了O(n**2)

标签: python


【解决方案1】:

正如 cmets 所述,sorted() 不需要线性时间。 sorted() 还会创建一个新列表,因此您的解决方案也违反了 O(1) 内存约束。

这是一个线性时间,恒定空间的解决方案。这个问题需要两件事(为简单起见,让n = len(nums)):

  1. 一种数据结构,可以在O(1)时间,判断区间[1, n]中的一个正整数是否在nums中。 (我们要检查n 数字,并且我们的算法的运行时间必须是线性的。)对于这个问题,我们的策略是创建一个表,使得对于介于 1 和n 之间的每个整数i,如果@ 987654331@ 是 nums,然后是 nums[i - 1] = i。 (答案必须是肯定的,并且答案不能大于n + 1——答案是n + 1 的唯一方法是nums 包含区间[1, n] 中的每个整数)。
  2. 就地生成数据结构以满足内存限制的过程。

    这是一个解决方案。

    class Solution:
        def firstMissingPositive(self, nums: List[int]) -> int:
            # Match elements to their indicies.
            for index, num in enumerate(nums):
                num_to_place = num
                while num_to_place > 0 and num_to_place <= len(nums) and num_to_place != nums[num_to_place - 1]:
                    next_num_to_place = nums[num_to_place - 1]
                    nums[num_to_place - 1] = num_to_place
                    num_to_place = next_num_to_place
            
            # Find smallest number that doesn't exist in the array.
            for i in range(len(nums)):
                if nums[i] != i + 1:
                    return i + 1
            
            return len(nums) + 1
    

    两个for 循环都需要线性时间。第二个的原因很明显,但第一个的时间分析有点微妙:

    请注意,while 循环包含以下条件:num_to_place != nums[num_to_place - 1]。对于此while 循环的每次迭代,满足此条件的值的数量减少1。因此,此while 循环在所有迭代中最多只能执行n 次,这意味着第一个for 循环需要O(n) 时间。

【讨论】:

  • 优秀的答案。这可能只是一个口味问题,但我个人会发现没有临时变量更容易解析数字交换。它可能需要缩短变量以舒适地放在一行上,例如num, nums[num - 1] = nums[num - 1], num
  • 好建议!通常我会同意你的看法,但nums[num - 1] 的位置取决于num,我们在同一行中分配给它。实际上,您给出的建议替换不起作用,因为 num 首先被分配,导致 LHS 上的 nums[num - 1] 引用不同的内存位置。您可以通过交换 LHS 和 RHS 来进行元组分配,但它很脆弱,所以在这种情况下我宁愿完全避免它。
  • 哦,哇,你是对的。我想我从来没有交换过涉及这样计算索引的变量。谢谢开导!
【解决方案2】:
# O(n) time and O(1) space
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
    index = 0
    while index < len(nums):
        if nums[index] > 0 and nums[index] - 1 < len(nums) and nums[index] != nums[nums[index] - 1]:
            nums[nums[index]-1], nums[index] = nums[index], nums[nums[index] - 1]
        else:
            index += 1
    
    for i, integer in enumerate(nums):
        if integer != i + 1:
            return i + 1
    return len(nums) + 1

【讨论】:

    【解决方案3】:
    # O(n) time and O(n) space
    class Solution(object):
        def firstMissingPositive(self, nums):
            nums_set = set(nums)
            result = 1
            while True:
                if result not in nums_set:
                    return result
                result += 1
    
    # O(n) time and O(1) space
    class Solution(object):
        def firstMissingPositive(self, nums):
        nums_length = len(nums)
        tmp = 0
        for i, num in enumerate(nums):
            while num <= nums_length and num > 0:
                tmp = nums[num-1]
                nums[num-1] = float('-inf')
                num = tmp
                    
        for i in range(nums_length):
            if nums[i] != float('-inf'):
                return i + 1
            
        return len(nums) + 1
    

    【讨论】:

    • 谢谢,但这个问题需要 o(1) 空间复杂度。从列表创建哈希表是 o(n) 空间
    • 明白了,让我回顾一下。我会改变的。
    • @boswellpercy 我添加了另一个解决方案,它将解决您的问题
    猜你喜欢
    • 2020-05-21
    • 2018-03-19
    • 1970-01-01
    • 2023-04-07
    • 2015-01-06
    • 1970-01-01
    • 2018-12-12
    • 2016-10-27
    • 1970-01-01
    相关资源
    最近更新 更多