1. 程式人生 > >41. 第一個缺失的正數

41. 第一個缺失的正數

題目:

給一個未排序的陣列,找出第一個缺失的正整數。

例如,
[1,2,0] 返回 3
[3,4,-1,1] 返回 2

你的演算法應該在 O(n) 的時間複雜度內完成並且使用常數量的空間。

分析:

  1. 尋找缺失正整數,因此所有1以下數字均無效
  2. 定義字典用於標記對應數值存在
  3. 遍歷列表,將出現的有效數字加入字典,如果1在列表中,改變相應flag
  4. 從1開始遞增,在字典中查詢是否存在,不存在即為缺失正整數

程式碼:

class Solution(object):
    def firstMissingPositive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if not n :
            return 1
        minposNum = 2
        numDict = {}
        for x in nums:
            if x > 0:
                numDict[x] = 1
                if x == 1:
                    minposNum = 1
        if minposNum > 1:
            return 1
        else:
            i = 1
            while n:
                if not numDict.get(i):
                    return i
                n -= 1
                i += 1
        return i

思考:

  1. 以上程式碼時間複雜度O(n),空間複雜度O(n),未能實現要求的O(1)空間複雜度
  2. 從討論區內學習到了滿足時間空間複雜度要求的方法
  3. 思路為,去除小於1及大於n的無效資料,以hash鍵值方式,將x[i]%n值加n,這樣做的方式不會導致當前元素後部元素改寫導致的hash鍵值改變,重寫後,1~n中缺失的整數對應位置將為小於n的整數,再次遍歷,尋找第一次出現的小於n的位置;
  4. 程式碼如下:(leetcode asones
     def firstMissingPositive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
         Basic idea:
        1. for any array whose length is l, the first missing positive must be in range [1,...,l+1], 
            so we only have to care about those elements in this range and remove the rest.
        2. we can use the array index as the hash to restore the frequency of each number within 
             the range [1,...,l+1] 
        """
        nums.append(0)
        n = len(nums)
        for i in range(len(nums)): #delete those useless elements
            if nums[i]<0 or nums[i]>=n:
                nums[i]=0
        for i in range(len(nums)): #use the index as the hash to record the frequency of each number
            nums[nums[i]%n]+=n
        for i in range(1,len(nums)):
            if nums[i]/n==0:
                return i
        return n