贪心题目:单调递增的数字

文章目录

题目

标题和出处

标题:单调递增的数字

出处:738. 单调递增的数字

难度

5 级

题目描述

要求

一个整数是单调递增的,当且仅当每一对相邻位的数字 x \texttt{x} x 和 y \texttt{y} y 满足 x ≤ y \texttt{x} \le \texttt{y} x≤y。

给定一个整数 n \texttt{n} n,返回小于等于 n \texttt{n} n 且单调递增的最大数字。

示例

示例 1:

输入: n = 10 \texttt{n = 10} n = 10

输出: 9 \texttt{9} 9

示例 2:

输入: n = 1234 \texttt{n = 1234} n = 1234

输出: 1234 \texttt{1234} 1234

示例 3:

输入: n = 332 \texttt{n = 332} n = 332

输出: 299 \texttt{299} 299

数据范围

  • 0 ≤ n ≤ 10 9 \texttt{0} \le \texttt{n} \le \texttt{10}^\texttt{9} 0≤n≤109

解法

思路和算法

如果整数 n n n 已经单调递增,则答案即为 n n n。如果整数 n n n 不满足单调递增,则答案小于 n n n。

为了方便处理,将整数 n n n 转换成字符数组 array \textit{array} array,然后遍历字符数组 array \textit{array} array 计算小于等于 n n n 且单调递增的最大数字。为了得到单调递增的数字,其对应的字符数组 array \textit{array} array 必须单调递增。

从右到左遍历 array \textit{array} array,对于遍历到的每个下标 i i i,如果 array i > array i + 1 \textit{array}i > \textit{array}i + 1 arrayi>arrayi+1,则 array \textit{array} array 不满足单调递增,且在不减少 array i \textit{array}i arrayi 的情况下无法使 array \textit{array} array 满足从下标 i i i 到末尾的子数组单调递增。为了使 array \textit{array} array 满足从下标 i i i 到末尾的子数组单调递增,可以执行如下操作。

  1. 将 array i \textit{array}i arrayi 减 1 1 1。

  2. 将 array \textit{array} array 从下标 i + 1 i + 1 i+1 到末尾的数字全部设为 9 9 9。

此时 array \textit{array} array 从下标 i i i 到末尾的每一位都取可能的最大值,因此 array \textit{array} array 表示的整数为小于 n n n 且满足从下标 i i i 到末尾的子数组单调递增的最大整数。

更新 array \textit{array} array 从下标 i i i 到末尾的数字之后,继续向左遍历,对于遍历到的每个下标执行该操作,遍历到最高位之后,即可得到小于等于 n n n 且单调递增的最大数字。特别地,如果对于任意下标 i i i 都有 array i ≤ array i + 1 \textit{array}i \le \textit{array}i + 1 arrayi≤arrayi+1,则整数 n n n 已经单调递增,答案是 n n n。

实现方面,当 array i \textit{array}i arrayi 减少时,并不需要立即更新 array \textit{array} array 从下标 i + 1 i + 1 i+1 到末尾的数字,而是可以找到被修改的最高位下标,遍历结束之后将被修改的最高位右边的数字全部设为 9 9 9 即可。

根据上述分析,可以使用贪心的思想计算小于等于 n n n 且单调递增的最大数字。

  1. 用 startIndex \textit{startIndex} startIndex 表示 array \textit{array} array 中被修改的最高位下标,初始时 startIndex = − 1 \textit{startIndex} = -1 startIndex=−1。从右到左遍历 array \textit{array} array,对于每个下标 i i i,如果 array i > array i + 1 \textit{array}i > \textit{array}i + 1 arrayi>arrayi+1,则将 array i \textit{array}i arrayi 减 1 1 1 并将 startIndex \textit{startIndex} startIndex 更新为 i i i。

  2. 遍历结束之后,如果 startIndex ≥ 0 \textit{startIndex} \ge 0 startIndex≥0 则将 array \textit{array} array 从下标 startIndex + 1 \textit{startIndex} + 1 startIndex+1 到末尾的数字全部设为 9 9 9。

  3. 此时 array \textit{array} array 对应的数字为小于等于 n n n 且单调递增的最大数字。

代码

java 复制代码
class Solution {
    public int monotoneIncreasingDigits(int n) {
        char[] array = String.valueOf(n).toCharArray();
        int numLength = array.length;
        int startIndex = -1;
        for (int i = numLength - 2; i >= 0; i--) {
            if (array[i] > array[i + 1]) {
                array[i]--;
                startIndex = i;
            }
        }
        if (startIndex >= 0) {
            for (int i = startIndex + 1; i < numLength; i++) {
                array[i] = '9';
            }
        }
        return Integer.parseInt(new String(array));
    }
}

复杂度分析

  • 时间复杂度: O ( log ⁡ 10 n ) O(\log_{10} n) O(log10n),其中 n n n 是给定的整数。整数 n n n 的位数是 O ( log ⁡ 10 n ) O(\log_{10} n) O(log10n),最多需要遍历整数两次。

  • 空间复杂度: O ( log ⁡ 10 n ) O(\log_{10} n) O(log10n),其中 n n n 是给定的整数。需要创建长度为 O ( log ⁡ 10 n ) O(\log_{10} n) O(log10n) 的数组记录每一位数字。

相关推荐
Tisfy4 小时前
LeetCode 3727.最大交替平方和:排序 (双指针可选)
算法·leetcode·题解·贪心·数组·排序
jyyyx的算法博客4 天前
机器人开箱子【贪心 + 模拟】
贪心·模拟
伟大的车尔尼7 天前
贪心题目:使绳子变成彩色的最短时间
贪心
Tisfy9 天前
LeetCode 0678.有效的括号字符串:O(n)+O(1)一次遍历
算法·leetcode·字符串·题解·贪心·括号匹配
伟大的车尔尼10 天前
贪心题目:坏了的计算器
贪心
lvwangshu12 天前
T1 称重(weight)题解
题解·贪心·总结·技巧·性质题·思维好题
伟大的车尔尼12 天前
贪心题目:十-二进制数的最少数目
贪心
伟大的车尔尼14 天前
贪心题目:不含 AAA 或 BBB 的字符串
贪心
伟大的车尔尼15 天前
贪心题目:最少的后缀翻转次数
贪心