Algorithm: 数学基础在编程的应用(LC题目)

263. Ugly Number

264. Ugly Number II

313. Super Ugly Number



263. Ugly Number

Write a program to check whether a given number is an ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7.

Note:

1 is typically treated as an ugly number. Input is within the 32-bit signed integer range.


思路:prime number是可以重复利用的。所以有可能是2*2*2. 如果是合格的数,利用每一步肯定是可以被2或者3或者5整除。为了效率,判断如果能先被2整除就先被2整除,再到3再到5. 到最后的结果是1的时候就肯定是合格数。为什么要2在前面?因为2可以通过移位实现运算。


public boolean isUgly(int num) {
    if(num==1) return true;
    if(num==0) return false;
	while(num%2==0) num=num>>1;
	while(num%3==0) num=num/3;
	while(num%5==0) num=num/5;
    return num==1;
}

264. Ugly Number II

Write a program to find the n-th ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.

Note that 1 is typically treated as an ugly number, and n does not exceed 1690.


注意观察,2、3、5是一个有魔性的序列。从1开始,1肯定是ugly number。缺少的4也是ugly number。所以从观察可知,ugly number * ugly number得到的也是ugly number。这也是之后的ugly numbers 的构成。我们知道丑陋序列可以拆分成3个子序列,分别是得到的ugly number去乘以2或者3或者5:
1x2, 2x2, 3x2, 4x2, 5x2, ...
1x3, 2x3, 3x3, 4x3, 5x3, ...
1x5, 2x5, 3x5, 4x5, 5x5, …

每次从三个列表中取出当前最小的那个加入序列,直到第n个为止。需要注意一点,每次用当前ugly[index]的值和候选的下一个比较,去除重复情况。如4*2和2*4是相同的。所以,index < n - 1是循环条件。


class Solution {
  public int nthUglyNumber(int n) {
    if (n == 1) {
      return 1;
    }

    int[] ugly = new int[n];

    ugly[0] = 1;

    int index = 0;
    int index2 = 0, index3 = 0, index5 = 0;

    while (index < n - 1) {
      int c2 = ugly[index2] * 2;
      int c3 = ugly[index3] * 3;
      int c5 = ugly[index5] * 5;

      int ans = Math.min(c2, Math.min(c3, c5));
      if (ans == c2) {
        ++index2;
      }
      else if (ans == c3) {
        ++index3;
      }
      else {
        ++index5;
      }

      // duplicate
      if (ugly[index] == ans) {
        continue;
      }

      ugly[++index] = ans;
    }

    return ugly[n - 1];
  }
}

313. Super Ugly Number


Write a program to find the nth super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4.
Note:
(1) 1 is a super ugly number for any given primes.
(2) The given numbers in primes are in ascending order.
(3) 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000.

(4) The nth super ugly number is guaranteed to fit in a 32-bit signed integer.


这道题和上一道不一样的地方在于不再局限在2 3和5上了。但是思路还是一样的,得到的ugly number去乘以给出的list的每个元素,然后选择最小的。由于这道题不再确定给出的list大小,要不停地与最小值相比,得到当前最小值以及对应的是第ith个index。别忘了初始化第一个ugly number和取ugly[indexes[i]]。


class Solution {
  public int nthSuperUglyNumber(int n, int[] primes) {
    if (n == 1) {
      return 1;
    }

    int[] ugly = new int[n];
    ugly[0] = 1;

    int index = 0;
    int numP = primes.length;
    int[] indexes = new int[numP];

    while (index < n - 1) {
      int min = Integer.MAX_VALUE;
      int minIndex = -1;
      for (int i = 0; i < numP; ++i) {
        int c = ugly[indexes[i]] * primes[i];
        if (c < min) {
          min = c;
          minIndex = i;
        }
      }

      ++indexes[minIndex];
      
      if (ugly[index] == min) {
        continue;
      }

      ugly[++index] = min;
    }

    return ugly[n - 1];
  }
}

如果想牺牲空间效率,提高时间效率(用一个数组去记住可以下一次用的乘结果):


class Solution {
  public int nthSuperUglyNumber(int n, int[] primes) {
        int[] ugly = new int[n];
        int[] idx = new int[primes.length];
        int[] val = new int[primes.length];
        Arrays.fill(val, 1);

        int next = 1;
        for (int i = 0; i < n; i++) {
            ugly[i] = next;
            
            next = Integer.MAX_VALUE;
            for (int j = 0; j < primes.length; j++) {
                //skip duplicate and avoid extra multiplication
                if (val[j] == ugly[i]) val[j] = ugly[idx[j]++] * primes[j];
                //find next ugly number
                next = Math.min(next, val[j]);
            }
        }

        return ugly[n - 1];
  }
}












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值