数论——因子组合【幸运数字】
记录一道关于数论的题目,题目本身不难,主要是学习一下思想~
文章目录
题目
到 X 星球旅行的游客都被发给一个整数,作为游客编号。X 星的国王有个怪癖,他只喜欢数字 3,5 和 7。
国王规定,游客的编号如果只含有因子:3,5,7 就可以获得一份奖品。
我们来看前 10 个幸运数字是:
3 5 7 9 15 21 25 27 35 45 因而第 11 个幸运数字是: 49
小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505 是第几个幸运数字。
常规思路or错误思路
首先来分析一下这道题:初次接触此类题的时候,我们通常会想到,先写一个方法——判断某个数的因子是否只含有3,5,7;于是乎,我们写了一个方法,这个方法也确实能够做出准确的判断,而在这个方法中,你或许还会用到一些集合,比如HashSet等…然后输入49,得出是第11个数。
int类型代码如下(Java):
import java.util.HashSet;
public class Main{
static HashSet<Integer> hashSet = new HashSet<>();
public static void main(String[] args) {
// long num = 59084709587505L;
int num = 49;
int count = 2;
while (3 * count < num) {
hashSet.add(3 * count);
count++;
}
count = 2;
while (5 * count < num) {
hashSet.add(5 * count);
count++;
}
count = 2;
while (7 * count < num) {
hashSet.add(7 * count);
count++;
}
count = 0;
for (int i = 2; i <= num; i++) {
if (judge(i))
count++;
}
System.out.println(count);
}
private static boolean judge(int num) {
boolean flag = num % 3 == 0 || num % 5 == 0 || num % 7 == 0;
for (int i = 2; i < num; i++) {
if (i != 3 && i != 5 && i != 7 && !hashSet.contains(i))
if (num % i == 0) {
flag = false;
break;
}
}
return flag;
}
}
BigInteger类型代码如下(Java):
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
public class demo04_BigInteger {
public static void main(String[] args) {
BigInteger num = new BigInteger("49");
int count = 0;
int i = 2;
BigInteger temp = new BigInteger(String.valueOf(i));
while (true) {
if (temp.compareTo(num) <= 0) {
if (judge(temp)) {
count++;
System.out.print(temp+" ");
}
temp = new BigInteger(String.valueOf(++i));
} else break;
}
System.out.println(count);
}
private static boolean judge2(BigInteger i) {
if (i.compareTo(BigInteger.valueOf(3)) == 0 || i.compareTo(BigInteger.valueOf(5)) == 0 || i.compareTo(BigInteger.valueOf(7)) == 0)
return true;
while (i.mod(BigInteger.valueOf(3)).compareTo(BigInteger.valueOf(0)) == 0)
i = i.divide(BigInteger.valueOf(3));
while (i.mod(BigInteger.valueOf(5)).compareTo(BigInteger.valueOf(0)) == 0)
i = i.divide(BigInteger.valueOf(5));
while (i.mod(BigInteger.valueOf(7)).compareTo(BigInteger.valueOf(0)) == 0)
i = i.divide(BigInteger.valueOf(7));
return i.compareTo(BigInteger.valueOf(1)) == 0;
}
private static boolean judge(BigInteger num) {
boolean flag = Integer.parseInt(num.mod(BigInteger.valueOf(3)).toString()) == 0 || Integer.parseInt(num.mod(BigInteger.valueOf(5)).toString()) == 0 || Integer.parseInt(num.mod(BigInteger.valueOf(7)).toString()) == 0;
BigInteger temp = new BigInteger(String.valueOf(2));
while (true) {
if (temp.compareTo(num) < 0) {
if (!judge2(temp))
if (Integer.parseInt(num.mod(temp).toString()) == 0) {
flag = false;
break;
}
temp = temp.add(BigInteger.valueOf(1));
} else
break;
}
return flag;
}
}
就在我以为大功告成的时候,将数字改为59084709587505(用long存储 ),发现hashset爆栈了或者是一直跑不出来——超时了!这题这么有难吗?怎么办呢?接着往下看!
正确思路(一)
这里说一下我后来想到的办法,可能还能做优化,但是目前已经是能用的了,如有更好的方法,请在评论区留言指点,不胜感激!
其实这类题和快速幂等数论思想一样,从已知条件入手,不考虑无关内容,从而优化循环,降低复杂度
解题思路:
由于因子只含有3,5,7,所以满足该条件的数一定是由 : 3的某次方 * 5的某次方 * 7的某次方 构成,而这样组成的数相对于全部的数,它们只占少部分,则可以直接暴力求解!
定义三个变量,三个变量都从0开始,因为一个数的0次方法等于1,相乘不会影响结果,但需要注意的是,要排除掉1这个数字,并且给定的那个数是需要取到的,所以我们列出公式:
for (int x = 0; Math.pow(3, x) <= num; x++)
for (int y = 0; Math.pow(5, y) <= num; y++)
for (int z = 0; Math.pow(7, z) <= num; z++)
这样就能遍历出全部的“幸运数字”,然后加以判断,只要“幸运数字”是<=number的,就追加个数。
代码如下(Java):
public class Main {
public static void main(String[] args) {
long num = 59084709587505L;
int count = 0;
for (int x = 0; Math.pow(3, x) <= num; x++)
for (int y = 0; Math.pow(5, y) <= num; y++)
for (int z = 0; Math.pow(7, z) <= num; z++)
if (Math.pow(3, x) * Math.pow(5, y) * Math.pow(7, z) <= num)
count++;
System.out.println(count - 1);
}
}
总结
当我们初次接触到这类问题时,总是以最直观的方法进行求解,却没有想到耗时问题;应该仔细分析已知条件,从已知的条件入手能够排除掉很多无关的数字,从而大大降低时间空间开销!
文章粗浅,希望对大家有帮助!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/159831.html