博主从2020.5.9下定决心,每天两道算法题,写博客是为了有动力坚持下去,望各位博友监督与鼓励 (ง •_•)ง
2020.5.17 学校开始上课了,博主忙于课设,从今天开始每天一道
算法题来自微信公众号:数据结构和算法
13195的所有质因数为5、7、13和29。600851最大的质因数是多少?
分析:通过不断的递归调用,判断number是否为质数。
public class Algorithe01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("600851的最大质因数:"+primeFactor(600851));
}
public static long primeFactor(long num) {
if(num==1)
return 1;
for(int i=2;i<num;i++) {
if(num%i==0) {
return primeFactor(num/i);
}
}
return num;
}
}
回文数就是从前往后和从后往前读都一样的数。由两个2位数相乘得到的最大回文乘积是 9009 = 91 × 99。找出由两个3位数相乘得到的最大回文乘积。
分析:通过循环一个个判断。
public class Algorithe02 {
public static void main(String[] args) {
System.out.println("两个3位数相乘得到的最大回文乘积是"+palindrome());
}
public static long palindrome() {
long num=0;
for(int j=999;j>100;j--) {
for(int i=999;i>100;i--) {
long result=i*j;
if(result>num &&palindrome(result))
num=result;
}
}
return num;
}
private static boolean palindrome(long result) {
int count=0;
long[] a=new long[10];
while(result!=0) {
a[count]=result%10;
count++;
result=result/10;
}
for(int i=0;i<=count/2;i++) {
if(a[i]!=a[count-i-1])
return false;
}
return true;
}
}
2520是最小的能够被1到10整除的数。最小的能够被1到20整除的正数是多少
分析:其实就是求1到20的最小公倍数,讲道理直接写个for,计算1到n的乘积即可,这样未免太简单。这道算法题应该要展现整除的过程,令product=n*(n-1)可以减少循环次数
public class Algorithe03 {
public static void main(String[] args) {
System.out.println("求最小的能被1到n整除的数,请输入n:");
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int product=n*(n-1);
int num = 0;
for(int j=1;j<=Integer.MAX_VALUE;j++) {
num=product*j;
int count=0;
for(int i=1;i<=n;i++) {
if(num%i!=0) {
break;
}
count++;
}
if(count==n) {
break;
}
}
System.out.println(num);
}
}
列出前6个素数,它们分别是2、3、5、7、11和13。我们可以看出,第6个素数是13。第10001个素数是多少?
分析:判断n是否为素数,根据定义直接判断从2到n-1是否存在约数即可
public class Algorithe04 {
public static void main(String[] args) {
System.out.println(prime(10001));
}
public static int prime(int num) {
int i=0;
for(int j=2;j<Integer.MAX_VALUE;j++) {
if(isPrime(j)) {
i++;
if(i==num)
return j;
}
}
return -1;
}
private static boolean isPrime(int j) {
if(j==2) {
return true;
}
for(int i= 2;i<=j-1;i++) {
if(j%i== 0)
return false;
}
return true;
}
}
在下面这个1000位正整数中,连续4个数字的最大乘积是
9 × 9 × 8 × 9 = 5832。
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
找出这个1000位正整数中乘积最大的连续13个数字。它们的乘积是多少?
分析:相邻的13个数相乘,直到循环完,然后返回最大的。注意的是如果乘积为0就跳出循环,charAt()取值,如0的ASCII码是48,减去48,就是对应的int值
public class Algorithe05 {
public static void main(String[] args) {
String num="73167176531330624919225119674426574742355349194934" +
"96983520312774506326239578318016984801869478851843" +
"85861560789112949495459501737958331952853208805511" +
"12540698747158523863050715693290963295227443043557" +
"66896648950445244523161731856403098711121722383113" +
"62229893423380308135336276614282806444486645238749" +
"30358907296290491560440772390713810515859307960866" +
"70172427121883998797908792274921901699720888093776" +
"65727333001053367881220235421809751254540594752243" +
"52584907711670556013604839586446706324415722155397" +
"53697817977846174064955149290862569321978468622482" +
"83972241375657056057490261407972968652414535100474" +
"82166370484403199890008895243450658541227588666881" +
"16427171479924442928230863465674813919123162824586" +
"17866458359124566529476545682848912883142607690042" +
"24219022671055626321111109370544217506941658960408" +
"07198403850962455444362981230987879927244284909188" +
"84580156166097919133875499200524063689912560717606" +
"05886116467109405077541002256983155200055935729725" +
"71636269561882670428252483600823257530420752963450";
int max=0;
for(int i=0;i<num.length()-13;i++) {
int result=1;
for(int j=i;j<i+13;j++) {
int digit=num.charAt(j)-48;
result*=digit;
if(result==0)
break;
}
if(result>max) {
max=result;
}
}
System.out.println("连续13个数字最大乘积是"+max);
}
}
毕达哥拉斯三元组是三个自然数a < b < c组成的集合,并满足a2 + b2 = c2。例如,32 + 42 = 9 + 16 = 25 = 52。有且只有一个毕达哥拉斯三元组满足 a + b + c = 1000。求这个三元组的乘积abc。
分析:满足毕达哥拉斯定理,可以把它想象成为一个直角三角形的三条边,a是小的直角边,b是大的直角边,c是斜边。b如果等于a,那么c就是无理数了,相加不可能等于1000,所以b不能等于a。下面的循环要满足直角三角形的几个条件,1:直角边要小于斜边,2:两边之和大于第三边,3:两边之差小于第三边。如果查找到就直接返回。
public class Algorithe06 {
public static void main(String[] args) {
System.out.println(pythagorean(1000));
}
public static int pythagorean(int sum) {
for(int a=1;a<sum/3;a++) {
for(int b=a+1;b<sum/2;b++) {
int c=sum-a-b;
if(b<c &&(a*a+b*b==c*c)) {
return a*b*c;
}
}
}
return -1;
}
}
所有小于10的素数的和是2 + 3 + 5 + 7 = 17。求所有小于两百万的素数的和。
分析:通过循环遍历,能提高算法效率的点有,素数除了2以外都是奇数。判断是否为素数时,可以从2到i的平方根之间循环,至于为什么这样简化,可以拿计算器试一试就明白了,这样极大缩短了运行时间
public class Algorithe07 {
public static void main(String[] args) {
long sum=2;
for(int i=3;i<2000000;i+=2) {
if(isPrime(i)) {
sum+=i;
}
}
System.out.println(sum);
}
private static boolean isPrime(int i) {
for(int j=2;j<=Math.sqrt(i);j++) {
if(i%j==0)
return false;
}
return true;
}
}
三角形数数列是通过逐个加上自然数来生成的。例如,第7个三角形数是 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28。三角形数数列的前十项分别是:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, …
让我们列举出前七个三角形数的所有约数:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
我们可以看出,28是第一个拥有超过5个约数的三角形数。
第一个拥有超过500个约数的三角形数是多少?
分析:列举三角形数,判断他的约数是否大于500,如果大于直接返回。注意下面的判断是否是平方数,如果是要减1,比如9的约数是1,3,9不是1,3,3,9。
public class Algorithe08 {
public static void main(String[] args) {
System.out.println(triangleNumber(500));
}
public static int triangleNumber(int number) {
for(int i=1;i<Integer.MAX_VALUE;i++) {
int count=0;
int result=(1+i)*i/2;
int prime=(int) Math.sqrt(result);
for(int j=1;j<=prime;j++) {
if(result%j==0)
count++;
}
count= (prime*prime==result?2*count-1:2*count);
if(count>number)
return result;
}
return -1;
}
}
英国的货币单位包括英镑£和便士p,在流通中的硬币一共有八种:
1p, 2p, 5p, 10p, 20p, 50p, £1 (100p), £2 (200p)
以下是组成£2的其中一种可行方式:
1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
不限定使用的硬币数目,组成£2有多少种不同的方式?
分析:通过递归计算,只有相减等于0的时候sum才会加1,否则通过循环递归计算sum的值。
public class Algorithe09 {
public static void main(String[] args) {
System.out.println(coinSum(200, 0));
}
public static int coinSum(int totalMoney,int index) {
int money[]= {1,2,5,10,20,50,100,200};
int sum=0;
for(int i=index;i<money.length;i++) {
if(totalMoney-money[i]==0) {
sum++;
break;
}
if(totalMoney-money[i]>0)
sum+=coinSum(totalMoney-money[i],i);
}
return sum;
}
}
在正整数集上定义如下的迭代序列:
n → n/2 (若n为偶数)
n → 3n + 1 (若n为奇数)
从13开始应用上述规则,我们可以生成如下的序列:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
可以看出这个序列(从13开始到1结束)共有10项。尽管还没有被证明,但我们普遍认为,从任何数开始最终都能迭代至1(“考拉兹猜想”)。
从小于一百万的哪个数开始,能够生成最长的序列呢?
注: 序列开始生成后允许其中的项超过一百万。
分析:返回最长的序列即可。
public class Algorithe10 {
public static void main(String[] args) {
System.out.println(longestCollatz(1000000));
}
public static int longestCollatz(int num) {
int max=0;
int j=0;
for(int i=2;i<num;i++) {
int length=collatzLength(i);
if(max<length) {
max=length;
j=i;
}
}
return j;
}
private static int collatzLength(int num) {
int i=1;
while(num!=1) {
if(num%2==0)
num=num>>>1;
else
num=num*3+1;
i++;
}
return i;
}
}
215 = 32768,而32768的各位数字之和是 3 + 2 + 7 + 6 + 8 = 26。
21000的各位数字之和是多少(2的1000次方)?
分析:我们知道2的64次方就已经很大了,那么2的1000次方就更大了,常规的算法是不行的,换个思路。2的1000次方,相当于把1往左移动1000位,然后转化为BIgInteger在计算各位数字之和。digit就是表示每个位置上的数字的字符串,遍历相加即可。
public class Algorithe11 {
public static void main(String[] args) {
System.out.println(powerDigit(1000));
}
public static int powerDigit(int max) {
int sum=0;
StringBuilder sb=new StringBuilder(max+1);
sb.append(1);
for(int j=0;j<max;j++) {
sb.append(0);
}
BigInteger num=new BigInteger(sb.toString(),2);
String digit=num.toString(10);
for(int i=0;i<digit.length();i++) {
sum+=digit.charAt(i)-48;
}
return sum;
}
}
如果把1到5写成英文单词,分别是:one, two, three, four, five,这些单词一共用了3 + 3 + 5 + 4 + 4 = 19个字母。
如果把1到1000都写成英文单词,一共要用多少个字母?
注意: 不要算上空格和连字符。例如,342(three hundred and forty-two)包含23个字母,而115(one hundred and fifteen)包含20个字母。单词“and”的使用方式遵循英式英语的规则。
分析:主要就是找规律,然后总结,注意1000的时候不要忘了。
public class Algorithe12 {
public static void main(String[] args) {
System.out.println(NumberLetterCounts());
}
private static int NumberLetterCounts() {
int sum=0;
for(int i=1;i<21;i++) {
sum+=LetterCountsOne(i);
}
for(int i=21;i<100;i++) {
sum+=LetterCountsTwo(i/10)+LetterCountsTwo(i%10);
}
for(int i=100;i<1000;i++) {
if(i%100<=20)
sum+=LetterCountsOne(i/100) + (i%100==0?7:10)+LetterCountsOne(i%100);
else
sum+=LetterCountsOne(i/100) + (i%100==0?7:10)+LetterCountsTwo(i%100/10)+LetterCountsOne(i%10);
}
//one thousand
sum+=11;
return sum;
}
private static int LetterCountsTwo(int num) {
/**
* one two three four five six seven eight nine ten
* eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty
* twenty-one twenty-two twenty-three twenty-four twenty-five twenty-six
* twenty-seven twenty-eight twenty-nine
* thirty forty fifty sixty seventy eighty ninety
* one hundred
*/
if(num==1)
return 3;
if(num==2)
return 3;
if(num==3)
return 5;
if(num==4)
return 4;
if(num==5)
return 4;
if(num==6)
return 3;
if(num==7)
return 5;
if(num==8)
return 5;
if(num==9)
return 4;
if(num==10)
return 3;
if(num==11)
return 6;
if(num==12)
return 6;
if(num==13)
return 8;
if(num==14)
return 8;
if(num==15)
return 7;
if(num==16)
return 7;
if(num==17)
return 9;
if(num==18)
return 8;
if(num==19)
return 8;
if(num==20)
return 6;
return 0;
}
private static int LetterCountsOne(int num) {
if(num==2)
return 6;
if(num==3)
return 6;
if(num==4)
return 5;
if(num==5)
return 5;
if(num==6)
return 5;
if(num==7)
return 7;
if(num==8)
return 6;
if(num==9)
return 6;
return 0;
}
}
下列信息是已知的,当然你也不妨自己再验证一下。
1900年1月1日是星期一。
三十天在九月中,
四六十一也相同。
剩下都是三十一,
除去二月不统一。
二十八天平常年,
多加一天在闰年。
闰年指的是能够被4整除却不能被100整除的年份,或者能够被400整除的年份。
在二十世纪(1901年1月1日到2000年12月31日)中,有多少个月的1号是星期天?
分析:这个虽然简单但有点麻烦,自己慢慢看,就不在介绍。
public class Algorithe13 {
public static void main(String[] args) {
System.out.println(countSundays());
}
public static int countSundays() {
//1900年1月1日是星期一,那么7号就是星期日
int sum=365-6;
int count=0;
for(int i=1901;i<=2000;i++) {
for(int j=1;j<=12;j++) {
sum+=daysOfYear(i,j);
if(sum%7==0)
count++;
}
sum+=30;//最后一个月只加到1号,年循环完要把剩余的30天加上
}
return count;
}
private static int daysOfYear(int year, int month) {
if(month==1)
return 1;
return days(year,month-1)+daysOfYear(year,month-1);
}
private static int days(int year, int month) {
if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12)
return 31;
if(month==4 || month==6 || month==9 || month==11)
return 30;
if(month==2 &&(year%4!=0 || year%400!=0))
return 28;
return 29;
}
}
n! 的意思是 n × (n − 1) × … × 3 × 2 × 1
例如,10! = 10 × 9 × … × 3 × 2 × 1 = 3628800,所以10!的各位数字和是 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27。
求出100!的各位数字和。
分析:int和long都不能表示,所以要使用BinInteger,也很简单就不在介绍。
public class Algorithe14 {
public static void main(String[] args) {
System.out.println(factorialDigitSum(100));
}
public static int factorialDigitSum(int num) {
int i=1;
BigInteger bigInteger=new BigInteger("1");
while(i<=num) {
bigInteger=bigInteger.multiply(new BigInteger(i+""));
i++;
}
String numString=bigInteger.toString();
int sum=0;
for(int j=0;j<numString.length();j++) {
sum+=Character.digit(numString.charAt(j), 10);
}
return sum;
}
}
记d(n)为n的所有真因数(小于n且整除n的正整数)之和。
如果d(a) = b且d(b) = a,且a ≠ b,那么a和b构成一个亲和数对,a和b被称为亲和数。
例如,220的真因数包括1、2、4、5、10、11、20、22、44、55和100,因此d(220) = 284;而284的真因数包括1、2、4、71和142,因此d(284) = 220。
求所有小于10000的亲和数的和。
分析:先判断是否是亲和数,然后相加,但要防止加两次。
public class Algorithe15 {
public static void main(String[] args) {
System.out.println(amicableNumberSum(10000));
}
public static int amicableNumberSum(int num) {
int sum=0;
for(int i=1;i<num;i++) {
int amicable=amicableNumbers(i);
if(amicable>i) {
sum+=i;
sum+=amicable;
}
}
return sum;
}
private static int amicableNumbers(int num) {
int sum1=0;
for(int i=1;i<num;i++) {
if(num%i==0)
sum1+=i;
}
int sum2=sum1;
sum1=0;
for(int i=1;i<sum2;i++) {
if(sum2%i==0)
sum1+=i;
}
if(num==sum1)
return sum2;
return -1;
}
}
将192分别与1、2、3相乘:得到192,384,576
连接这些乘积,我们得到一个1至9全数字的数192384576。我们称192384576为192和(1,2,3)的连接乘积。同样地,将9分别与1、2、3、4、5相乘,得到1至9全数字的数918273645,即是9和(1,2,3,4,5)的连接乘积。对于n > 1,所有某个整数和(1,2, … ,n)的连接乘积所构成的数中,最大的1至9全数字的数是多少?
分析:判断是否是全数字,然后返回最大的。
public class Algorithe16 {
public static void main(String[] args) {
System.out.println(pandigitalMultiples());
}
public static int pandigitalMultiples() {
int max=0; //因为n>1,所以i<10000
for(int i=1;i<10000;i++) {
String product="";
for(int j=1;j<10;j++) {
product=product+(i*j);
if(product.length()>9)
break;
if(repetition(product))
continue;
if(product.length()==9) {
if(max<Integer.parseInt(product)) {
max=Integer.parseInt(product);
}
}
}
}
return max;
}
private static boolean repetition(String i) {
List<String> list=new ArrayList<String>();
for(int j=0;j<i.length();j++) {
if(i.charAt(j)=='0' || list.contains(i.charAt(j)+""))
return true;
list.add(i.charAt(j)+"");
}
return false;
}
}
排列指的是将一组物体进行有顺序的放置。例如,3124是数字1、2、3、4的一个排列。如果把所有排列按照数字大小或字母先后进行排序,我们称之为字典序排列。0、1、2的字典序排列是:
012 021 102 120 201 210
数字0、1、2、3、4、5、6、7、8、9的字典序排列中第一百万位的排列是什么?
分析:这里用到阶乘的概念,比如n可以组合成n*(n-1)*(n-2)**21中方式。只需要计算(n-1)的阶乘即可,就可以知道除了n有多少种形式,然后把i放到数的最前面,i是list中第几个元素,list的初始元素相当于已经排序好的,然后在通过不断的递归即可求出。
public class Algorithe17 {
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
for(int i=0;i<10;i++) {
list.add(i);
}
System.out.println(lexicographicPermutations(10, 999999, list));
}
public static String lexicographicPermutations(int num,int max,List<Integer> list) {
if(num>0) {
int prexLeicographicNum=1;
if(num!=1)
prexLeicographicNum=recursion(num-1);
int quotients=max/prexLeicographicNum;
int mod=max%prexLeicographicNum;
int i=list.remove(quotients);
return i+""+lexicographicPermutations(num-1, mod, list);
}
return "";
}
private static int recursion(int num) {
if(num==1)
return 1;
return num*recursion(num-1);
}
}
斐波那契数列是按如下递归关系定义的数列:
F1 = 1 F2 = 1
Fn = Fn−1 + Fn−2
因此斐波那契数列的前12项分别是:
F1 = 1
F2 = 1
F3 = 2
F4 = 3
F5 = 5
F6 = 8
F7 = 13
F8 = 21
F9 = 34
F10 = 55
F11 = 89
F12 = 144
第一个有三位数字的项是第12项F12。
在斐波那契数列中,第一个有1000位数字的是第几项?
分析:用BigInteger计算即可。
public class Algorithe18 {
public static void main(String[] args) {
System.out.println(digitFibonacciNumber());
}
public static String digitFibonacciNumber() {
BigInteger first=new BigInteger("1");
BigInteger second=new BigInteger("1");
for(int i=3;i<Integer.MAX_VALUE;i++) {
BigInteger corren=first.add(second);
if(corren.toString().length()>=1000)
return i+"";
first=second;
second=corren;
}
return "";
}
}
单位分数指分子为1的分数。分母为2至10的单位分数的十进制表示如下所示:
1/2= 0.5
1/3= 0.(3)
1/4= 0.25
1/5= 0.2
1/6= 0.1(6)
1/7= 0.(142857)
1/8= 0.125
1/9= 0.(1)
1/10= 0.1
这里0.1(6)表示0.166666…,括号内表示有一位循环节。可以看出,1/7有六位循环节。
找出正整数d < 1000,其倒数的十进制表示小数部分有最长的循环节。
分析:只需要求出循环节的长度即可,任何分数都可以写成有限小数或者无限循环小数,如果是有限的好说,如果是无限的,通过不断的求余运算,计算出mod,然后直到找到第一个出现重复的即可。
public class Algorithe19 {
public static void main(String[] args) {
System.out.println(reciprocalCycles());
}
private static int reciprocalCycles() {
int max=0;
int target=0;
for(int i=1;i<1000;i++) {
int circulationCount=circulation(1,i);
if(circulationCount>max) {
target=i;
max=circulationCount;
}
}
return target;
}
private static int circulation(int dividend, int divisor) {
List quoientList=new ArrayList<>();
List moList=new ArrayList<>();
int index=-1;
while(true) {
quoientList.add(dividend/divisor);
int mod=dividend%divisor;
if(mod==0)
break;
index=moList.indexOf(mod);
if(index>=0)
break;
else
moList.add(mod);
dividend=mod*10;
}
if(index>=0)
return quoientList.size()-(index+1);
else
return 0;
}
}