23-05-24 刷题

练习刷题思路

Missing Number - LeetCode 【easy】

分析:

  • 长度为n的int数组,包含无重复的元素,每个元素范围是[0, n]. 找[0, n] 范围内没有出现在数组中的那个元素。
  • 思路1: 用求和公式,计算出0+1+…+n的和,然后遍历数组,减去出现的,最后剩下就是没有出现的。时间 O(n) 空间 O(1)
  • 思路2:用异或的性质,两个相同的数异或结果是0,所以先把0…n这些数异或,得到x,然后再跟数组中每个数异或,最后剩下的就是缺失的数。时间 O(n) 空间 O(1)
  • 思路3:利用数组(hashMap)记录已经出现的数,遍历一遍看哪个没有出现。时间 O(n) 空间 O(n),不好。

题目变形:

  • 要求一样,增加一条,数组递增排序。怎么做?

    • 思路:利用二分。如果中间 A[mid] == mid 说明左边没有缺少元素,到右边去查找。否则去左边查找。直到最后剩下一个元素。

    • 代码

      static int findMissing(int[] A) {
          int left = 0, right = A.length - 1;
          while (left <= right) {
              int mid = (left + right) >>> 1;
              if (A[mid] == mid) {
                  left = mid + 1;
              } else {
                  right = mid - 1;
              }
          }
          return left; // why left? just use a sample to find it out
      }
      

First Missing Positive - LeetCode 【Hard】

分析:

  • 题目描述,跟上面的类似,但是更难一点。每个数的范围是int最大范围内,然后找第一个缺失的正数。要求O(n)时间,O(1)空间。

  • 思路1:分两步来做,第一步尝试把每个元素归位(修改输入数组,将A[i] 放到 A[i] - 1位置,前提是它在[1,n]范围内,且目标位置也是错位的,如果没有判断目标位置错位,那当数组有重复元素时,可能会出现死循环,这也是一个难点)。第2步,就是从前往后遍历找第一个不满足条件的下标。注意返回的数是i + 1. 如果都满足,则说明缺失的是n + 1

    class Solution {
        public int firstMissingPositive(int[] A) {
            // 1. move A[i] to correct pos
            int n = A.length;
            for(int i = 0; i < n; i++) {
                while (A[i] > 0 && A[i] <= n && A[i] != i + 1 && A[A[i] - 1] != A[i]) {
                    int t = A[i];
                    A[i] = A[t - 1];
                    A[t - 1] = t;
                }
            }
            // 2. find first incorrect one
            for (int i = 0; i < n; i++) {
                if (A[i] != i + 1) {
                    return i + 1;
                }
            }
            return n + 1;
        }
    }
    
  • 思路2:先过滤掉所有不符合要求的数,把他们标记成0,(并且可以把他们移动到最后面,可省略)。 然后对每个正数,把他们对应下标元素标记成负数,如果那个位置是0,那么标记成-n(也可以是-n-1),然后找第一个>= 0的位置即可。【这个思路时间复杂度也是O(n),空间O(1),也很简单,但是彻底改变了原始的数组了】

  • class Solution {
        public int firstMissingPositive(int[] A) {
            // 1. first filter out out-of-range [1, n] number, mark as 0
            int n = A.length;
            for (int i = 0; i < n; i++) {
                if (A[i] < 1 || A[i] > n) A[i] = 0;
            }
            // 2. mark non-zero's pos (A[i] - 1) as negative value
            for (int val : A) {
                if (val == 0) continue;
                int x = Math.abs(val);
                if (A[x - 1] == 0) A[x - 1] = -n;
                else if (A[x - 1] > 0) A[x - 1] = -A[x - 1];
                // otherwise A[val-1] already neg, it means it has been set by 
                // other pos(i.e. it has duplicated num)
            }
            // 3. find first >= 0 pos
            for (int i = 0; i < n; i++) {
                if (A[i] >= 0) return i + 1;
            }
            return n + 1;
        }
    }
    
posted @ 2023-05-24 11:34  编程爱好者-java  阅读(7)  评论(0编辑  收藏  举报