LeetCode第263题_丑数

LeetCode 第263题:丑数

文章摘要

本文详细解析LeetCode第263题"丑数",这是一道数学问题。文章提供了简洁高效的除法判断解法,包含C#、Python、C++、JavaScript四种语言实现,配有详细的算法步骤图解和性能分析。适合算法初学者和想要掌握基础数学算法的开发者。

核心知识点: 数学运算、除法操作、循环控制
难度等级: 简单
推荐人群: 算法初学者、编程基础学习者

题目描述

编写一个程序判断给定的数是否为丑数。

丑数就是只包含质因数 2, 3, 5 的正整数。

示例

示例 1:

输入: 6
输出: true
解释: 6 = 2 × 3

示例 2:

输入: 8
输出: true
解释: 8 = 2 × 2 × 2

示例 3:

输入: 14
输出: false
解释: 14 不是丑数,因为它包含了另外一个质因数 7。

提示

  • -2^31 <= num <= 2^31 - 1
  • 1 通常被视为丑数。

解题思路

丑数的定义是只包含质因数 2、3、5 的正整数。根据这个定义,我们可以通过不断除以 2、3 和 5 来检查一个数是否为丑数。如果最后剩下的数是 1,那么这个数就是丑数;否则,它就不是丑数。

方法:除法判断

核心思想

  1. 如果给定的数 num 小于等于 0,则它不是丑数,直接返回 false
  2. 如果 num 等于 1,根据定义,它是丑数,直接返回 true
  3. 循环处理:只要 num 能被 2 整除,就将其除以 2;只要 num 能被 3 整除,就将其除以 3;只要 num 能被 5 整除,就将其除以 5
  4. 处理完所有可能的 2、3、5 因子后,检查剩余的数是否为 1。如果是 1,则原始数是丑数;否则,它不是丑数

算法优化

  • 使用循环和数组来简化代码结构
  • 先处理边界情况,提高代码健壮性
  • 使用迭代方式避免递归栈溢出风险

复杂度分析

  • 时间复杂度:O(log n),其中 n 是输入的数字。最坏情况下,n 的每一位都是 2、3 或 5 的因子,我们需要执行 log n 次除法
  • 空间复杂度:O(1),只使用了常数级别的额外空间

图解思路

算法步骤分析表

步骤 输入示例 操作 结果 说明
初始状态 num = 12 检查边界条件 num > 0,继续 12是正数,可能是丑数
第一轮 num = 12 除以2直到不能整除 num = 3 12 ÷ 2 ÷ 2 = 3
第二轮 num = 3 除以3直到不能整除 num = 1 3 ÷ 3 = 1
第三轮 num = 1 除以5直到不能整除 num = 1 1不能被5整除,保持不变
结果判断 num = 1 检查是否为1 true 最终结果为1,是丑数

不同情况分析表

输入 质因数分解 处理过程 最终结果 是否丑数
6 2 × 3 6→3→1 1
8 8→4→2→1 1
14 2 × 7 14→7 7 否(包含质因数7)
1 直接返回 1 是(特殊情况)
0 无意义 边界检查 false 否(非正数)

代码实现

C# 实现

public class Solution {
    public bool IsUgly(int num) {
        // 非正数不是丑数
        if (num <= 0) {
            return false;
        }
        
        // 循环除以2、3、5,直到不能整除为止
        int[] factors = {2, 3, 5};
        foreach (int factor in factors) {
            while (num % factor == 0) {
                num /= factor;
            }
        }
        
        // 如果最后剩下1,则是丑数;否则不是
        return num == 1;
    }
}

Python 实现

class Solution:
    def isUgly(self, num: int) -> bool:
        # 非正数不是丑数
        if num <= 0:
            return False
        
        # 循环除以2、3、5,直到不能整除为止
        for factor in [2, 3, 5]:
            while num % factor == 0:
                num //= factor
        
        # 如果最后剩下1,则是丑数;否则不是
        return num == 1

C++ 实现

class Solution {
public:
    bool isUgly(int num) {
        // 非正数不是丑数
        if (num <= 0) {
            return false;
        }
        
        // 循环除以2、3、5,直到不能整除为止
        int factors[] = {2, 3, 5};
        for (int factor : factors) {
            while (num % factor == 0) {
                num /= factor;
            }
        }
        
        // 如果最后剩下1,则是丑数;否则不是
        return num == 1;
    }
};

JavaScript 实现

/**
 * @param {number} num
 * @return {boolean}
 */
var isUgly = function(num) {
    // 非正数不是丑数
    if (num <= 0) {
        return false;
    }
    
    // 循环除以2、3、5,直到不能整除为止
    const factors = [2, 3, 5];
    for (const factor of factors) {
        while (num % factor === 0) {
            num /= factor;
        }
    }
    
    // 如果最后剩下1,则是丑数;否则不是
    return num === 1;
};

执行结果

C# 实现

  • 执行用时:24 ms
  • 内存消耗:15.1 MB

Python 实现

  • 执行用时:32 ms
  • 内存消耗:13.6 MB

C++ 实现

  • 执行用时:0 ms
  • 内存消耗:5.9 MB

JavaScript 实现

  • 执行用时:68 ms
  • 内存消耗:38.1 MB

性能对比

语言 执行用时 内存消耗 特点
C++ 0 ms 5.9 MB 性能最佳,内存占用最小
C# 24 ms 15.1 MB 性能中等,语法简洁清晰
Python 32 ms 13.6 MB 代码最简洁,易于理解
JavaScript 68 ms 38.1 MB 性能较差,内存占用最大

代码亮点

  1. 算法简洁明了,逻辑清晰,易于理解和实现
  2. 使用循环和数组优化代码结构,提高代码可读性
  3. 优先处理边界情况(非正数),提高代码健壮性
  4. 采用迭代方式而非递归,避免栈溢出风险

常见错误分析

  1. 忘记处理非正数的情况,导致对0或负数判断错误
  2. 未考虑1是丑数的特殊情况,直接返回false
  3. 在循环中使用不必要的条件判断,增加时间复杂度
  4. 使用递归实现,可能导致栈溢出问题

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
迭代除法 O(log n) O(1) 简单易懂,效率高 无明显缺点
递归除法 O(log n) O(log n) 代码简洁 存在栈溢出风险
质因数分解 O(sqrt(n)) O(1) 适用于更一般的因数分解问题 对于本题过于复杂

相关题目

  • LeetCode 264. 丑数 II - 中等
  • LeetCode 313. 超级丑数 - 中等
  • LeetCode 204. 计数质数 - 简单
  • LeetCode 1201. 丑数 III - 中等

系列导航

算法专题合集 - 查看完整合集

关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第263题。


互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 点个赞,让更多人看到这篇文章
  • 收藏文章,方便后续查阅复习
  • 关注作者,获取更多高质量算法题解
  • 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

一起进步:算法学习路上不孤单,欢迎一起交流学习!

你可能感兴趣的:(算法,leetcode,算法,职场和发展,c#,学习,python,c++)