zoukankan      html  css  js  c++  java
  • 缺失的第一个正数

    • 问题描述

    1. leetcode41 寻找数组中缺失的第一个正数。
    2. 第一个指的是按照数字顺序,在数组中没有出现的正整数
    • 要求

    1. 时间复杂度O(n)
    2. 空间复杂度O(1)
    • 解决思路
    1. 基本解法:这个超出了时间复杂度的要求
      1. 先找出数组中最小的正整数,如果最小正值为 1, 则找比 1 大的在数组中没出现过的那个数,返回。
      2. 否则,直接返回 1。
    2. 高级解法:第一次遍历,更改数组元素的存储结构,使之成为这样的结构:

            [1, 一些大于1的正数区,负数区,一些比本身下标大的正数值区]。

            第二次遍历找出符合条件的最小正值。

    原作为什么会想到这样的解法来做这个题呢?为什么要把数组变成这样的形式?

    1. 这道题的关键就是对数组中存在 1 这种情况进行处理。如果有1,则需要找到比 1 大的最小正值。
    2. 利用好数组索引与数组元素值的关系,对于那些元素值大于索引值的部分不需要进行更改。只需要把那些大于0,且值与索引不等的情况才需要交换更改。
    • 代码呈现
    1. 普通解法。
       1    public static int firstMissingPositive(int[] nums) {
       2         if (nums.length==0) { return 1; }
       3         int res = Integer.MAX_VALUE;
       4         // 找到该数组中最小的正数
       5         for(int i=0; i<nums.length; i++) {
       6             if (nums[i]>0) {
       7                 res = res < nums[i] ? res : nums[i];
       8             }
       9         }
      10 
      11         if (res == 1) {
      12             // 当数组中出现最小正数 1 的时候,是最难处理的时候。需要去找比1大的在数组中没出现过的那个数
      13             // 时间复杂度O(n2),因为在while循环里还有for循环。所以这种方式是不完全正确的。
      14             boolean findFlag = true;
      15             while (findFlag) {
      16                 findFlag = false;
      17                 for(int j=0; j<nums.length; j++) {
      18                     if (nums[j] == res+1) {
      19                         res += 1;
      20                         // System.out.println("循环内:"+res);
      21                         findFlag = true;
      22                         break;
      23                     }
      24                 }
      25             }
      26             // System.out.println(res+1);
      27             return res+1;
      28         }
      29         // 全负或者最小正数大于1时,取1
      30         return 1;
      31     }
    2. 更改数组的形式
       1     public static int firstMissingPositive3(int[] A) {
       2         int n = A.length;
       3         if (n == 0) return 1;
       4         for (int i = 0; i < n; ) {
       5             if (A[i] > 0 && A[i] <= n && A[i]-1 != i){
       6                 int a = A[i];
       7                 A[i] = A[a - 1];
       8                 A[a - 1] = a;
       9             }
      10             else ++i;
      11         }
      12 
      13         for(int j:A) {
      14             // System.out.println(j);
      15         }
      16 
      17         for (int i = 0; i < n; ++i){
      18             if (A[i] != i + 1)
      19                 return i + 1;
      20         }
      21         return n+1;
      22     }

      原作这样写,让我有种错觉:那就是这道题的代码不是为了题目存在的,而是这道题是为了这段代码存在的。其中更改数组结构的代码

      1    for (int i = 0; i < n; ) {
      2             if (A[i] > 0 && A[i] <= n && A[i]-1 != i){
      3                 int a = A[i];
      4                 A[i] = A[a - 1];
      5                 A[a - 1] = a;
      6             }
      7             else ++i;
      8         }

      和下面的代码一致:

      1  for (int i = 0; i < n; i++) {
      2             while (nums[i] >= 1 && nums[i] <= n && nums[i] - 1 != i) {
      3                 //swap(nums, nums[i] - 1, i);
      4                 int temp = nums[i];
      5                 nums[i] = nums[temp-1];
      6                 nums[temp-1] = temp;
      7             }
      8         }

      仍然是在 for 里面包含了 while 循环,看起来像是 n^2 复杂度,但由于其三个条件的约束,导致内层循环达到O(1)复杂。这点算是可以学习的地方

  • 相关阅读:
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    20172332 实验一《Java开发环境的熟悉》实验报告
    20172332 《程序设计与数据结构》第二周学习总结
    20172332 《程序设计与数据结构》第一周学习总结
    寒假作业03
    寒假作业02
    寒假作业01
    Java核心技术点之集合框架
  • 原文地址:https://www.cnblogs.com/dogeLife/p/11052364.html
Copyright © 2011-2022 走看看