该题不在hot-100因为在面试真实遇到所以记录下来。
描述:给定一个数字n,给定一个数组,求数组所有元素可以组成小于n的最大数,数组里面的元素可以重复使用
该题还有变形题:就是元素不可重复使用,本质是一道变形题,难度还是比较大。 最大为 N 的数字组合
https://leetcode.cn/problems/numbers-at-most-n-given-digit-set/
思路(和 LeetCode902 同源,贪心 + 数位构造)
-
把 n 转字符串
s,长度len_s -
分两种情况:
- 情况 1:拼的数位数 < len_s直接用 digits 里最大数字,拼「位数少 1 的全最大数」,一定更小,且是同长度最大
- 情况 2:拼的数位数 = len_s 逐位贪心试探:
- 选比当前位小的最大数字 → 后面全填最大数字,直接组成候选
- 选和当前位相等的数字 → 继续下一位递归
- 选更大的 → 跳过
-
两种情况取最大值即可
def maxNumberLessThanN(digits, n: int) -> int:
s = str(n)
m = len(s)
digits = list(map(str, digits))
max_d = max(digits) # 数组里最大数字字符
res = -1# 情况1:构造 长度 = m-1 的最大数(一定比n小) if m > 1: candidate = int(max_d * (m - 1)) # 排除前导0 if candidate != 0: res = candidate # 情况2:构造 长度 = m 且 < n 的最大数 def dfs(pos, path): nonlocal res if pos == m: num = int(''.join(path)) if num < n and num > res: res = num return limit = s[pos] for d in sorted(digits, reverse=True): # 前导0禁止 if not path and d == '0': continue if d < limit: # 当前位选更小,后面全填最大数字,直接生成最大候选 tmp = path + [d] + [max_d] * (m - pos - 1) num = int(''.join(tmp)) if num < n and num > res: res = num elif d == limit: # 相等继续往下搜 path.append(d) dfs(pos + 1, path) path.pop() else: # 比当前位大,直接跳过 continue dfs(0, []) return res