【字节跳动高频面试题】不超过 N 的最大数拼接

题目描述

给定一个按 非递减顺序 排列的数字字符数组 digits(如 ["1","3","5","7"]),你可以任意次数使用这些字符,拼接成一个正整数

请返回:所有能拼出且 ≤ 给定整数 n 的正整数中,值最大的那个


示例

输入:digits = ["1","3","5","7"], n = 100
输出:77

解法一:暴力回溯(Backtrack 贪心)

思路概览

我们希望构造一个不大于 n 的数,且尽可能大。每一位从高位到低位逐位尝试:

  1. 若该位能找到一个 ≤ s[i] 的最大字符 d

    • 如果 d == s[i],继续匹配下一位;
    • 如果 d < s[i],则当前为转折点,后面全部填 digits 中最大值,直接构成答案;
  2. 如果该位没有合法字符(即所有字符都 > s[i]),则需要回退(Backtrack):

    • 回退到前一位,寻找一个更小字符,之后所有位都填最大字符。

若所有位都成功对齐 n 的每一位字符,则答案为 n 本身。否则返回构造出的最大值。

时间复杂度分析

  • 最坏情况每一位都需要回退多次;

  • 时间复杂度约为 O(L × |digits|),其中:

    • L = log10(n) + 1 为位数;
    • |digits| ≤ 9

即便 n 非常大(如 10^18),依然能在毫秒级别内完成。

C++ 实现

int bytedance1(vector<string>& digits, int n) {
bool flag = false; // 是否已经满足 <,之后可以直接填最大digit
string s = to_string(n);
n = s.size();
unordered_map<char, int> mp;
for(int i = 0; i < digits.size(); i++) mp[digits[i][0]] = i + 1; vector<char> res(n, digits[0][0]); for(int i = 0; i < n && !flag; i++) {
for(auto& d : digits) {
if(d[0] <= s[i]) res[i] = d[0];
}
if(res[i] < s[i]) {
flag = true;
for(int j = i + 1; j < n; j++) res[j] = digits.back()[0];
} else if(res[i] > s[i]) { // 无法继续匹配
int j = i;
while(j >= 0 && res[j] == digits[0][0]) j--;
if(j == -1) {
res.resize(n - 1, digits.back()[0]);
} else {
for(auto& d : digits) {
if(d[0] < s[j]) res[j] = d[0];
}
j++;
for(; j < n; j++) res[j] = digits.back()[0];
}
flag = true;
}
} for(auto& ch : res) cout << ch;
cout << endl;
return 0;
}

解法二:数位 DP(Digit DP)

解题框架

使用数位 DP 框架模板,通过参数限制合法性。

  • L:下界,补齐成和 R 同样的位数(例如 "001");

  • R:上界,即 n

  • digits:枚举所有合法的数字;

  • 状态参数:

    • i:当前位;
    • isZero:是否还处于前导零;
    • isLow:当前是否仍受下界限制;
    • isHigh:当前是否仍受上界限制。

关键转移逻辑

int dfs(int i, int isZero, int isLow, int isHigh);
  • isZero && l == 0 时,可以跳过当前位;
  • !isZero && !isLow && !isHigh 时,结果可以记忆化缓存;
  • 尝试填入所有合法的 digits 中的数字,满足边界限制即可。

C++ 实现

string L, R;
vector<int> digits;
int n, f[10];
string tmp = "", res = ""; int dfs(int i, int isZero, int isLow, int isHigh) {
if(i == n) {
if(res == "") res = tmp; // 保存最大值
return !isZero;
} if(!isZero && !isLow && !isHigh && ~f[i]) return f[i]; int l = isLow ? L[i] - '0' : 0;
int r = isHigh ? R[i] - '0' : 9;
int ans = 0; for(int& d : digits) {
if(d >= l && d <= r) {
tmp.push_back(d + '0');
ans += dfs(i + 1, 0, isLow && d == l, isHigh && d == r);
tmp.pop_back();
}
} if(isZero && l == 0) ans += dfs(i + 1, 1, 1, isHigh && r == 0); if(!isZero && !isLow && !isHigh) f[i] = ans;
return ans;
} int bytedance2(vector<string>& digitsStr, int n) {
R = to_string(n);
L = string(R.size() - 1, '0') + "1";
::n = R.size(); digits.clear();
for(auto& x : digitsStr) digits.emplace_back(x[0] - '0');
ranges::reverse(digits); // 从大到小尝试 memset(f, -1, sizeof f);
dfs(0, 1, 1, 1);
cout << res << endl;
return 0;
}

LeetCode 原题推荐

LeetCode 902. 最大为 N 的数字组合

  • 类型:数位 DP
  • 难度:中等
  • 高频企业题:字节跳动、美团、阿里

总结

方法 思路 优点 缺点
回溯贪心法 模拟构造 逻辑直观,易于调试 实现较繁琐,回退处理需细致
数位 DP 状态转移+缓存 可扩展,适合复杂限制条件 学习门槛略高,状态较多

