在算法刷题中,“仅由 6 和 9 组成的数字翻转优化” 是一道经典的贪心思想应用题。本文将以一段高效的 C++ 代码为例,拆解其解决 “最大 69 数” 问题的核心逻辑,带你理解如何用最少操作实现数值最大化。
一、题目背景与核心需求
题目要求给定一个仅由数字 6 和 9 组成的正整数num,最多翻转一位数字(6 变 9 或 9 变 6),返回能得到的最大数字。例如:
- 输入69,翻转第一位 6 为 9,得到99(最大结果);
- 输入9669,翻转左数第二位 6 为 9,得到9969。
核心需求的本质是 **“贪心选择”**:要让数字最大,需优先将最高位的 6 翻转为 9—— 因为高位数字对数值的影响远大于低位(如千位的 6 变 9,数值直接增加 3000,远胜于个位 6 变 9 的 3)。
二、代码逻辑逐行拆解
以下是我实现的完整代码,我将从变量定义到返回结果,逐一解析其设计思路:
class Solution {
public:
int maximum69Number (int num) {
// 1. 初始化高位因子n为1000(覆盖题目中num的最大可能位数:4位,如9999)
int n = 1000;
// 2. 从最高位到最低位遍历(每次因子除以10,依次检查千位、百位、十位、个位)
for(int i = 1000;i > 0;i /= 10){
// 3. 提取当前位数字:num/i得到高位部分,%10取当前位值
if(num / i % 10 == 6){
// 4. 翻转当前位6为9:增加3*i(如千位6变9,数值+3000=3*1000)
num = num + i * 3;
// 5. 翻转一次后立即退出循环(满足“最多翻转一位”的要求)
break;
}
}
// 6. 返回修改后的最大数字(若全为9,直接返回原num)
return num;
}
};
关键逻辑详解
- 高位因子的初始化:
变量n初始化为 1000,是因为题目中num由 6 和 9 组成,最大可能为 4 位数(如 9999),1000 恰好对应千位的权重。若num为 3 位数(如 699),遍历到i=100时仍能正常提取百位数字,无需担心位数不匹配。
- 从高位到低位的遍历设计:
循环条件i > 0且每次i /= 10,确保遍历顺序为 “千位→百位→十位→个位”。这种顺序正是贪心思想的体现 —— 优先处理高位,一旦找到第一个 6,翻转后数值提升最大,无需再检查低位。
- 当前位数字的提取技巧:
表达式num / i % 10是代码的 “核心提取器”。以num=699、i=100为例:
- num / i = 699 / 100 = 6(得到千位以下的高位部分);
- %10后得到6(即当前百位数字),精准判断是否需要翻转。
- 高效的数值修改:
当找到 6 时,用num + i * 3实现翻转。原理是:某一位的权重为i(如百位权重 100),6 变 9 相当于该位增加 3,整体数值增加3*i(600→900,差值 300=3*100),比先拆分数字、再重组的方式更简洁。
三、代码优势与边界测试
1. 优势总结
- 时间复杂度 O (1):固定遍历 4 次(千位到个位),与num的具体数值无关,属于常数级效率;
- 空间复杂度 O (1):仅用 1 个额外变量i,无额外数据结构;
- 逻辑直观:完全贴合 “优先翻转最高位 6” 的贪心策略,无冗余操作。
2. 边界测试验证
- 测试用例 1:num=9999(全 9)
循环中所有位的判断均为9,不进入翻转逻辑,直接返回9999,符合 “不翻转也能得到最大数” 的需求;
- 测试用例 2:num=6666(全 6)
遍历到i=1000时,第一个 6 被翻转,num变为6666+3000=9666,立即退出循环,得到最大结果;
- 测试用例 3:num=9696(混合位)
遍历到i=100(百位为 6)时,num变为9696+300=9996,退出循环,结果正确。
四、总结
这道题的解题关键在于 “抓住高位优先的贪心本质”,而你的代码恰好完美落地了这一思路 —— 通过固定高位因子、逐位检查、高效翻转的设计,用极简的代码实现了最优解。这种 “直击问题核心、避免冗余操作” 的编码风格,不仅能提升算法效率,也为类似的 “数字优化” 问题(如最大数字、最小数字修改)提供了可复用的思路框架。