LeetCode 1323: 6和9组成的最大数字

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。

算法步骤

  1. 将数字转换为字符串:便于逐位处理
  2. 从左到右遍历每一位:找到第一个6
  3. 将第一个6改为9:这样能获得最大的数字
  4. 返回结果:如果没有找到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的情况。

总结

这道题目是一个很好的贪心算法入门题,主要考察以下几点:

  1. 贪心思想:选择最优的局部解
  2. 字符串处理:熟练使用字符串操作
  3. 边界情况处理:考虑各种输入情况
  4. 算法效率:理解时间复杂度和空间复杂度

关键要点

  • 贪心策略:总是将最左边的6改为9
  • 字符串操作:使用切片操作构造新字符串
  • 边界处理:考虑全是9的情况
  • 代码简洁性:使用replace方法可以简化代码

这道题目虽然简单,但很好地体现了算法设计中的贪心思想,是学习算法基础的好题目。


标签:#LeetCode #Python #算法 #贪心算法 #字符串处理 #每日一题

相关题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值