【字节跳动高频面试题】不超过 N 的最大数拼接的更多相关文章

  1. 字节跳动-前端面试题 Multi Promise Order

    字节跳动-前端面试题 Multi Promise Order Promise Order Async/Await async function async1 () { console.log('asy ...

  2. 双非本科字节跳动Android面试题分享(已拿offer)

    基本情况 本人系非985非211普通本科生一枚,有实习有项目经历但成绩普通,在面试前刷了很多面经.面试题,这里也把自己的分享下,做个回报好了,顺便攒攒人品,一到这种时候人就迷信起来了. 面试是以视频面 ...

  3. 字节跳动社会招聘&内推-帮助你更快加入字节跳动

    字节跳动社会招聘&内推「[内推码]:4J8CA3W」 内推时间:一直有效 招聘对象:根据招聘要求而定 社招投递链接: https://job.toutiao.com/s/de5teaA 应届生 ...

  4. 字节跳动Android实习面试难吗,应该如何应对?

    字节跳动的面试难不难其实很难去非常准确的定义,但是能肯定的一点是,字节跳动的面试题都很有水平,真正考察了该岗位在以后工作中需要的能力. 大学学的Java后面又自学Android方向,跟着老师在实验室做 ...

  5. 2019 字节跳动java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.字节跳动等公司offer,岗位是Java后端开发,因为发展原因最终选择去了字节跳动,入职一年时间了,也成为了面 ...

  6. 最新 字节跳动java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.字节跳动等10家互联网公司的校招Offer,因为某些自身原因最终选择了字节跳动.6.7月主要是做系统复习.项目复盘.Leet ...

  7. 多次面试被拒,‘宅家苦修’30天,终获美团offer(含字节跳动/阿里/腾讯等大厂面试题整理)

    背景:双非渣本. 今年由于疫情,上半年一直在家里.2月份本来无忧无虑,呆在家里不给国家添乱的时候,发现身边的同学找到了大厂的offer.心里开始有点慌张.本来想在3月份如果能回到学校,就开始考研之路, ...

  8. 从阿里、腾讯的面试真题中总结了这11个Redis高频面试题

    前言 现在大家的工作生活基本已经是回归正轨了,最近也是迎来了跳槽面试季,有些人已经拿到了一两个offer了. 这段时间收集了阿里.腾讯.百度.京东.美团.字节跳动等公司的Java面试题,总结了Redi ...

  9. 字节跳动实习面经分享(已拿offer附攻略)

    大家好,我是bigsai,今天给大家分享自己字节跳动面试经验分享. enum我面得岗位是后台实习开发,具体部门是懂车帝,总体感觉就是字节的流程真的好快,只要安排面试,那流程接着很快. 大概是上上周投递 ...

  10. 一份热乎的字节跳动客户端面经,已拿Offer

    字节面试过程: 4月4号进行内推,7天的简历评估,11号接到电话面试,尽管猝不及防回答仓促,但好在前期准备充分,通过.14号现场面试,次日收到通知,通过,二面.三面都很顺利.20号进行HR面,26号收 ...

随机推荐

  1. JSON Objects Framework(1)

    学习datasnap,json必须掌握.用自身的JSON,就必须熟悉JSON Objects Framework.其中tostring和value区别就是一个坑. The JSON objects f ...

  2. FastAPI 核心安全功能与模板渲染的完整示:登录、CSRF、JWT、会话、认证和缓存功能

    以下是一个整合 FastAPI 核心安全功能与模板渲染的完整示例,基于多个技术文档的最佳实践,包含登录.CSRF.JWT.会话.认证和缓存功能: from datetime import dateti ...

  3. 为什么不推荐在 MySQL 中直接存储图片、音频、视频等大容量内容?

    在MySQL中直接存储图片.音频.视频等大容量内容(通常称为BLOB数据)通常不被推荐,主要原因包括以下几点: 1. 性能问题 存储效率:存储大容量文件(如图片.音频.视频等)会大幅增加数据库的存储负 ...

  4. 在 .NET 中的 ConvertAll 和 Select 方法哪个性能好

    .NET 的 List 中提供了 ConvertAll 和 Select 两个方法,在开发中实际上应该使用哪一个? 接下来通过基准测试脚本来对比性能. 先编写基准测试脚本: [MemoryDiagno ...

  5. 题解:CF1955E Long Inversions

    简单题. 考虑贪心地进行修改,每次选择字符串中最左侧第一个 000,并以该位置为左端点进行一次修改,可以发现若 lenlenlen 合法则这样一定构造出全 111 串. 然而直接暴力实现是 O(n2) ...

  6. 16.1k star! 只需要DDL就能一键生成数据库关系图!开源神器ChartDB让你的数据结构"看得见"

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 ChartDB是一款开源的数据库可视化神器,通过一句智能查询就能自动生成专业的数据库关系图. ...

  7. 原生JS表格数据常用总结

    主要是在数据报表这块, 做了好几年发现, 其实用户最终想要看的并不是酷炫的BI大屏, 而是最基础也是最复杂的 中国式报表. 更多就是倾向于从表格中去获取数据信息, 最简单的就是最好的, 于是还是来总结 ...

  8. TVM:Schedule的理解

    schedule与计算逻辑分离是自动代码生成技术的核心概念,由MIT CASIL组的Jonathan Ragan-Kelley在2012年发表在SIGGRAPH上的文章率先提出,然后在2013年发表在 ...

  9. 用C#将多个jpg合成一个pdf

    nuget安装iTextSharp: static void MergePDF(string picPath,string pdfPath) { string[] picFileNames=Direc ...

  10. 2.2.net core 工作流WorkFlow流程(流程设计)

    流程设计 WikeFlow官网:http://www.wikesoft.com WikeFlow学习版演示地址:http://workflow.wikesoft.com WikeFlow学习版源代码下 ...