import java.util.*; /** * NC30 缺失的第一个正整数 * @author d3y1 */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param nums int整型一维数组 * @return int整型 */ public int minNumberDisappeared (int[] nums) { // return solution1(nums); return solution2(nums); // return solution3(nums); } /** * 哈希: TreeSet * * 数组元素可重复 * * @param nums * @return */ private int solution1(int[] nums){ TreeSet<Integer> treeSet = new TreeSet<>(); for(int num: nums){ if(num > 0){ treeSet.add(num); } } int min = 1; for(int num: treeSet){ if(num > min){ return min; } min++; } return min; } /** * 原地哈希: 标记法 * * 数组元素可重复 * * 相似 -> NC305 寻找唯一重复数 [nowcoder] * * 对于一个长度为N的数组, 其中没有出现的最小正整数只能在[1,N+1]中. * 这是因为如果[1,N]都出现了, 那么答案是N+1, 否则答案是[1,N]中没有出现的最小正整数. * 这样一来, 我们将所有在[1,N]范围内的数放入哈希表, 可以得到最终的答案, 而给定的数组恰好长度为N. * * @param nums * @return */ private int solution2(int[] nums){ int n = nums.length; for(int i=0; i<n; i++){ // 无效数置为n+1 不影响最终结果 if(nums[i] <= 0){ nums[i] = n+1; } } int idx; for(int num: nums){ num = Math.abs(num); // 1<=num<=n -> num为有效数 if(num <= n){ // 0<=idx<=n-1 idx = num-1; // 标记为负值 表示num=idx+1的数已存在 -> 有效数num标记转化为索引位置num-1 nums[idx] = -Math.abs(nums[idx]); } } // 依次判断 for(int i=0; i<n; i++){ // 表示num=i+1的数不存在 if(nums[i] > 0){ return i+1; } } return n+1; } /** * 原地哈希: 置换法 * * 数组元素可重复 * * @param nums * @return */ private int solution3(int[] nums){ int n= nums.length; int num; for(int i=0; i<n; i++){ num = nums[i]; // 1<=num<=n -> num为有效数; 0<=num-1<=n-1, 有效数num置换到索引位置num-1 while((1<=num&&num<=n) && num!=nums[num-1]){ swap(nums, i, num-1); num = nums[i]; } } // 依次判断 for(int i=0; i<n; i++){ // 表示num=i+1的数不存在 if(nums[i] != i+1){ return i+1; } } return n+1; } /** * 交换 * @param nums * @param i * @param j */ private void swap(int[] nums, int i, int j){ int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } }