小于 n 的最大数
Posted 恋喵大鲤鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小于 n 的最大数相关的知识,希望对你有一定的参考价值。
文章目录
1.问题描述
数组 A 中给定可以使用的 1~9 的数,返回由数组 A 中的元素组成的小于 n 的最大数。
示例 1:A=1, 2, 9, 4,n=2533,返回 2499。
示例 2:A=1, 2, 5, 4,n=2543,返回 2542。
示例 3:A=1, 2, 5, 4,n=2541,返回 2525。
示例 4:A=1, 2, 9, 4,n=2111,返回 1999。
示例 5:A=5, 9,n=5555,返回 999。
2.难度等级
medium。
3.热门指数
★★★★☆
出题公司:字节跳动。
4.解题思路
此题需要用到贪心和回溯。
从高位开始遍历,对每一位先尝试使用相同数字,除了最后一位。如果没有相同的数字时,尝试是否有比当前数字更小的,有的话选更小的数字里最大的,剩下的用最大数字。都没有就向前回溯看前一个有没有更小的。如果一直回溯到第一个数字都没有更小的数字,就用位数更少的全都是最大数字的数。
5.实现示例
5.1 C++
// getMaxDigitLtD 获取小于指定数字的最大数字。
int getMaxDigitLtD(const vector<int> &digits, int digit)
for (auto it = digits.rbegin(); it != digits.rend(); it++)
if (*it < digit)
return *it;
return 0;
// getMaxNumLtN 获取小于 n 的最大数。
int getMaxNumLtN(vector<int> &digits, int n)
// 获取 n 的每一位数字。
vector<int> ndigits;
while (n > 0)
ndigits.push_back(n % 10);
n /= 10;
// 排序给定的数字数组。
sort(digits.begin(), digits.end());
// 数字写入 map 用于快速查看是否存在。
unordered_set<int> set;
for (auto v : digits)
set.insert(v);
// 目标数的每一位数字。
vector<int> tdigits(ndigits.size());
// 从高位遍历,尽可能地取相同值,除了最后一位。
for (int i = ndigits.size() - 1; i >= 0; i--)
// 存在相同的数字(最后一位除外)。
if (i > 0 && set.find(ndigits[i]) != set.end())
tdigits[i] = ndigits[i];
continue;
// 存在小于当前位的最大数字。
auto d = getMaxDigitLtD(digits, ndigits[i]);
if (d > 0)
tdigits[i] = d;
break;
// 需要回溯。
for (i++; i < ndigits.size(); i++)
tdigits[i] = 0;
// 小于当前位的最大数字。
d = getMaxDigitLtD(digits, ndigits[i]);
if (d > 0)
tdigits[i] = d;
break;
// 最高位也没有小于其的最大数字。
if (i == ndigits.size() - 1)
tdigits.resize(tdigits.size() - 1);
break;
// 拼装目标数。
int target = 0;
for (int i = tdigits.size() - 1; i >= 0; i--)
target *= 10;
if (tdigits[i] > 0)
target += tdigits[i];
continue;
// 取数字数组中最大的数字。
target += digits.back();
return target;
验证代码:
#include <algorithm>
#include <unordered_set>
#include <vector>
#include <iostream>
using namespace std;
int main()
auto digits = vector<int>1, 2, 9, 4;
cout << getMaxNumLtN(digits, 2533) << endl;
digits = vector<int>1, 2, 5, 4;
cout << getMaxNumLtN(digits, 2543) << endl;
digits = vector<int>1, 2, 5, 4;
cout << getMaxNumLtN(digits, 2541) << endl;
digits = vector<int>1, 2, 9, 4;
cout << getMaxNumLtN(digits, 2111) << endl;
digits = vector<int>5, 9;
cout << getMaxNumLtN(digits, 5555) << endl;
运行输出:
2499
2542
2525
1999
999
5.2 Golang
// getMaxDigitLtD 获取小于指定数字的数字。
func getMaxDigitLtD(digits []int, digit int) int
for i := len(digits) - 1; i>=0; i--
if digits[i] < digit
return digits[i]
return 0
// getMaxNumLtN 获取小于 n 的最大数。
func getMaxNumLtN(digits []int, n int) int
var ndigits []int
// 获取 n 的每一位数字。
for n > 0
ndigits = append(ndigits, n%10)
n /= 10
// 排序给定的数字数组。
sort.Ints(digits)
// 数字写入 map 用于查看是否存在。
m := make(map[int]struct)
for _, v := range digits
m[v] = struct
// 目标数的每一位数字。
tdigits := make([]int, len(ndigits))
// 从高位遍历,尽可能地取相同值,除了最后一位。
for i:= len(ndigits) - 1; i >= 0; i--
// 存在相同数字(最后一位除外)。
if _, ok := m[ndigits[i]]; ok && i > 0
tdigits[i] = ndigits[i]
continue
// 存在小于当前位的最大数字。
if d := getMaxDigitLtD(digits, ndigits[i]); d > 0
tdigits[i] = d
break
// 回溯
for i++; i < len(ndigits); i++
tdigits[i] = 0
if d := getMaxDigitLtD(digits, ndigits[i]); d > 0
tdigits[i] = d
break
// 最高位也没有小于其的最大数字。
if i == len(ndigits) - 1
tdigits = tdigits[:len(tdigits)-1]
break
// 组装目标数。
var target int
for i := len(tdigits) - 1; i >= 0; i--
target *=10
if tdigits[i] > 0
target += tdigits[i]
continue
target += digits[len(digits)-1]
return target
验证代码:
package main
import (
"fmt"
"sort"
)
func main()
fmt.Println(getMaxNumLtN([]int1,2,9,4, 2533))
fmt.Println(getMaxNumLtN([]int1,2,5,4, 2543))
fmt.Println(getMaxNumLtN([]int1,2,5,4, 2541))
fmt.Println(getMaxNumLtN([]int1,2,9,4, 2111))
fmt.Println(getMaxNumLtN([]int5,9, 5555))
运行输出:
2499
2542
2525
1999
999
参考文献
以上是关于小于 n 的最大数的主要内容,如果未能解决你的问题,请参考以下文章
Greedy Sequence(主席树-区间小于每个数的最大值)