缺失的第一个正数——原地哈希

67 阅读1分钟

image.png

代码1:

  1. 因为要找的是最小正数,所以只需要考虑值在(1——n)之间的的数就可以了,如果有值大于n,或存在一个数为负数,那么说明一定有一个小于n的数不在数组中
  2. 所以我们只需要将数组中值在(1——n)之间的数当成下标,改变此下标的值,最后遍历一遍,看那个下标没有改变,那么那个下标所对应的值自然就是缺失的那个正数
  3. 但因为我们是在原数组中做的变化,我们必须保证在我们做完标记后,这个数字我们还可以还原出来,因为这个值我们可能还有用,所以我们可以将值变为负数来做为一种标记
  4. 如果以负数为标记,那么我们自然要将原数组中的负数变为一个大于 n 的正数,从而不让它影响我们
  5. 所以第一个for,将负数变为正数
  6. 第二个for,将(1——n)之间的值进行标记
  7. 第三个for,查找那个下标未被标记,因为标记对应的是(0——n-1)所以,return的时候应该下标加一
  8. 如果遍历完,都存在,那么返回 n+1
func firstMissingPositive(nums []int) int {
    n := len(nums)
    for i, v := range nums {
        if v <= 0 {
            nums[i] = n + 1
        }
    }
    for _, v := range nums {
        v = abs(v)
        if v <= n {
            nums[v-1] = -abs(nums[v-1])
        }
    }
    for i, v := range nums {
        if v > 0 {
            return i + 1
        }
    }
    return n + 1
}

func abs(n int) int {
    if n < 0 {
        return -n 
    }
    return n
}

代码2:

置换:将(1——n)放到属于自己的位置 nums[nums[i]-1] != nums[i],防止一直和自己交换,死循环

func firstMissingPositive(nums []int) int {
    n := len(nums)
    for i := 0; i < n; i++ {
        for nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i] {
            nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]
        }
    }
    for i := 0; i < n; i++ {
        if nums[i] != i + 1 {
            return i + 1
        }
    }
    return n + 1
}