In situ hash

Time:2021-2-25

Example: missing first positive number

Source: leetcode

Link:https://leetcode-cn.com/probl…

In situ hash

Example:

Missing first positive number

Difficulty: hard

describe

To give you an unsorted integer array, please find the smallest positive integer that does not appear in it.

Examples

Example 1:

Input: [1,2,0]
Output: 3

Example 2:

Input: [3, 4, - 1, 1]
Output: 2

Example 3:

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

requirement

The time complexity of your algorithm should be o(n)And only constant level extra space can be used.

Analysis and explanation

If you don’t look at the requirements, the topic is very simple, just use a HashMap (HashSet is also an instance of HashMap). As follows:

class Solution {
    public int firstMissingPositive(int[] nums) {
        Set<Integer> set = new HashSet<>();

        //Only data in the range [1, n] is valid
        for (int num: nums){
            if (num>0 && num<=nums.length){
                set.add(num);
            }
        }
        
        //Find the first positive number that doesn't appear
        for (int i=1; i<=nums.length; ++i){
            if (!set.contains(i)){
                return i;
            }
        }
        
        return nums.length+1;
    }
}

However, although the time complexity is only O (n), the space complexity increases linearly with the increase of array due to HashMap, which is also o (n). Does not meet the constant level of the topic of additional space requirements.

At this time, let’s review the topic again to see if we can find a breakthrough

OneUnsortedArray, required inTime complexity of O (n)as well asThe space complexity of O (1)Find the missing onesFirst positive integer

Look at this topic again, the important condition is nothing more than the above four bold words.

The first positive integer we need to find is our answer. Isn’t the positive integer an array starting from 1. If it is alreadyIt’s sortedWe can find the missing positive integers in the range of [1, N + 1] (there are only n numbers in the array). But the title clearly shows that the array is not sorted, and any known sorting algorithm can not achieve o (n) time complexity.Sorting and searching is not feasible!

But do we need to sort?

unwanted!Because we just need to find the first element that doesn’t appear. Therefore, we can consider from this perspective: the constant level of space complexity requires that we cannot create a new array. If you want to change the order of the numbers, you have toOriginal array. How to find the first positive integer that doesn’t appear?

Let’s continue to think about the relationship between the given array and the required result of the title: array subscript range [0, n-1], title result [1, N + 1].

Now the question is very simple. Do we just need to put the elements in the array that meet the requirements of the topic in the corresponding subscript. Finally, traverse the array to see which subscript has no corresponding element. Isn’t that the answer?

The specific code is as follows

class Solution {

    public int firstMissingPositive(int[] nums) {
        int len = nums.length;

        for (int i=0; i<len; ++i){
            //Note here that after the exchange of the two elements, nums [i] still does not return to where it should be
            //For example, [1,2,0], after the first exchange, [2,1,0], the element 2 should not be in this position, so it needs to loop until the element with subscript 0 returns
            while (nums[i] > 0 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
                swap(nums,nums[i] - 1, i);
            }
        }

        for (int i=0; i<len; ++i){
            if (nums[i]!=i+1){
                return i+1;
            }
        }
        return len+1;
    }

    public static void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

The official gave a more ingenious solution: by converting all negative numbers to len + 1, the elements that meet the conditions are converted to negative absolute values. Finally, the first positive number is found. There is no need to exchange elements

For details, please refer to:https://leetcode-cn.com/probl…

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; ++i) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
        for (int i = 0; i < n; ++i) {
            int num = Math.abs(nums[i]);
            if (num <= n) {
                nums[num - 1] = -Math.abs(nums[num - 1]);
            }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
}

Summary and reflection

I don’t think it’s hard because the idea is very simple. It’s just a clever connection between key value pairs, but I’ve learned a lot.

I’ve read the source code of HashMap these days, and I think I’ve learned a lot about HashMap. But I was beaten by the daily question. After I worked it out in a muddle, I went to see the solution of the question. Oh, I wrote a custom hash function. I’ve been reminding myself not to paint a dungeon, but I still get into the habitual thinking: I think hash is the source code, f (x) = n & (length-1). Still need to do more questions, understand the thought, not just learn it.