leetcode逐日一题:数组漂亮值求和

打印 上一主题 下一主题

主题 1871|帖子 1871|积分 5613



弁言

        今天的逐日一题原题是2278. 字母在字符串中的百分比,直接模拟,逐个匹配,统计letter在原始字符串s中出现的次数,然后再计算所占百分比即可。更换成前几天遇到的更有意思的一题来写这个逐日一题。
题目

2012. 数组漂亮值求和
给你一个下标从 0 开始的整数数组 nums 。对于每个下标 i(1 <= i <= nums.length - 2),nums漂亮值 即是:


  • 2,对于所有 0 <= j < i 且 i < k <= nums.length - 1 ,满足 nums[j] < nums < nums[k]
  • 1,如果满足 nums[i - 1] < nums < nums[i + 1] ,且不满足前面的条件
  • 0,如果上述条件全部不满足
返回符合 1 <= i <= nums.length - 2 的所有 nums漂亮值的总和

示例 1:
  1. 输入:nums = [1,2,3]
  2. 输出:2
  3. 解释:对于每个符合范围 1 <= i <= 1 的下标 i :
  4. - nums[1] 的美丽值等于 2
复制代码
示例 2:
  1. 输入:nums = [2,4,6,4]
  2. 输出:1
  3. 解释:对于每个符合范围 1 <= i <= 2 的下标 i :
  4. - nums[1] 的美丽值等于 1
  5. - nums[2] 的美丽值等于 0
复制代码
示例 3:
  1. 输入:nums = [3,2,1]
  2. 输出:0
  3. 解释:对于每个符合范围 1 <= i <= 1 的下标 i :
  4. - nums[1] 的美丽值等于 0
复制代码

提示:


  • 3 <= nums.length <= 105
  • 1 <= nums <= 105

思路

        起首还是读懂题目,对于符合1 <= i <= nums.length - 2的下标i,漂亮值大概有3种情况:


  • 漂亮值 = 2,对于在i位置前面的数,都严格小于nums;且在i位置后面的数,都严格大于nums
  • 漂亮值 = 1,无法满足第1种情况下,且可以满足nums前面的1个数严格小于它,后面的1个数严格大于它
  • 漂亮值 = 0,排除上述2种情况的其他情况
        那么对于每个在范围内的i,我们要逐个判断漂亮值:对于情况1,如果每个都去比力,判断单个i必要的时间复杂度是O(n),整体的时间复杂度就是O(n^2);对于情况2,只要判断前后,判断单个i的时间复杂度是O(1);对于情况3,在上述2种情况都判断后,不再必要单独判断。
        由此可见,我们重要优化点在于如何快速判断情况1。构造2个辅助数组,prefixMax[]和suffixMin[],prefixMax表示下标[0, i]范围内的最大值,suffixMin表示下标[i, n-1]范围内的最小值。有了这2个辅助数组后,对于位置i我们在判断是否满足情况1的时间,只要判断条件 prefixMax[i-1] < nums && nums < suffixMin[i+1] 即可,这样每次判断的时间复杂度会缩减到O(1),判断范围内的i的时间复杂度是O(n)。而构建这2个辅助数组,必要分别从前往后和从后往前遍历原始数组,时间复杂度也是O(n)。这样,我们就避免了O(n^2)的时间复杂度。
        进一步来看,如果我们从前往后处置惩罚i的话,prefixMax[]数组不必要被创建,只要滚动维护一个prefixMax的变量,表示[0, i]范围内的最大值即可,这样,可以省下一个大小为n的数组的空间开销。同理,如果从后往前处置惩罚i的话,可以省下suffixMin[]的空间。不外,这2者不可兼得。
图解


代码


  1. class Solution {
  2.    public int sumOfBeauties(int[] nums) {
  3.        int[] min = getMin(nums);
  4.        int sum = 0;
  5.        int max = nums[0];
  6.        for (int i = 1; i < nums.length - 1; i++) {
  7.            if (nums[i] > max && nums[i] < min[i + 1]) {
  8.                sum += 2;
  9.            } else if (nums[i] > nums[i - 1] && nums[i] < nums[i + 1]) {
  10.                sum += 1;
  11.            }
  12.            // 求出遍历到下一个i时,nums[0,i-1]的最大值
  13.            max = Integer.max(max, nums[i]);
  14.        }
  15.        return sum;
  16.    }
  17.    /**
  18.     * 从后往前,求出当前下标到数组结尾的最小值
  19.     */
  20.    private int[] getMin(int[] nums) {
  21.        int n = nums.length;
  22.        int[] min = new int[n];
  23.        min[n - 1] = nums[n - 1];
  24.        for (int i = n - 2; i >= 0; i-- ) {
  25.            min[i] = Integer.min(min[i+1], nums[i]);
  26.        }
  27.        return min;
  28.    }
  29. }
复制代码
耗时



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表