加载中...

难题本 | LeetCode665. 非递减数列

题目链接:https://leetcode-cn.com/problems/non-decreasing-array/

看到这题第一感受:简单题!

做完这题第一感受:简单题?

题目

给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。

我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]

示例1

  • 输入: nums = [4,2,3]

  • 输出: true

  • 解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。

示例2

  • 输入: nums = [4,2,1]

  • 输出: false

数据范围

  • 1 <= n <= 10 ^ 4
  • - 10 ^ 5 <= nums[i] <= 10 ^ 5

分析

简单题毕竟还是简单题,思路初步找起来是比较容易的。

我们把所有元素以(index, value)这种形式在坐标轴上画出来,横坐标是元素下标,纵坐标是元素数值,那么如果希望该数组是一个非递减数列,这张折线图的形状最终需要满足各个部位的斜率都大于等于0

如果在允许改变一个元素的情况下,希望该数组变为一个非递减数列,那么初始图形只允许有一个波谷存在,而且这个波谷还必须具备某些性质。

例如,对于一组数据3,5,6,7,8,3,10,可以改变倒数第二个元素3,令其等于8,即可构成一个非递减数列。

这组数据原本的折线图是这样的:

改变一个元素后的折线图是这样的:

下面给出原始折线图需要满足的两个性质:

  • 对于原始的折线图,首先只允许有一个波谷存在,如果超过一个波谷,说明存在有两处的非递减情况,这时只改变一个元素是不行的。

  • 对于这一处波谷,还有几种情况:

    • 波谷左边的元素小于等于波谷右边。也就是Fig1的情况,我们可以直接令波谷元素等于波谷左边的元素,这样就填平了波谷,并且保持继续上涨的趋势不变;如果波谷右边已经没有元素,说明已经到达了最后,直接将波谷元素拔高即可;

    • 波谷左边的元素大于波谷右边。此时我们就不能将波谷拔高到其左边的元素了,只能将其左边的元素拉低到波谷。这种情况下,我们要考虑到波谷左边第二个元素,如果它也大于波谷,这时就不存在一种办法来填平波谷。

      我们先看看可以填平波谷的情况:

      可以看到,波谷左边第二个元素小于波谷,那么我们将波谷左边的元素拉低到波谷的水平,就能把波谷消除掉:

      当波谷左边第二个元素大于波谷,我们把波谷左边的元素拉低到波谷时,产生了新的波谷:

      特别地,当波谷左边只有一个元素,自然就直接将左边的元素拉低即可。示例1中的nums = [4,2,3]就属于这种情况。

AC代码

下标从前往后递增,每次判断是否出现一个下降的区段。

首先,全局范围内只能出现一次下降;

其次,这个波谷要分上面两种情况讨论。

class Solution {
public:
    bool checkPossibility(vector<int>& nums) {
        int len = nums.size();
        if (len == 1)
        {
            return true;
        }

        int ptr;
        int change = 0;  // 改变的元素个数
        bool res = true;

        ptr = 1;
        while (ptr < len)
        {
            if (nums[ptr] < nums[ptr - 1])  // 递减了
            {
                if (change < 1)
                {
                    // 波谷左边的元素大于波谷右边,只能拉低左边元素,不能拔高波谷
                    if (ptr + 1 < len && nums[ptr - 1] > nums[ptr + 1])
                    {
                        // 只能改变nums[ptr - 1]
                        if ((ptr - 2 >= 0 && nums[ptr - 2] <= nums[ptr]) || ptr == 1)
                        {
                            nums[ptr - 1] = nums[ptr];
                            change++;
                            continue;
                        }
                        else
                        {
                            // nums[ptr - 2] > nums[ptr]
                            res = false;
                            break;
                        }
                    }
                    else  // 波谷左边元素小于等于波谷右边元素,直接拔高波谷
                    {
                        nums[ptr] = nums[ptr - 1];
                        change++;
                        continue;
                    }
                }
                else
                {
                    res = false;
                    break;
                }
            }
            ptr++;
        }

        return res;
    }
};

表现很一般,就不放出来了。比较复杂的逻辑增大了时间消耗,暂时没有看到有什么优化的办法。

9 comments
Anonymous
Markdown is supported
@mpv945
mpv945commentedover 2 years ago

添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

@SGS4ever
SGS4evercommentedover 2 years ago

@mpv945
添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

我的博客没有使用图床,所以没办法帮到你~

@Celetherin
Celetherincommentedover 2 years ago

您好,我也是使用的stack主题,我在照着您的方法添加返回顶部按钮时,遇到了按钮虽然出现、也能够点击,但无法实现实际上的返回顶部功能的问题,我没有任何的代码知识,不知道您有没有解决方法?
另外,也是想提醒一下其他需要这篇教程的朋友,最新版的stack主题,添加返回按钮的组件应该在layouts/partials/sidebar/right.html, 在layouts/_default/single.html中添加代码会导致出现两个右边栏。

@jsjcjsjc
jsjcjsjccommentedabout 2 years ago

请教一下博主,如何优雅的给stack主题添加广告哈?
我只想在左或者右侧边栏底部,或者每篇文章底部添加一个小小的广告,但是默认似乎的满屏广告哈~~
感谢

@SGS4ever
SGS4evercommentedabout 2 years ago
@ClimbingMouse
ClimbingMousecommentedover 1 year ago

你好,按照你的方法设置页面载入动画,这个动画不会停止咋办啊

@46fafa
46fafacommentedover 1 year ago

博主你好,请问一下主页布局修改哪里的代码如何作用于整个网页,我发现修改后的布局只存在主页和前两篇文章,其他部分还是没修改的样子

@4kohakunushi
4kohakunushicommentedabout 1 year ago

你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

@SGS4ever
SGS4evercommentedabout 1 year ago

首先我只能基于本文使用的Stack版本来尝试解答,因为没看过当前的Stack主题的代码~
我重新翻了下此前写的关于高亮的内容,理论上只要你的post页面的标题在menu配置中即可高亮。如果post页面是你站点的根路径,那应该可以参考我的文章里写的方法,修改下active的触发逻辑~

@4kohakunushi
你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

有朋自远方来,不亦说乎?