leetcode 41. 缺失的第一个正数

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3

示例 2:

输入:nums = [3,4,-1,1]
输出:2

示例 3:

输入:nums = [7,8,9,11,12]
输出:1

提示:

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

先不考虑题目要求的时间、空间复杂度,先简单暴力的做出来结果;

暴力的做法有两个:

1、时间最快,空间不限:

  1. 准备一个2^31大的数组作为桶bucket[]
  2. 遍历输入数据,出现数字k就bucket[k]=1标志出现;
  3. 从1开始向上找bucket中第一个出现0的数,这个数就是最小的正整数

2、时间、空间都不限:

  1. 对输入数据排序,
  2. 遍历一遍排序后的数组,就可以找到最小的正整数

回到题目的要求,时间复杂度要求是O(N),可以肯定是会用到方法1; 现在要求O(1)的空间复杂度,那么就必须利用上给出的数组。 遍历数组,如果数字k小于n且非负,那么a[k-1]=k-1; 然后遍历一遍,a[i] != i的就行是解。

** 复杂度解析:** O(N)的时间和O(1)的空间复杂度; ** 其他解法:** 基数排序。

从低位开始, 当前第i位,统计0出现x次,1出现y次,(x+y == n) 再次扫描数组,可以直接确定每个数字该排在哪里。 if bit = 0 then idx = total_y + (total_x-left_x)

思路1:

class Solution {

    static let ArrayCount = 10000
    var bucket = Array(repeating: 0, count: Solution.ArrayCount)

    func firstMissingPositive(_ nums: [Int]) -> Int {

        // 建一个10000个数组,遍历往里面放值
        // 遍历这个10000数组,找到有空值就输出
        // 找不到,把原数组每个值减10000,在放到新数组中,
        // 遍历这个10000数组,找到有空值就输出
        var result = 0
        var count = 0

        var nums = nums

        while true {
            self.fillBucket(nums)
            let (isSuccess, tempResult) = self.checkBucket()
            if isSuccess {
                result = tempResult
                break
            } else {
                nums = self.updateNumber(nums)
                self.cleabBucket()
                count += 1

                if nums.count == 0 {
                    result = 1
                    break
                }
            }
        }
        result = count * (Solution.ArrayCount-1) + result
        return result
    }


    // 拿数据填充桶
    func fillBucket(_ nums: [Int]) {
        for num in nums {
            if num > 0 && num < Solution.ArrayCount {
                self.bucket[num] = 1
            }
        }
    }

    // 检查桶内有没有空值
    func checkBucket() -> (Bool, Int) {
        var isSuccess = false
        var result = 0
        for (i,value) in bucket.enumerated() {

            if (i == 0) {
                continue
            }
            if (value == 0) {
                isSuccess = true
                result = i
                break
            }
        }
        return (isSuccess, result)
    }

    // 清空桶内的上一轮数据的标志位
    func cleabBucket() {
        bucket = Array(repeating: 0, count: Solution.ArrayCount)
    }

    // 原数组的数据更新
    func updateNumber(_ nums: [Int]) -> [Int] {
        var newArray = [Int]()
        for num in nums {
            if (num < Solution.ArrayCount) {
                // 负数, 已经往数组里放过的数,不在追加到新数组中
            } else {
                let newNum = num - Solution.ArrayCount + 1
                newArray.append(newNum)
            }
        }
        return newArray
    }
}

你可能感兴趣的:(leetcode,算法,数据结构)