【数学】C035_阶乘后的零(暴力 | 优化 | 数学思想)

一、题目描述

Given an integer n, return the number of trailing zeroes in n!.

Example 1:
Input: 3
Output: 0
Explanation: 3! = 6, no trailing zero.

Example 2:
Input: 5
Output: 1
Explanation: 5! = 120, one trailing zero.

Note: Your solution should be in logarithmic(对数) time complexity.

二、题解

(1) 暴力(超时,使用int存储会溢出)

/**
 * 暴力破解(超时):ret不用long会溢出。
 * @param n
 * @return
 */
public int trailingZeroes1(int n) {
  int count=0;
  long ret=0;
  for (int i = n; i >= 1; --i) {
    ret *= n;
    n--;
  }
  while(n != 0) {
    if(n % 10 == 0) count++;
    n/=10;
  }
  return count;
}

复杂度分析

  • 时间复杂度: O ( n ) O(n)
  • 空间复杂度: O ( 1 ) O(1)

(2) 暴力优化(数学思想 | 超时)

计算 N 的阶乘 N ! = 1 2 . . . N N!=1*2*...*N 有多少个后缀0,即计算 N ! N! 里有多少个 10 10 ,也就是计算 N ! N! 里有多少个 2 2 5 5

  • 数学原理:分解质因数,最后结果即 2 的个数和 5 的个数取较小值。
  • 因此,得到下面时间复杂度为 O ( N l o g 2 N ) O(Nlog_2N) 的暴力求解的算法。
  • 这种求法不会阶乘时的溢出。
/**
 * @date: 1/17/2020 5:09 PM
 * @Execution info:
 *  ·执行用时  ms 击败了 % 的java用户
 *  ·内存消耗 MB 击败了 % 的java用户
 * @Asymptotic Time Complexity:O()
 */
public int trailingZeroes2(int n) {
  int cnt2=0;
  int cnt5=0;
  for (int i = 2; i <= n; i++) {
    int t=i;
    while(t%2 == 0) {
      cnt2++;
      t>>=1;
    }
    while(t%5==0) {
      cnt5++;
      t/=5;
    }
  }
  return cnt2 > cnt5 ? cnt5 : cnt2;
}

复杂度分析

  • 时间复杂度: O ( N l o g 2 N ) O(Nlog_2N)
  • 空间复杂度: O ( 1 ) O(1)

(3) 纯数学求解

暴力的解法对于特殊的数学问题一般会超时,但却不是一无是处,可用于前期查找规律,为之后提供数据和思路。于是,我们就有了下面这些思想。

  • 0 0 的来源 2 5 2 * 5 所以一对 2 和 5 即可产生一个 0,所以 0 的个数即为 m i n ( 5 2 ) min(阶乘中含有因子 5 的元素的个数和 2 的个数)
  • 又因 2 的倍数的数一定比是 5 的倍数的数多,所以 2 的个数一定 >=5 的个数,所以只需要统计 5 的个数
  • 每隔 5 个数就会有一个含有因子5 的元素,但是这些元素中每隔 5 个会多一个因子5(即, 5 + 5 + 5 + 5 + 5 = 5 5 5+5+5+5+5 = 5*5 ),如 25 = 5 5 25 = 5 * 5 ,这些因子中 25 = 5 5 5 25 = 5 * 5 * 5 就又多一个因子5,
  • 其实就是求 n / 5 + n / 25 + n / 125 + . . . n/5 + n/25 + n/125 + ... 的和。迭代,先求 n / 5 n/5 ,完事再其基础上再除以 5 来求 n / 25 n / 25 等等
/**
 * @date: 1/17/2020 5:28 PM
 * @Execution info:
 *  ·执行用时 1 ms 击败了 100% 的java用户
 *  ·内存消耗 33MB 击败了 89.8% 的java用户
 * @Asymptotic Time Complexity:O()
 */
public int trailingZeroes3(int n) {
  int count=0;
  while(n >= 5) {
    count += n/5;
    n/=5;
  }
  return count;
}

复杂度分析

时间复杂度: O ( l o g 5 ( n ) ) O(log_5(n))
空间复杂度: O ( 1 ) O(1)

发布了300 篇原创文章 · 获赞 48 · 访问量 8055

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104025023