当前位置: 首页 > news >正文

回溯 vs 贪心+二分:2种解法深度对比,解析字节面试题 902 的 3 个核心陷阱

回溯 vs 贪心+二分:2种解法深度对比与字节面试题902的3个核心陷阱解析

1. 问题背景与算法选择

在算法面试中,"小于n的最大数"这类问题频繁出现于字节跳动等一线互联网公司的考察范围。题目要求给定一个由1-9数字组成的数组nums,和一个目标数n,从nums中可重复选取数字组合出小于n的最大数。例如nums=[2,8,8,6,7],n=88888时,正确答案应为88876。

解决这类问题通常有两种主流算法思路:

  1. 回溯算法:通过深度优先搜索枚举所有可能的数字组合,保留满足条件的最大值
  2. 贪心+二分:利用贪心思想从高位到低位构造数字,配合二分查找优化选择过程

两种算法在时间复杂度、空间复杂度和代码实现难度上存在显著差异。回溯法时间复杂度为O(k^m)(k为nums长度,m为n的位数),而贪心+二分可优化至O(mlogk)。但在特定场景下,回溯法反而可能更直观易懂。

提示:算法选择应考虑输入规模,当n的位数超过5位时,回溯法性能会急剧下降

2. 回溯算法实现与优化

回溯法的核心在于系统地枚举所有可能解,并通过剪枝策略减少无效搜索。以下是优化后的Python实现:

class Solution: def maxNumber(self, nums, n): nums.sort(reverse=True) # 降序排列加速剪枝 self.max_res = -1 def backtrack(current): if current >= n: return self.max_res = max(self.max_res, current) for num in nums: backtrack(current * 10 + num) backtrack(0) return self.max_res

关键优化点

  • 预处理降序排列nums,优先尝试大数字
  • 及时剪枝:当current≥n时立即终止该路径
  • 全局变量记录最大值,避免传递复杂参数

典型测试用例分析

测试用例结果递归次数时间复杂度
nums=[2,8], n=22215O(2^2)
nums=[5,8,9], n=78597O(3^2)
nums=[2,8,8,6,7], n=88888888763124O(5^5)

3. 贪心+二分算法精解

贪心算法的核心思想是分步决策,每步选择当前最优解。结合二分查找可快速定位合适数字:

def maxNumberGreedy(nums, n): nums.sort() n_str = str(n-1) # 转换为字符串处理 res = [] for i in range(len(n_str)): cur_digit = int(n_str[i]) # 二分查找小于等于cur_digit的最大数 left, right = 0, len(nums) pos = -1 while left < right: mid = left + (right - left) // 2 if nums[mid] <= cur_digit: pos = mid left = mid + 1 else: right = mid if pos != -1: if nums[pos] == cur_digit: res.append(str(nums[pos])) else: res.append(str(nums[pos])) res.extend([str(nums[-1])]*(len(n_str)-i-1)) return int(''.join(res)) else: # 回溯处理 for j in range(len(res)-1, -1, -1): new_pos = bisect.bisect_left(nums, int(res[j])) - 1 if new_pos >= 0: res[j] = str(nums[new_pos]) res.extend([str(nums[-1])]*(len(n_str)-j-1)) return int(''.join(res)) return int(str(nums[-1])*(len(n_str)-1)) if len(n_str)>1 else -1 return int(''.join(res))

算法步骤解析

  1. 排序nums数组(升序)
  2. 将n-1转换为字符串逐位处理
  3. 对每位数字进行二分查找:
    • 找到≤当前位的最大数
    • 相等则继续下一位
    • 小于则填充剩余位为最大值
  4. 处理无法匹配的情况(回溯调整前一位)

4. 两种算法的对比分析

我们从三个维度对两种算法进行对比:

性能对比表

指标回溯算法贪心+二分
时间复杂度O(k^m)O(mlogk)
空间复杂度O(m)O(m)
最佳适用场景m<5的小规模数据m≥5的大规模数据
代码复杂度简单中等
是否需要排序推荐但不必须必须

决策树指导算法选择

开始 │ ├─ n的位数≤4? → 是 → 使用回溯法 │ └─ 否 → nums是否已排序? → 否 → 先排序(O(klogk)) │ └─ 是 → 使用贪心+二分法

实际测试数据对比

测试案例:nums=[2,5,8,9], n=5892 回溯法: - 执行时间:0.12s - 结果:5899 - 递归调用次数:1053 贪心+二分: - 执行时间:0.0004s - 结果:5899 - 二分查找次数:4

5. 面试中的三个核心陷阱

在解决此类问题时,面试官通常会考察以下三个易错点:

5.1 前导零处理

当nums中不包含0时,需注意:

  • 组合数字不应有前导零
  • 但题目通常规定n本身不含零(如902题)

