LeetCode 记录-775. 全局倒置与局部倒置

75 阅读2分钟

LeetCode 记录-775. 全局倒置与局部倒置

我的解法

思路

image.png

我们可以看出一个局部倒置一定是一个全局倒置,所以我们只需要判断是否存在一个不是局部倒置的全局倒置,就是判断对于每一个 i(0=<i<nums.length20=<i<nums.length-2),是否存在一个 j(i+2=<j<nums.lengthi+2=<j<nums.length)使得满足nums[i]>nums[j]nums[i]>nums[j]。当找到一个满足条件的下标对时,直接返回 false,当遍历结束,返回 true。

这个思路的时间复杂度比较高,本来觉得可以使用单调栈的思路解决问题,但想了一下好像不行。

代码

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var isIdealPermutation = function (nums) {
  for (let i = 0; i < nums.length - 2; i++) {
    let j = i + 2;
    while (j < nums.length) {
      if (nums[i] > nums[j]) {
        return false;
      }
      j++;
    }
  }

  return true;
};

复杂度分析(自我分析,不一定对)

时间复杂度

O(n2)O(n^2),n 为 nums 数组的长度。在最差情况下,全局倒置和局部倒置个数一样,需要全部遍历一边。

空间复杂度

O(1)O(1)


官方解法 1: 维护后缀最小值

思路

这题的思路前半部分和我的解法类似,但官方在寻找不是局部倒置的全局倒置时,是从后往前寻找的(从 i=nums.length3i=nums.length-3 开始),寻找的同时维护了一个后缀数组中的最小值 minSuffix(后缀数组的下标范围为[i+2,nums.length1][i+2, nums.length-1]),因为只需要比较 nums[i]和 minSuffix 就可以判断是否存在这样的全局倒置了。最巧妙的地方是,因为从后往前寻找,所以每次只需要比较 minSuffix 和新添加进后缀数组的值,这样的话,总体的时间复杂度就降低到了O(n)O(n)

代码

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var isIdealPermutation = function (nums) {
  const len = nums.length;
  let minSuffix = nums[len - 1];
  for (let i = len - 3; i >= 0; i--) {
    if (nums[i] > minSuffix) {
      return false;
    }

    minSuffix = Math.min(minSuffix, nums[i + 1]);
  }
  return true;
};

复杂度分析

时间复杂度

O(n)O(n),其中 n 是 nums 的长度。

空间复杂度

O(1)O(1),只使用到常数个变量空间。

官方解法 2: 归纳证明

思路

通过归纳证明的方式来判断,放个截图,就不详细看啦。

image.png