小于 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 的最大数 - leetcode

以上是关于小于 n 的最大数的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3652大新闻 数位dp+期望概率dp

Greedy Sequence(主席树-区间小于每个数的最大值)

nyoj 寻找最大数

BZOJ 3668 [NOI2014]起床困难综合症

C++中使用cout输出int时,怎么在高位补0?如输出003.

NOYJ——寻找最大数