错误示例

nums = [0,1,2], n=20 # 错误返回02

5.2 数字可重复使用

题目允许重复使用数字,但容易忽略:

  • 回溯法中需允许重复选择
  • 贪心法中需考虑重复填充最大值的情况

5.3 数组未排序

未排序的nums会导致:

  • 二分查找失效
  • 回溯法效率降低

正确处理

# 必须排序! nums.sort() # 贪心必须 nums.sort(reverse=True) # 回溯推荐

6. 测试用例设计与验证

完备的测试用例应覆盖以下场景:

测试类型示例输入预期输出验证点
边界值nums=[9], n=1-1无解情况
完全匹配nums=[2,5,8], n=258258等值处理
数字重复nums=[8,8], n=8988重复利用
大数测试nums=[1,3,5,7], n=10000077777性能承受
零特殊情况nums=[0,1], n=101零处理

调试技巧

  • 在回溯法中打印递归树
  • 在贪心算法中跟踪每位选择
  • 使用小规模数据手动验证

7. 算法扩展与变种

该问题的变种及对应解法:

  1. 不可重复使用数字

    • 修改回溯条件,记录已用数字索引
    • 贪心法需维护可用数字集合
  2. 包含零的数字

    • 单独处理第一位不能为零
    • 添加零值判断逻辑
  3. 多个最优解

    • 返回所有可能解而非单个
    • 需要额外存储空间
# 返回所有最大值的变种解法 def allMaxNumbers(nums, n): nums.sort(reverse=True) max_val = -1 res = [] def backtrack(current): nonlocal max_val if current >= n: return if current > max_val: max_val = current res.clear() if current == max_val: res.append(current) for num in nums: backtrack(current*10 + num) backtrack(0) return res

在实际面试中,展示对算法本质的理解比单纯写出代码更重要。建议从暴力解法入手,逐步优化,并清楚说明每个优化步骤的考虑因素和效果提升。对于字节跳动这类重视算法能力的公司,还需要关注代码的边界条件处理和异常情况应对。

http://www.jsqmd.com/news/1155464/

相关文章:

  • Error 88716 逼疯了多少NI工程师?cRIO与DAQmx版本不匹配,其实十分钟就能搞定
  • 2026年7月最新南昌欧米茄官方售后客服服务电话及地址网点大全 - 欧米茄官方服务中心
  • 学生综合成绩测评系统-springboot + vue
  • 2026性价比高的小程序制作公司
  • 九江暗装马桶首选看安装服务
  • # BMI 计算器深度解析:双 Slider 联动、健康分类算法与条件渲染建议
  • Gemini3.5Flash如何重塑前端AI原生工作流
  • 当蛋白质开始“随机漫步”:北大团队用概率模型重塑分子动力学轨迹生成
  • NAU8224与PIC18F4458构建高效音频系统
  • Zynq Linux 内核驱动开发与 insmod 加载流程指南
  • 成都活动策划公司怎么选?27年实战复盘:拒绝“草台班子”,高难度庆典看这几点 - GrowUME
  • 面试官的震撼:互联网大厂 Java 求职者面试技巧与应对
  • 清华PPT模板终极指南:2025学术演示的完整解决方案
  • WSL2 是 Codex CLI 的必需运行环境:原理、安装与国内接入全指南
  • 解决PulseView构建报错:libsigrok C++绑定缺失的完整指南
  • 2026年沈阳腕表回收市场 禹竞高价收表广受好评 - 奢品小当家
  • YOLOv8 与 YOLOv10 模型对比:COCO数据集上mAP、参数量与推理速度的3项核心指标分析
  • Java后端高效进阶路线:7大核心模块实战指南与AI赋能
  • Proxmox VE 9.1.1部署Windows 11 23H2完整实践指南
  • 基于 Trae + DeepSeek 的 Vibe Coding 实践指南(七):用AI写生产级代码与SDD编程
  • 2026年呼叫机器人厂家排名怎么看?
  • Rufus:打破系统安装限制的USB启动盘制作神器
  • AI训练数据版权争议:苹果被诉非法抓取YouTube视频
  • 针对无症状阿米巴感染,糠酸二氯尼特是肠道内杀滋养体的专属特效药
  • 上市公司高管数字知识断层强度数据集
  • 5分钟终极指南:一次性解决所有Windows C++运行库安装问题
  • 天津和平区名表回收门店大盘点|劳力士百达翡丽回收无隐形消费 - 逸程奢侈品回收中心
  • PDF文件太大的几种压缩方法:从在线工具到Python脚本
  • WiFi 显示已连接却提示无 Internet 安全?联想官方修复工具一键解决
  • 把 Ace Data Cloud 平台能力接入你的 AI 助手:MCP 文档、价格、API 与账户管理实战