LeetCode 1323: 6和9组成的最大数字 - 详细解题思路与Python实现
题目描述
给定一个由数字6和9组成的正整数num,你最多只能翻转一位数字,将6变成9,或者将9变成6。返回你可以得到的最大的数字。
示例
输入:num = 9669
输出:9969
解释:改变第一位数字可以得到 6669,改变第二位数字可以得到 9969,改变第三位数字可以得到 9699,改变第四位数字可以得到 9666。
其中最大的数字是 9969。
约束条件
- 1 <= num <= 10^4
- num 仅由数字 6 和 9 组成
解题思路
核心思想
要获得最大的数字,我们需要理解一个关键点:在数字的某一位上,9比6大。因此,如果我们想要通过翻转一位数字来获得最大值,应该将6改为9,而不是将9改为6。
算法步骤
- 将数字转换为字符串:便于逐位处理
- 从左到右遍历每一位:找到第一个6
- 将第一个6改为9:这样能获得最大的数字
- 返回结果:如果没有找到6,说明原数字已经是最大的
为什么这样是正确的?
- 贪心策略:我们总是选择将最左边的6改为9,因为这样能获得最大的数字
- 数学原理:在相同位数的情况下,高位数字越大,整个数字就越大
- 最优性:由于只能翻转一次,将最左边的6改为9是最优选择
代码实现
方法一:逐位遍历
class Solution:
def maximum69Number(self, num: int) -> int:
"""
将数字中的第一个6改为9,以获得最大数字
Args:
num (int): 输入的正整数,只包含6和9
Returns:
int: 修改后能得到的最大数字
"""
# 将数字转换为字符串,便于逐位处理
num_str = str(num)
# 从左到右遍历每一位数字
for i in range(len(num_str)):
# 找到第一个6,将其改为9
if num_str[i] == '6':
# 构造新的字符串:前i位保持不变,第i位改为9,后面保持不变
new_num_str = num_str[:i] + '9' + num_str[i+1:]
return int(new_num_str)
# 如果没有找到6,说明原数字已经是最大的(全是9)
return num
方法二:字符串替换
def maximum69Number_alternative(self, num: int) -> int:
"""
另一种实现方法:使用字符串替换
Args:
num (int): 输入的正整数,只包含6和9
Returns:
int: 修改后能得到的最大数字
"""
# 将数字转换为字符串
num_str = str(num)
# 使用replace方法,只替换第一个6
# 如果字符串中没有6,replace不会做任何改变
new_num_str = num_str.replace('6', '9', 1)
return int(new_num_str)
复杂度分析
时间复杂度
- O(log n):其中n是数字的位数
- 我们需要遍历数字的每一位,数字的位数是log₁₀(n)
空间复杂度
- O(log n):需要存储字符串形式的数字
- 字符串的长度等于数字的位数
测试用例
def test_solution():
"""测试函数,验证算法的正确性"""
solution = Solution()
# 测试用例
test_cases = [
(9669, 9969), # 标准测试用例
(9996, 9999), # 6在最后一位
(9999, 9999), # 全是9,无需修改
(6666, 9666), # 全是6,修改第一位
(6969, 9969), # 6和9交替
(6, 9), # 单个数字6
(9, 9), # 单个数字9
]
for i, (input_num, expected) in enumerate(test_cases, 1):
result = solution.maximum69Number(input_num)
status = "✓" if result == expected else "✗"
print(f"测试用例 {i}:")
print(f" 输入: {input_num}")
print(f" 期望输出: {expected}")
print(f" 实际输出: {result}")
print(f" 状态: {status}")
print("-" * 30)
测试结果
测试用例 1:
输入: 9669
期望输出: 9969
实际输出: 9969
状态: ✓
测试用例 2:
输入: 9996
期望输出: 9999
实际输出: 9999
状态: ✓
测试用例 3:
输入: 9999
期望输出: 9999
实际输出: 9999
状态: ✓
测试用例 4:
输入: 6666
期望输出: 9666
实际输出: 9666
状态: ✓
测试用例 5:
输入: 6969
期望输出: 9969
实际输出: 9969
状态: ✓
测试用例 6:
输入: 6
期望输出: 9
实际输出: 9
状态: ✓
测试用例 7:
输入: 9
期望输出: 9
实际输出: 9
状态: ✓
算法优化思路
1. 数学方法优化
如果我们想要进一步优化,可以考虑使用数学方法:
def maximum69Number_math(self, num: int) -> int:
"""
使用数学方法:找到最高位的6,然后加上相应的差值
"""
# 找到最高位的6的位置
temp = num
digit = 1
max_digit = 1
while temp > 0:
if temp % 10 == 6:
max_digit = digit
temp //= 10
digit *= 10
# 如果找到了6,将其改为9
if max_digit > 1:
return num + 3 * (max_digit // 10)
return num
2. 位运算方法(如果适用)
虽然这个题目不直接涉及位运算,但我们可以思考类似的优化思路。
常见错误分析
错误1:将9改为6
# 错误示例
if num_str[i] == '9':
new_num_str = num_str[:i] + '6' + num_str[i+1:]
return int(new_num_str)
问题:将9改为6会使数字变小,这与我们的目标相反。
错误2:修改多个数字
# 错误示例
for i in range(len(num_str)):
if num_str[i] == '6':
num_str[i] = '9' # 修改了原字符串
问题:题目要求只能修改一位数字,而且字符串是不可变的。
错误3:不考虑边界情况
# 错误示例
if num_str[0] == '6':
return int('9' + num_str[1:])
问题:没有考虑数字只有一位的情况,或者没有6的情况。
总结
这道题目是一个很好的贪心算法入门题,主要考察以下几点:
- 贪心思想:选择最优的局部解
- 字符串处理:熟练使用字符串操作
- 边界情况处理:考虑各种输入情况
- 算法效率:理解时间复杂度和空间复杂度
关键要点
- 贪心策略:总是将最左边的6改为9
- 字符串操作:使用切片操作构造新字符串
- 边界处理:考虑全是9的情况
- 代码简洁性:使用replace方法可以简化代码
这道题目虽然简单,但很好地体现了算法设计中的贪心思想,是学习算法基础的好题目。
标签:#LeetCode #Python #算法 #贪心算法 #字符串处理 #每日一题
相关题目: