leetcode每日一题:数组美丽值求和

引言

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

题目

2012. 数组美丽值求和

给你一个下标从 0 开始的整数数组 nums 。对于每个下标 i1 <= i <= nums.length - 2),nums[i]美丽值 等于:

  • 2,对于所有 0 <= j < ii < k <= nums.length - 1 ,满足 nums[j] < nums[i] < nums[k]
  • 1,如果满足 nums[i - 1] < nums[i] < nums[i + 1] ,且不满足前面的条件
  • 0,如果上述条件全部不满足

返回符合 1 <= i <= nums.length - 2 的所有 nums[i]美丽值的总和

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 3 <= nums.length <= 105
  • 1 <= nums[i] <= 105

思路

​ 首先还是读懂题目,对于符合1 <= i <= nums.length - 2的下标i,美丽值可能有3种情况:

  • 美丽值 = 2,对于在i位置前面的数,都严格小于nums[i];且在i位置后面的数,都严格大于nums[i]
  • 美丽值 = 1,无法满足第1种情况下,且可以满足nums[i]前面的1个数严格小于它,后面的1个数严格大于它
  • 美丽值 = 0,排除上述2种情况的其他情况

​ 那么对于每个在范围内的i,我们要逐个判断美丽值:对于情况1,如果每个都去比较,判断单个i需要的时间复杂度是O(n),整体的时间复杂度就是O(n^2);对于情况2,只要判断前后,判断单个i的时间复杂度是O(1);对于情况3,在上述2种情况都判断后,不再需要单独判断。

​ 由此可见,我们主要优化点在于如何快速判断情况1。构造2个辅助数组,prefixMax[]suffixMin[]prefixMax[i]表示下标[0, i]范围内的最大值,suffixMin[i]表示下标[i, n-1]范围内的最小值。有了这2个辅助数组后,对于位置i我们在判断是否满足情况1的时间,只要判断条件 prefixMax[i-1] < nums[i] && nums[i] < suffixMin[i+1] 即可,这样每次判断的时间复杂度会缩减到O(1),判断范围内的i的时间复杂度是O(n)。而构建这2个辅助数组,需要分别从前往后和从后往前遍历原始数组,时间复杂度也是O(n)。这样,我们就避免了O(n^2)的时间复杂度。

​ 进一步来看,如果我们从前往后处理i的话,prefixMax[]数组不需要被创建,只要滚动维护一个prefixMax的变量,表示[0, i]范围内的最大值即可,这样,可以省下一个大小为n的数组的空间开销。同理,如果从后往前处理i的话,可以省下suffixMin[]的空间。不过,这2者不可兼得。

图解

代码

java 复制代码
class Solution {
    public int sumOfBeauties(int[] nums) {
        int[] min = getMin(nums);
        int sum = 0;
        int max = nums[0];
        for (int i = 1; i < nums.length - 1; i++) {
            if (nums[i] > max && nums[i] < min[i + 1]) {
                sum += 2;
            } else if (nums[i] > nums[i - 1] && nums[i] < nums[i + 1]) {
                sum += 1;
            }
            // 求出遍历到下一个i时,nums[0,i-1]的最大值
            max = Integer.max(max, nums[i]);
        }
        return sum;
    }

    /**
     * 从后往前,求出当前下标到数组结尾的最小值
     */
    private int[] getMin(int[] nums) {
        int n = nums.length;
        int[] min = new int[n];
        min[n - 1] = nums[n - 1];
        for (int i = n - 2; i >= 0; i-- ) {
            min[i] = Integer.min(min[i+1], nums[i]);
        }
        return min;
    }
}

耗时

相关推荐
方也_arkling7 小时前
【Java-Day08】static / final / 枚举
java·开发语言
橙淮7 小时前
Spring Bean作用域与生命周期全解析
java·spring
Chengbei117 小时前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
llz_1127 小时前
web-第一次课后作业
java·开发语言·idea
kkeeper~7 小时前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
秋97 小时前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本7 小时前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
DIY源码阁8 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse
wabs6668 小时前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964139 小时前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