描述:「如果我们将小于 10 的所有是 3 或 5 倍数的自然数列出来,我们得到 3、5、6 和 9 ,它们的和是 23 。与之类似,计算 1000 以下所有是 3 或 5 的倍数的自然数的和。」
package Euler;
//If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9.
//The sum of these multiples is 23.
//Find the sum of all the multiples of 3 or 5 below 1000.
public class Prob_1 {
public static void main(String[] args) {
final int TOP = 1000;
int sum = 0;
for (int i = 1; i < TOP; i++) {
if (i % 3 == 0 || i % 5 == 0) {
sum += i;
}
}
//答案:233168
System.out.println(sum);
}
}
描述:「斐波那契序列中的数都是由前两项加总得出,本题假设第一与第二项为1、2,则前十项分别为:1,2,3,5,8,13,21,34,55,89。考虑不超过四百万的斐波那契数,计算其中偶数斐波那契数的和。」
|虽然下面这段代码运行无误并可以得到正确结果“4613732”
|但是它是存在逻辑漏洞的,细心的小伙伴你能看出来嘛
package Euler;
/**
* Each new term in the Fibonacci sequence is generated
* by adding the previous two terms.
*
* By starting with 1 and 2, the first 10 terms will be:
* 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
*
* By considering the terms in the Fibonacci sequence
* whose values do not exceed four million, find the sum of the even-valued terms.
*/
public class Prob_2 {
public static void main(String[] args) {
final int MAX = 4000000;
int x = 1;
int y = 2;
int sum = 0 + y;
while (x < MAX && y < MAX) {
x += y;
if (x % 2 == 0) {
sum += x;
}
y += x;
if (y % 2 == 0) {
sum += y;
}
}
//答案:4613732
System.out.println(sum);
}
}
此处的
while (x < MAX && y < MAX)
条件限制表示斐波那契数列的奇数项&偶数项必须全部小于MAX。假设有效(即为偶数)的 x时,刚好 y>MAX ,那么这里的 x 将不会被代入 sum 求和:这无疑是一个隐患。意图设计一个 robust 的程序,请千万别忘了测试极端和意外情况。
相信机智的你可以不假思索地给出改进方案,此处便不再赘述,可参考 LOOP in C
描述:「13195的质因数分别为5,7,13与29。600851475143 最大的质因数是多少?」
package Euler;
//The prime factors of 13195 are 5, 7, 13 and 29.
//What is the largest prime factor of the number 600851475143 ?
public class Prob_3 {
public static boolean isPrime(int n) {
//保证健壮性,特殊条件判断:0、1均不是质数
if (n <= 1) {
return false;
}
//为了避免重复计算及浮点误差,引入top,稍后解释
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static void main(String[] args) {
//倘若无修饰符L,IDEA提示"Integer Too Large",即600851475143默认被认作整型
long x = 600851475143L;
//long 强制类型转换,从其平方根开始往下查找,保证 "最大"
int i = (int) Math.floor(Math.sqrt(600851475143.0) + 0.5);
while (true) {
//如果i是x的因子,且该因子为素数,则退出循环
//短路求值,不建议调换 相与的两个条件的顺序
if (x % i == 0 && isPrime(i)) {
//答案:6857
System.out.println(i);
break;
}
//否则,i自减1,进入下一次循环判断
i--;
}
}
}
或许你会心存疑问,为什么isPrime函数中,没有使用更普遍更常见的
for (int i = 2; i * i <= n; i++)
呢?“千万别忘了特殊情况的测试”。最极端的情况是,假如需要验证,231-1(2147483647)是一个素数,使用这条语句实现的 isPrime 会发生什么呢?虽然 2147483647 没有超过
int n
的最大值,然而,i * i
就明显存在溢出的风险;甚至特殊情况下可能出现死循环。
例如:
46340 * 46340 = 2147395600 < n
46341 * 46341 = -2147479015 < n
…i++;
2147483646 * 2147483646 = 4 < n
2147483647 * 2147483647 = 1 < n
2147483648 * 21474836478 = 0 < n
…i++;当然你也可以将
int
换成long
一步搞定,不过这样可能使程序运行较为迟缓。
下面给出另一种思路(模拟短除法)以飨读者
package Euler;
public class Prob_3s {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
long n = 600851475143L;
long factor = 2;
//模拟短除法
while (true) {
//从最小且唯一的偶质数开始
//如果可以整除,除到不能除为止,缩小n的范围
while (n % factor == 0) {
n /= factor;
}
//为下一次循环准备条件
//从此之后,所有的质数必定为奇数
//所以只需验证 2+1=3,3+2=5,5+2=7 是否为其质因数……
if (factor == 2) {
factor += 1;
} else {
factor += 2;
}
//循环(退出)条件
//返璞归真,”类似法1判断n为质数“只需要遍历到sqrt(n)
if (factor * factor >= n) {
break;
}
}
System.out.println(n);
//程序运行时间:1ms
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
}
}
long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
这里使用了一点点小 tricks 粗略估计程序运行耗时情况,结果“模拟短除法”以1ms的优异成绩一举K.O掉了“无脑暴力法”10ms。
描述:「回文数即从正反两边读都是一样的数,两个二位数的乘积中最大的回文数为9009=91*99,寻找两个三位数乘积中最大的回文数。」
package Euler;
//A palindromic number reads the same both ways.
//The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
//Find the largest palindrome made from the product of two 3-digit numbers.
public class Prob_4 {
public static boolean isPalindrome(int x) {
Integer y = x;
StringBuilder str = new StringBuilder(y.toString());
StringBuilder strInverse = new StringBuilder(str).reverse();
//StringBuilder没有重写Object类equals方法,所以需要to String()
if (strInverse.toString().equals(str.toString())) {
return true;
}
return false;
}
public static void main(String[] args) {
final int hi = 999;
final int lo = 100;
int max = -1;
//依题意,由大至小遍历-两个三位数
for (int i = hi; i >= lo; i--) {
for (int j = hi; j >= lo; j--) {
int x = i * j;
if (isPalindrome(x) && x > max) {
max = x;
}
}
}
//答案:906609
System.out.println(max);
}
}
相对于偏向底层的C语言,C++更受算法竞赛者的青睐,很大程度上,就是因为其STL提供了许多算法和容器。而Java,作为一个“纯净版的C++”,提供了一个庞大的库;标准库中有几千个类,单是String一个类中就包含了50多个API,比如说这里的equals 。
“运用脑髓,放出眼光,自己来拿。”——《拿来主义》鲁迅
比如说这里的“回文”,我们不必像C语言入门“从零开始”将数字转换成字符数组,也不必“一步一步”循环实现字符数组反转,用现成的方法写程序,用旧零件组装新事物;“拿来吧你”即可,这方才符合“面向对象”的思想。
当然,这里的 isPalidrome 还可以简化为:
String s = String.valueOf(x);
return s.equals(new StringBuilder(s).reverse().toString());
描述:「2520是可以被从一到十所有自然数整除的最小的数,即为从一到十的自然数的最小公倍数,求从一到二十所有自然数的最小公倍数。」
package Euler;
//2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
//What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
public class Prob_5 {
public static void main(String[] args) {
//从小到大循环遍历,保证“最小”
for (int i = 2520; ; i++) {
boolean flag = true;
//循环1~20,验证该数是否符合可以整除其中所有自然数
for (int j = 1; j <= 20; j++) {
if (i % j != 0) {
flag = false;
break;
}
}
//如果布尔标记变量flag仍为真,则将符合条件的打印
if (flag) {
//答案:232792560
System.out.println(i);
break;
}
}
}
}
|秉持着一贯“暴力求解”的思路,上述代码只是让计算机作为一个无情的验证机器。
|那是否可以"用点子智慧"直接计算出结果呢?基于小学二年级习得的数学知识,即“两个数的最大公因数乘以其最小公倍数等于这两个数的乘积”,下面先给出一段"有问题"的代码,抛砖引玉。
package Euler;
public class Prob_5s {
//【最大公约数】Greatest Common Divisor
public static int gcd(int m, int n) {
return (m % n == 0) ? n : gcd(n, m % n);
}
//【最小公倍数】Least Common Multiple
public static int lcm(int m,int n){
return m*n/gcd(m,n);
}
public static void main(String[] args) {
int lcmForAll=1;
for(int i = 1; i <=20;i++){
lcmForAll = lcm(lcmForAll,i);
//结果有误
System.out.println(lcmForAll);
}
}
}
需对几处进行说明:
第一,求解最大公约数时,利用了“递归”的思想(DFS递归搜索树),即自己调用自己,形式上颇像高中数学的“数学归纳法”。这里采用著名且有效的“辗转相除法”,其运算步骤,例如:1122 mod 695 = 417
695 mod 417 = 278
417 mod 278 = 139
278 mod 139 = 0
达到终止条件GCD = 139
那逻辑上说,为什么该方法可以找到最大公约数呢?图示如下。第二,细心的同学或许注意到,
lcm
函数中m * n
有溢出的可能,我们输出一下中间结果,果真如此:
1 2 6 12 60 60 420 840 2520 2520 27720 27720 360360 360360 360360 720720 12252240 12252240 232792560 18044195(异常数值)。不过,这里我们先不急着把 int 修改为 long。
第三,“拿来主义”。有没有现成的类与方法可供使用呢?
答案是,还真有。Java提供了一个无比庞大无比强大的类库,其中包含了特大整型“BigInteger”,支持特大数字的高精度计算。大一C语言的学习过程中,我们知道要实现特大数字的四则运算,需要用倒序对齐字符数组模拟人工计算过程。
Java中,BigInteger,不仅支持add
、subtract
、multiply
、divide
、mod
、divideAndRemainder
等常规运算,同样支持gcd
,甚至,还有用到“米勒-拉宾素性检验”、“卢卡斯-莱默检验法”的素数可能性检验isProbablePrime
(虽然一般派不上用场)。要知道,C++选手再垂涎欲滴也没有这样的福利。相信我,BigInteger
只有零次和无数次,你终将爱上它的。
下面给出blingbling的改进代码
package Euler;
import java.math.BigInteger;
public class Prob_5x {
public static BigInteger lcm(BigInteger a,BigInteger b){
return a.multiply(b).divide(a.gcd(b));
}
public static void main(String[] args) {
BigInteger lcmForAll = BigInteger.ONE;
for (int i = 1; i <=20; i++) {
lcmForAll=lcm(lcmForAll,BigInteger.valueOf(i));
}
//答案:232792560
System.out.println(lcmForAll.toString());
}
}
描述:「前十个自然数的平方的和为: 12+22+32+⋯+102 =385;而前十个自然数和的平方为:(1+2+3+⋯+10)2=552=3025。两者的差为3025−385=2640,求前一百个自然数的和的平方与平方的和之间的差值。」
package Euler;
//The sum of the squares of the first ten natural numbers is 385
//The square of the sum of the first ten natural numbers is 3025
//Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025−385=2640
//Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
public class Prob_6 {
public static void main(String[] args) {
//平方的和
long sum1 = 0;
for (int i = 1; i <= 100; i++) {
sum1 += i * i;
}
//和的平方
long sum2 = 0;
for (int i = 1; i <= 100; i++) {
sum2 += i;
}
sum2 *= sum2;
//答案:25164150
System.out.println(Math.abs(sum1 - sum2));
}
}
描述:「列出前六个质数,我们可以发现第六个质数为 13,那么第 10001 个质数是多少?」
package Euler;
//By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
//What is the 10 001st prime number?
public class Prob_7 {
public static boolean isPrime(int n) {
if (n < 2) {
return false;
}
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static void main(String[] args) {
for (int i = 1, index = 0; ; i++) {
if (isPrime(i) && ++index == 10001) {
//答案: 104743
System.out.println("The " + index + "th PrimeNumber is " + i);
break;
}
}
}
}
描述:「在该 1000 位数(见代码)中,连续四个数的最大乘积为 9∗9∗8∗9=5832;寻找连续十三数的最大乘积,这个乘积是多少?
package Euler;
/**
* The four adjacent digits in the 1000-digit number
* that have the greatest product
* are 9 × 9 × 8 × 9 = 5832.
*
* Find the thirteen adjacent digits in the 1000-digit number
* that have the greatest product.
* What is the value of this product?
*/
public class Prob_8 {
static final String str =
"73167176531330624919225119674426574742355349194934" +
"96983520312774506326239578318016984801869478851843" +
"85861560789112949495459501737958331952853208805511" +
"12540698747158523863050715693290963295227443043557" +
"66896648950445244523161731856403098711121722383113" +
"62229893423380308135336276614282806444486645238749" +
"30358907296290491560440772390713810515859307960866" +
"70172427121883998797908792274921901699720888093776" +
"65727333001053367881220235421809751254540594752243" +
"52584907711670556013604839586446706324415722155397" +
"53697817977846174064955149290862569321978468622482" +
"83972241375657056057490261407972968652414535100474" +
"82166370484403199890008895243450658541227588666881" +
"16427171479924442928230863465674813919123162824586" +
"17866458359124566529476545682848912883142607690042" +
"24219022671055626321111109370544217506941658960408" +
"07198403850962455444362981230987879927244284909188" +
"84580156166097919133875499200524063689912560717606" +
"05886116467109405077541002256983155200055935729725" +
"71636269561882670428252483600823257530420752963450";
//递归,求str字符串中,从on起,邻接span个数的乘积
public static long adjProd(String str, int on, int span) {
//字符型是特殊的整型,如'1'=49,故下面减去基准值'0'
return (span == 1) ? str.charAt(on) - '0' : adjProd(str, on, span - 1) * (str.charAt(on + span - 1) - '0');
}
public static void main(String[] args) {
final int SPAN = 13;
long max = 0;
for (int i = 0; i < str.length() - SPAN; i++) {
long prod = adjProd(str, i, SPAN);
max = Math.max(max, prod);
}
//答案:23514624000
System.out.println("The greatest value of adjacent product is " + max);
}
}
描述:「毕达哥拉斯三元数是指一类三个自然数的集合,其中 a2 +b2 =c2 ,例如 32 +42 =52 。仅存在一组毕达哥拉斯三元数使得 a+b+c=1000 ,求 abc 。」
package Euler;
//A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,
//For example, 32 + 42 = 9 + 16 = 25 = 52.
//There exists exactly one Pythagorean triplet for which a + b + c = 1000.
//Find the product abc.
public class Prob_9 {
public static void main(String[] args) {
final int SUM = 1000;
final double EPS = 1e-9;//高等数学,设置无穷小量,以判断浮点数“相等”
//由于存在约束条件,故无需三重循环
for (int i = 1; i < SUM / 3; i++) {
for (int j = i; j < SUM; j++) {
int k = SUM - i - j;
//if (i * i + j * j = k * k)未尝不可,这里提供一种"奇奇怪怪"的判断方法
if (Math.abs(Math.hypot(i, j) - k) <= EPS) {
//答案: 31875000
System.out.println(i + "," + j + "," + k + " ~ " + i * j * k);
}
}
}
}
}
描述:「10以下的质数的和为 2+3+5+7=17 ,求所有两百万以下的质数的和。」
package Euler;
//The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
//Find the sum of all the primes below two million.
public class Prob_10 {
public static boolean isPrime(int x) {
if (x < 2) {
return false;
}
int top = (int) Math.floor(Math.sqrt(x) + 0.5);
for (int i = 2; i <= top; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
final int MAX = 2000000;
long sum = 0;
for (int i = 0; i < MAX; i++) {
if (isPrime(i)) {
sum += i;
}
}
//答案:142913828922
System.out.println(sum);
long endTime=System.currentTimeMillis();
//程序运行时间:198ms
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
上回说到
BigInteger
的isProbablePrime
方法。这个方法的参数是certainty
,可信度,也就是说这个参数值越大,“概率”上说越符合真实情况(例如,“费马素性检验”以及“卡迈克尔数”),不过与此同时运算的时间也会相应的增加。
certainty – a measure of the uncertainty that the caller is willing to tolerate: if the call returns true the probability that this BigInteger is prime exceeds (1 - 1/2certainty). The execution time of this method is proportional to the value of this parameter.——
package Euler;
import java.math.BigInteger;
public class Prob_10s {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
BigInteger sum = BigInteger.ZERO;
for (BigInteger i = BigInteger.ONE; i.compareTo(BigInteger.valueOf(2000000)) < 0; i = i.add(BigInteger.ONE)) {
if (i.isProbablePrime(10)) {
sum = sum.add(i);
}
}
System.out.println(sum.toString());
long endTime=System.currentTimeMillis();
//程序运行时间:1619ms
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
值得注意的是,由于
isProbablePrime
只是一个较为可能的“概率”判断,isProbablePrime(c)
,c越大,素性检验得到确认的次数越多,素数的可能性越高,也越准确。以本题为例,c > 5
,输出结果不再变化,此时和“暴力求解”的结果“142913828922”相吻合。可惜,其运行时间令其不得不暂时甘拜下风。
描述:「在这个20×20 的网格中,对角线上相邻的四个元素已经用红色标记出来了,这四个数的乘积为 26 × 63 × 78 × 14 = 1788696。求在这个网格中,同一方向 (上、下、左、右以及对角线)相邻四个元素最大乘积。」
|下面先给出一段无误 but 冗长 的代码
package Euler;
import java.util.Arrays;
import java.util.Scanner;
public class Prob_11 {
static final int N = 20;
//竖直|按列型
public static int prodByCol(int[][] a) {
int maxProd = -1;
for (int col = 0; col < N; col++) {
for (int row = 0; row + 3 < N; row++) {
int prod = a[row][col] * a[row + 1][col] * a[row + 2][col] * a[row + 3][col];
if (prod > maxProd) {
maxProd = prod;
}
}
}
return maxProd;
}
//横平——按行型
public static int prodByRow(int[][] a) {
int maxProd = -1;
for (int row = 0; row < N; row++) {
for (int col = 0; col + 3 < N; col++) {
int prod = a[row][col] * a[row][col + 1] * a[row][col + 2] * a[row][col + 3];
if (prod > maxProd) {
maxProd = prod;
}
}
}
return maxProd;
}
//斜对角线型\
public static int prodByDiag(int[][] a) {
int maxProd = -1;
for (int row = 0; row + 3 < N; row++) {
for (int col = 0; col + 3 < N; col++) {
int prod = a[row][col] * a[row + 1][col + 1] * a[row + 2][col + 2] * a[row + 3][col + 3];
if (prod > maxProd) {
maxProd = prod;
}
}
}
return maxProd;
}
//反对角线型/(容易遗漏的情况之一)
public static int prodByBackDiag(int[][] a) {
int maxProd = -1;
for (int row = 0; row + 3 < N; row++) {
for (int col = N - 1; col - 3 >= 0; col--) {
int prod = a[row][col] * a[row + 1][col - 1] * a[row + 2][col - 2] * a[row + 3][col - 3];
if (prod > maxProd) {
maxProd = prod;
}
}
}
return maxProd;
}
public static void main(String[] args) {
int[][] a = new int[N][N];
Scanner sc = new Scanner(System.in);
//方阵的输入:这里不可以使用Java的foreach循环
//虽然新增的foreach被称为"增强的for循环",然而其只能访问不可修改
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
a[i][j] = sc.nextInt();
}
}
int[] max = new int[]{prodByCol(a), prodByRow(a), prodByDiag(a), prodByBackDiag(a)};
//递增排序
Arrays.sort(max);
//答案:70600674
System.out.println(max[max.length - 1]);
}
}
当我们回头观察,将
prodByCol
prodByRow
prodByDiag
prodByBackDiagl
提取公共部分进一步抽象,可以发现,“求邻接乘积”无非两步:
- 按照特定的方式判断元素位置是否合法
- 按照特定的方式迭代下一元素并求乘积
所谓的“按照特定的方式”,即左右移、上下移、正逆45度移,事实上这些完全可以作为参数值传递给一个代码实现更为简洁的函数,如下
package Euler;
import java.util.Arrays;
import java.util.Scanner;
public class Prob_11s {
static final int N = 20;
static final int CONSECUTIVE = 4;
//求,以[idRow,idCol]为起点,邻接run个元素的元素乘积
//连续法则,即下一个元素下标应为[idRow+nxtRow,idCol+nxtCol]
public static int adjcProb(int[][] matrix, int idRow, int idCol, int nxtRow, int nxtCol, int run) {
int prod = 1;
for (int i = 0; i < run; i++) {
if (idRow < 0 || idRow >= matrix.length || idCol < 0 || idCol >= matrix[idRow].length) {
return -1;
}
prod *= matrix[idRow][idCol];
idRow += nxtRow;
idCol += nxtCol;
}
return prod;
}
public static void main(String[] args) {
int max = -1;
int[][] matrix = new int[N][N];
Scanner sc = new Scanner(System.in);
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
matrix[i][j] = sc.nextInt();
}
}
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
max = Math.max(max, adjcProb(matrix, i, j, 1, 0, CONSECUTIVE));//右
max = Math.max(max, adjcProb(matrix, i, j, 0, 1, CONSECUTIVE));//下
max = Math.max(max, adjcProb(matrix, i, j, 1, 1, CONSECUTIVE));//右下
max = Math.max(max, adjcProb(matrix, i, j, 1, -1, CONSECUTIVE));//右上
}
}
System.out.println(max);
}
}
描述:「三角数即由依次排列的自然数的和构成,所以第 7 个三角数是 1+2+3+4+5+6+7=28 ,前十个三角数是: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55⋯⋯,让我们列出前七个三角数的因子,可以看出2828是第一个因子超过是第一个因子超过55的三角数,求第一个因子超过的三角数,求第一个因子超过550000的三角数。」
package Euler;
/**
* The sequence of triangle numbers is generated by adding the natural numbers.
* So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.
*
* The first ten terms would be:
* 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
*
* Let us list the factors of the first seven triangle numbers:
*
* 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
*
* We can see that 28 is the first triangle number to have over five divisors.
*
* What is the value of the first triangle number to have over five hundred divisors?
*/
public class Prob_12 {
public static int divisorsNumber(int n) {
int count = 0;
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 1; i <= top; i++) {
if (n % i == 0) {
//找到一个因子,必定存在另一个因子与之对应,所以因子总数加二
count += 2;
}
}
//如果该数为完全平方数,计数时需要删除重复项
//例如36: 1,2,3,4,6,6,9,12,18,36
return (top * top == n) ? count - 1 : count;
}
public static void main(String[] args) {
for (int i = 1; ; i++) {
int triagl = (1 + i) * i / 2;
if (divisorsNumber(triagl) > 500) {
System.out.println(triagl);
break;
}
}
}
}
描述:「计算如下一百个50 位数的和,求这个和的前十位数。」
package Euler;
import java.math.BigInteger;
import java.util.Scanner;
/**
* Work out the "first ten digits" of the sum of the following one-hundred 50-digit numbers.
*
* 37107287533902102798797998220837590246510135740250
* 46376937677490009712648124896970078050417018260538
* 74324986199524741059474233309513058123726617309629
* 91942213363574161572522430563301811072406154908250
* 23067588207539346171171980310421047513778063246676
* 89261670696623633820136378418383684178734361726757
* 28112879812849979408065481931592621691275889832738
* 44274228917432520321923589422876796487670272189318
* 47451445736001306439091167216856844588711603153276
* 70386486105843025439939619828917593665686757934951
* 62176457141856560629502157223196586755079324193331
* 64906352462741904929101432445813822663347944758178
* 92575867718337217661963751590579239728245598838407
* 58203565325359399008402633568948830189458628227828
* 80181199384826282014278194139940567587151170094390
* 35398664372827112653829987240784473053190104293586
* 86515506006295864861532075273371959191420517255829
* 71693888707715466499115593487603532921714970056938
* 54370070576826684624621495650076471787294438377604
* 53282654108756828443191190634694037855217779295145
* 36123272525000296071075082563815656710885258350721
* 45876576172410976447339110607218265236877223636045
* 17423706905851860660448207621209813287860733969412
* 81142660418086830619328460811191061556940512689692
* 51934325451728388641918047049293215058642563049483
* 62467221648435076201727918039944693004732956340691
* 15732444386908125794514089057706229429197107928209
* 55037687525678773091862540744969844508330393682126
* 18336384825330154686196124348767681297534375946515
* 80386287592878490201521685554828717201219257766954
* 78182833757993103614740356856449095527097864797581
* 16726320100436897842553539920931837441497806860984
* 48403098129077791799088218795327364475675590848030
* 87086987551392711854517078544161852424320693150332
* 59959406895756536782107074926966537676326235447210
* 69793950679652694742597709739166693763042633987085
* 41052684708299085211399427365734116182760315001271
* 65378607361501080857009149939512557028198746004375
* 35829035317434717326932123578154982629742552737307
* 94953759765105305946966067683156574377167401875275
* 88902802571733229619176668713819931811048770190271
* 25267680276078003013678680992525463401061632866526
* 36270218540497705585629946580636237993140746255962
* 24074486908231174977792365466257246923322810917141
* 91430288197103288597806669760892938638285025333403
* 34413065578016127815921815005561868836468420090470
* 23053081172816430487623791969842487255036638784583
* 11487696932154902810424020138335124462181441773470
* 63783299490636259666498587618221225225512486764533
* 67720186971698544312419572409913959008952310058822
* 95548255300263520781532296796249481641953868218774
* 76085327132285723110424803456124867697064507995236
* 37774242535411291684276865538926205024910326572967
* 23701913275725675285653248258265463092207058596522
* 29798860272258331913126375147341994889534765745501
* 18495701454879288984856827726077713721403798879715
* 38298203783031473527721580348144513491373226651381
* 34829543829199918180278916522431027392251122869539
* 40957953066405232632538044100059654939159879593635
* 29746152185502371307642255121183693803580388584903
* 41698116222072977186158236678424689157993532961922
* 62467957194401269043877107275048102390895523597457
* 23189706772547915061505504953922979530901129967519
* 86188088225875314529584099251203829009407770775672
* 11306739708304724483816533873502340845647058077308
* 82959174767140363198008187129011875491310547126581
* 97623331044818386269515456334926366572897563400500
* 42846280183517070527831839425882145521227251250327
* 55121603546981200581762165212827652751691296897789
* 32238195734329339946437501907836945765883352399886
* 75506164965184775180738168837861091527357929701337
* 62177842752192623401942399639168044983993173312731
* 32924185707147349566916674687634660915035914677504
* 99518671430235219628894890102423325116913619626622
* 73267460800591547471830798392868535206946944540724
* 76841822524674417161514036427982273348055556214818
* 97142617910342598647204516893989422179826088076852
* 87783646182799346313767754307809363333018982642090
* 10848802521674670883215120185883543223812876952786
* 71329612474782464538636993009049310363619763878039
* 62184073572399794223406235393808339651327408011116
* 66627891981488087797941876876144230030984490851411
* 60661826293682836764744779239180335110989069790714
* 85786944089552990653640447425576083659976645795096
* 66024396409905389607120198219976047599490197230297
* 64913982680032973156037120041377903785566085089252
* 16730939319872750275468906903707539413042652315011
* 94809377245048795150954100921645863754710598436791
* 78639167021187492431995700641917969777599028300699
* 15368713711936614952811305876380278410754449733078
* 40789923115535562561142322423255033685442488917353
* 44889911501440648020369068063960672322193204149535
* 41503128880339536053299340368006977710650566631954
* 81234880673210146739058568557934581403627822703280
* 82616570773948327592232845941706525094512325230608
* 22918802058777319719839450180888072429661980811197
* 77158542502016545090413245809786882778948721859617
* 72107838435069186155435662884062257473692284509516
* 20849603980134001723930671666823555245252804609722
* 53503534226472524250874054075591789781264330331690
*/
public class Prob_13 {
static final int N = 100;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
BigInteger sum = BigInteger.ZERO;
for (int i = 0; i < N; i++)
//.add方法不改变对象的原值
sum=sum.add(sc.nextBigInteger());
//substring子串的参数索引是“左开右闭”区间
System.out.println(sum.toString().substring(0,10));
}
}
描述:「卡拉兹(Callatz)猜想:对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把乘 3 加 1。这样一直反复下去,最后一定在某一步得到 n = 1。例如,应用以上规则,并且以数字 13 开始,我们得到以下序列:13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想,而是求“以哪个不超过100 万的数字开始,能给得到最长的序列?” 注意: 一旦序列开始之后,也就是从第二项开始,项是可以超过 100 万的。」
package Euler;
import java.math.BigInteger;
public class Prob_14s {
static final int N = 1000000;
public static void main(String[] args) {
int max=0;//数字
int maxCollatz=-1;//序列长度
for (int i = 1; i < N; i++){
int count=0;//计数当前数字的Collatz长度
BigInteger n=BigInteger.valueOf(i);
while(!n.equals(BigInteger.ONE))
{
n=(n.mod(BigInteger.TWO).equals(BigInteger.ZERO))?
(n.divide(BigInteger.TWO)):
(n.multiply(BigInteger.valueOf(3)).add(BigInteger.ONE));
count++;
}
if(count>maxCollatz){
maxCollatz = count;
max=i;
}
}
System.out.println(max);
}
}
package Euler;
import java.math.BigInteger;
public class Prob_15 {
//递归求n!阶乘
public static BigInteger factorial(BigInteger n){
return (n.equals(BigInteger.ONE))?BigInteger.ONE:n.multiply(factorial(n.subtract(BigInteger.ONE)));
}
public static void main(String[] args) {
//C(40,20),梦回高中数学排列组合问题
BigInteger m=BigInteger.valueOf(40);
BigInteger n=BigInteger.valueOf(20);
System.out.println(factorial(m).divide(factorial(n).multiply(factorial(m.subtract(n)))));
}
}
package Euler;
import java.math.BigInteger;
/**
* 2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.
* What is the sum of the digits of the number 2^1000?
*/
public class Prob_16 {
public static void main(String[] args) {
BigInteger n = BigInteger.TWO;
n = n.pow(1000);
BigInteger sum=BigInteger.ZERO;
//BigInteger具有两重性,既是“字符串”,又有“数”的四则运算
//这里也可以遍历n.toString()并减去基准‘0’,求和
while(!n.equals(BigInteger.ZERO)){
sum=sum.add(n.mod(BigInteger.TEN));
n=n.divide(BigInteger.TEN);
}
System.out.println(sum.toString());
}
}
描述:「如果把数字一到五用单词写出来,即 one, two, three, four, five,那么总共使用的字母数量 3+3+5+4+4=19。如果把从一到一千的数字用对应的单词写出来,总共需要多少个字母?注意:不要计算空格与连字符,如 342(three hundred and forty-two)包含 23个字母,而 115(one hundred and fifteen)包含 20个字母, and 的使用遵守英式英语的规则 」
package Euler;
/**
* If the numbers 1 to 5 are written out in words:
* one, two, three, four, five,
* then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.
*
* If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words,
* how many letters would be used?
*
* NOTE: Do not count spaces or hyphens.
* For example, 342 (three hundred and forty-two) contains 23 letters
* and 115 (one hundred and fifteen) contains 20 letters.
*
* The use of "and" when writing out numbers is in compliance with British usage.
*/
public class Prob_17 {
public static String toEnglish(int n) {
String[] enRef = new String[]{"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"};
String[] enRef2 = new String[]{"", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", "hundred"};
String res = "";
if (n < 20) {
res += enRef[n];
} else if (n < 100) {
res += enRef2[n / 10];
res += (n % 10 == 0) ? "" : enRef[n % 10];
} else {
res += (enRef[n / 100] + enRef2[10]);
res += (n % 100 == 0) ? "" : "and" + toEnglish(n % 100); //递归
}
return res;
}
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i < 1000; i++)
sum += toEnglish(i).length();
System.out.println(sum + "onethousand".length());
}
}
|下面先给出一段“结果无误”却令人“啼笑皆非”,可以说是“贻笑大方”的代码
package Euler;
/**
* By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
*
* 3
* 7 4
* 2 4 6
* 8 5 9 3
*
* That is, 3 + 7 + 4 + 9 = 23.
*
* Find the maximum total from top to bottom of the triangle below:
*
* 75
* 95 64
* 17 47 82
* 18 35 87 10
* 20 04 82 47 65
* 19 01 23 75 03 34
* 88 02 77 73 07 63 67
* 99 65 04 28 06 16 70 92
* 41 41 26 56 83 40 80 70 33
* 41 48 72 33 47 32 37 16 94 29
* 53 71 44 65 25 43 91 52 97 51 14
* 70 11 33 28 77 73 17 78 39 68 17 57
* 91 71 52 38 17 14 91 43 58 50 27 29 48
* 63 66 04 68 89 53 67 30 73 16 69 87 40 31
* 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
*
* NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route.
* However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)
*/
public class Prob_18 {
static private int[][] triangle = {
{75},
{95, 64},
{17, 47, 82},
{18, 35, 87, 10},
{20, 4, 82, 47, 65},
{19, 1, 23, 75, 3, 34},
{88, 2, 77, 73, 7, 63, 67},
{99, 65, 4, 28, 6, 16, 70, 92},
{41, 41, 26, 56, 83, 40, 80, 70, 33},
{41, 48, 72, 33, 47, 32, 37, 16, 94, 29},
{53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14},
{70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57},
{91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48},
{63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31},
{4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23}};
public static void main(String[] args) {
int max = -1;
for (int a = 0; a <= 0; a++) {
for (int b = a; b <= a + 1; b++) {
for (int c = b; c <= b + 1; c++) {
for (int d = c; d <= c + 1; d++) {
for (int e = d; e <= d + 1; e++) {
for (int f = e; f <= e + 1; f++) {
for (int g = f; g <= f + 1; g++) {
for (int h = g; h <= g + 1; h++) {
for (int i = h; i <= h + 1; i++) {
for (int j = i; j <= i+1; j++) {
for (int k = j; k <= j + 1; k++) {
for (int l = k; l <= k + 1; l++) {
for (int m = l; m <= l + 1; m++) {
for (int n = m; n <= m + 1; n++) {
for (int o = n; o <= n + 1; o++) {
int sum = triangle[0][a] +
triangle[1][b] +
triangle[2][c] +
triangle[3][d] +
triangle[4][e] +
triangle[5][f] +
triangle[6][g] +
triangle[7][h] +
triangle[8][i] +
triangle[9][j] +
triangle[10][k] +
triangle[11][l] +
triangle[12][m] +
triangle[13][n] +
triangle[14][o];
max = Math.max(sum, max);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
//答案:
System.out.println(max);
}
}
原题“藐”述:「 By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
3
7 4
2 4 6
8 5 9 3
That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom in triangle.txt (right click and 'Save Link/Target As...'), a 15K text file containing a triangle with one-hundred rows.
NOTE: This is a much more difficult version of Problem 18. It is not possible to try every route to solve this problem, as there are 299 altogether! If you could check one trillion (1012) routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o) 」
翻译过来就是,如果“暴力枚举”该测试用例会运行到“海枯石烂”“天荒地老”。
下面用 可谓是令初学者闻风丧胆的“动态规划” 来重新思考这个问题:
- 若
f(i,j)
表示从 “起点” 至 “第 i 行第 j 个元素” 的所有路径选择方案集合中的路径和的最大项
- 则方案集合可以划分为,“由左上角”与“由右上角”到达两种情况,于是
f(i,j)=Math.max( f(i-1,j-1)+a[i,j], f(i-1,j)+a[i,j] )
package Euler;
import java.util.Arrays;
public class Prob_18s {
static int[][] a = {
{75},
{95, 64},
{17, 47, 82},
{18, 35, 87, 10},
{20, 4, 82, 47, 65},
{19, 1, 23, 75, 3, 34},
{88, 2, 77, 73, 7, 63, 67},
{99, 65, 4, 28, 6, 16, 70, 92},
{41, 41, 26, 56, 83, 40, 80, 70, 33},
{41, 48, 72, 33, 47, 32, 37, 16, 94, 29},
{53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14},
{70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57},
{91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48},
{63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31},
{4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23}
};
static int[][] f = new int[a.length + 10][a.length + 10];
public static void main(String[] args) {
for (int i = 1; i <= a.length; i++) {
for (int j = 1; j <= a[i - 1].length; j++) {
f[i][j] = Math.max(f[i - 1][j - 1], f[i - 1][j]) + a[i - 1][j - 1];
}
}
int max = -1;
for (int e : f[a.length]) {
max = (max < e) ? e : max;
}
//答案:1074
System.out.println(max);
}
}
package Euler;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* Find the maximum total from top to bottom in triangle.txt, a 15K text file containing a triangle with one-hundred rows.
*
* NOTE: This is a much more difficult version of Problem 18.
* It is not possible to try every route to solve this problem, as there are 2^99 altogether!
* If you could check one trillion (10^12) routes every second
* it would take over twenty billion years to check them all.
*
* There is an efficient algorithm to solve it. ;o)
*/
public class Prob_67 {
static final int n = 100;
static String[][] a = new String[n][];
static int[][] f = new int[n + 10][n + 10];
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("/Users/durui/Downloads/p067_triangle.txt"));
String tmp = br.readLine();
for (int i = 0; i < n && tmp != null; i++, tmp = br.readLine()) {
a[i] = tmp.split(" ");
}
br.close();
} catch (IOException e) {
System.out.println("error");
e.printStackTrace();
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
f[i][j] = Math.max(f[i - 1][j - 1], f[i - 1][j]) + Integer.parseInt(a[i-1][j-1]);
}
}
int ans = -1;
for (int e : f[n]) {
ans = (ans < e) ? e : ans;
}
//答案:7273
System.out.println(ans);
}
}
描述:「以下是一些已知信息,但是或许你需要自己做一些其他的调查。1900 年 1 月 1 日是星期一。30 天的月份有: 9 月, 4 月, 6 月, 1 1月。此外的月份都是 31 天,当然 2 月除外。2 月在闰年有 29 天,其他时候有 28 天。年份可以被 4 整除的是闰年,但是不能 400 整除的世纪年(100的整数倍年)除外。求:20 世纪( 1901 年 1 月 1 日到 2000 年 12 月 31 日)一共有多少个星期日落在了当月的第一天?」
package Euler;
import java.util.Calendar;
/**
* You are given the following information, but you may prefer to do some research for yourself.
*
* 1 Jan 1900 was a Monday.
* Thirty days has September,
* April, June and November.
* All the rest have thirty-one,
* Saving February alone,
* Which has twenty-eight, rain or shine.
* And on leap years, twenty-nine.
* A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
* How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
*/
public class Prob_19 {
public static void main(String[] args) {
int count = 0;
//以默认时区+系统当前时间初始化日历,不可使用new
Calendar cald = Calendar.getInstance();
for (int y = 1901; y <= 2000; y++) {
for (int m = 0; m < 12; m++) {
//注意:"Calendar.JANUARY"默认为"0";
cald.set(y, Calendar.JANUARY + m, 1);
//注意:"Calendar.SUNDAY"默认为"1"
if (cald.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
count++;
}
}
System.out.println(count);
}
}
蔡勒(Zeller) 公式可以快速的将日期转换为星期: 介绍&推导来源网络
D = [ c 4 ] − 2 c + y + [ y 4 ] + 13 ( m + 1 ) 5 + d − 1. \ D= \lbrack \frac c 4 \rbrack -2c +y + \lbrack \frac y 4 \rbrack + \cfrac{13(m+1)}{5} + d - 1 . D=[4c]−2c+y+[4y]+513(m+1)+d−1.
package Euler;
import java.math.BigInteger;
public class Prob_20 {
public static void main(String[] args) {
BigInteger ans=BigInteger.ONE;
int sum=0;
for (int i = 1; i <=100;i++) {
ans=ans.multiply(BigInteger.valueOf(i));
}
String str=ans.toString();
for(int i = 0; i < str.length();i++){
sum+=str.charAt(i)-'0';
}
System.out.println(sum);
}
}
描述:「令d(n) 表示自然数 n 所有真因子(除开数 n 身的所有因子)的和。如果 d(a)=b 且 d(b)=a ,其中 a≠b ,那么 a 与 b 便为亲和数对,其中的每个数称为亲和数。
例如:220 的真因子为 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 110,所以 d(220)=284;284 的真因子为 1, 2, 4, 71, 142,所以 d(284)=220 ,因此 220、284 为亲和数对。
计算: 10000 以下所有亲和数的和。」
package Euler;
/**
* Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
* If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.
*
* For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.
*
* Evaluate the sum of all the amicable numbers under 10000.
*/
public class Prob_21 {
public static int d(int n) {
int sum = 0;
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0)
sum += (i + n / i);
}
return sum+1;
}
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 10000; i++)
if (d(d(i)) == i && d(i)!=i) {
//System.out.println(i + "是友好数");
sum += i;
}
System.out.println(sum);
}
}
描述:「文件 names.txt 是一个 46K 大小的文本文件,包含 5000 多个英文名字。利用这个文件,首先将文件中的名字按照字母排序,然后计算每个名字的字母值,最后将字母值与这个名字在名字列表中的位置相乘,得到这个名字的得分。
例如:将名字列表按照字母排序后, COLIN 这个名字是列表中的第 938 个,它的字母值是
3 + 15 + 12 + 9 + 14 = 53 。所以,COLIN 这个名字的得分就是 938 × 53 = 49714。
计算:文件中所有名字的得分总和是多少?」
package Euler;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
/**
* Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names,
* begin by sorting it into alphabetical order.
*
* Then working out the alphabetical value for each name,
* multiply this value by its alphabetical position in the list to obtain a name score.
*
* For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list.
* So, COLIN would obtain a score of 938 × 53 = 49714.
*
* What is the total of all the name scores in the file?
*/
public class Prob_23 {
static Set<String> names = new TreeSet();
static void readFile(String ref) {
try {
BufferedReader br = new BufferedReader(new FileReader(ref));
String tmp = "";
while ((tmp = br.readLine()) != null) {
tmp = tmp.replace("\"", "");
String[] strings = tmp.split(",");
for (String s : strings) {
names.add(s);
}
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static int valueOf(String str) {
char[] letters = str.toCharArray();
int ans = 0;
for (char let : letters) {
ans += (let - 'A' + 1);
}
return ans;
}
public static void main(String[] args) {
readFile("/Users/durui/Downloads/p022_names.txt");
int sum = 0;
int index = 1;
for (String name : names) {
sum += valueOf(name) * (index++);
}
System.out.println(sum);
}
}
描述:「如果一个数的所有真因子之和等于该数自身 ,那么这个数被称为完全数。如果一个数的所有真因子之和小于该数自身 ,称其为不足数,如果大于 该数自身 ,称其为过剩数。
例如:28是一个完全数 ,因为 28 的所有真因子之和为 1 + 2 + 4 + 7 + 14 = 28;12是 一个 过剩数 ,因为 12 的所有真因子之和为 1 + 2 + 3 + 4 + 6 = 16 > 12;可以发现 12 是最小的过剩数,而 24 是最小的可以写为两个过剩数之和的数。
计算:所有无法写为两个过剩数之和的所有自然数的和。
说明:通过数学分析可以证明 ,所有大于 28123 的数都可以写成两个过剩数之和」
package Euler;
/**
* A perfect number is a number
* for which the sum of its proper divisors is exactly equal to the number.
*
* For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
*
* A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
*
* As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16,
* the smallest number that can be written as the sum of two abundant numbers is 24.
*
* By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers.
* However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
*
* Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
*/
public class Prob_23 {
static int sumOfDiv(int n) {
int sum = 0;
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
sum += (i + n / i);
}
}
return (top * top != n) ? (sum + 1) : (sum - top + 1);
}
static boolean isAbundant(int n) {
return sumOfDiv(n) > n;
}
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 28123; i++) {
boolean flag = false;
for (int addend = 1; addend <= i && i - addend >= 1; addend++) {
if (isAbundant(addend) && isAbundant(i - addend)) {
flag = true;
break;
}
}
sum += (flag) ? 0 : i;
}
System.out.println(sum);
}
}
描述:「一个排列是某些对象的有序组合,例如,3124 就是数字 1 2 3 4 的一种可能排列。如果所有的排列按照数值或者字母序排序,我们称其为一个字典序。
例如:0, 1, 2 的字典排列有: 012, 021, 102, 120, 201, 210。
计算:从0 到 9 的所有数字构成的字典排列中,第一百万个数字是多少?」
package Euler;
import java.util.ArrayList;
/**
* A permutation is an ordered arrangement of objects.
* For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4.
* If all of the permutations are listed numerically or alphabetically, we call it lexicographic order.
* The lexicographic permutations of 0, 1 and 2 are:
* 012 021 102 120 201 210
* What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
*/
public class Prob_24 {
static final int N = 10;
//记录各个数字的使用情况,0表示未选中,1表示已经使用
static boolean[] state = new boolean[N];
//记录当前使用情况下的,可行的一种排列方案
static int[] perm = new int[N];
static ArrayList<String> perms = new ArrayList<String>();
//思想:递归/递推,默认字典序搜索
static void dfs(int n) {
if (n == N - 1) {
String str = "";
for (int i : perm) {
str += i;
}
perms.add(str);
return;
}
//第 n 位选哪个数
for (int i = 0; i < N; i++) {
//数字 i 未被使用
if (state[i] == false) {
//倘若使用数字 i
state[i] = true;
perm[n] = i;
dfs(n + 1);
//恢复数字 i 的状态,以便下一次循环搜索
state[i] = false;
}
}
}
public static void main(String[] args) {
dfs(0);
//答案:2783915460
System.out.println(perms.get(1000000-1));
}
}
描述:「斐波那契数列定义如下:Fn = Fn1 +Fn2 ,其中 F1 = 1,F2 = 1;
例如:
F1 = 1
F2 = 1
F3 = 2
F4 = 3
F5 = 5
F6 = 8
F7 = 13
F8 = 21
F9 = 34
F10 = 55
F11 = 89
F12 = 144
求解:斐波那契数列中第一个包含斐波那契数列中第一个包含 1000 位数字的项是第几项?」
package Euler;
import java.math.BigInteger;
/**
* The Fibonacci sequence is defined by the recurrence relation:
*
* Fn = Fn−1 + Fn−2, where F1 = 1 and F2 = 1.
* Hence the first 12 terms will be:
*
* F1 = 1
* F2 = 1
* F3 = 2
* F4 = 3
* F5 = 5
* F6 = 8
* F7 = 13
* F8 = 21
* F9 = 34
* F10 = 55
* F11 = 89
* F12 = 144
* The 12th term, F12, is the first term to contain three digits.
*
* What is the index of the first term in the Fibonacci sequence to contain 1000 digits?
*/
public class Prob_25 {
static BigInteger[] fibRoll = new BigInteger[]{
BigInteger.valueOf(1),
BigInteger.valueOf(1),
BigInteger.valueOf(0)
};
public static void main(String[] args) {
int index=2;
while(fibRoll[2].toString().length()<1000){
//当前计算到第index个斐波那契数
index+=1;
fibRoll[2]=fibRoll[0].add(fibRoll[1]);
//滚动数组
fibRoll[0]=fibRoll[1];
fibRoll[1]=fibRoll[2];
}
//答案:4782
System.out.println(index);
}
}
描述:「一个单位分数就是分子为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 |
package Euler;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
/**
* A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:
*
* 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
* Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle.
*
* Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.
*/
public class Prob_26 {
static final int LIMIT = 1000;
static Map<Integer, Integer> recurs = new HashMap<Integer, Integer>();
static int RecurCycles(int denominator) {
//将分母化简为不含 2 5 因子的形式
BigInteger denOri = BigInteger.valueOf(denominator);
denOri = denOri.divide(denOri.gcd(BigInteger.valueOf(1024)));
denOri = denOri.divide(denOri.gcd(BigInteger.valueOf(625)));
//记忆,减少循环计算次数
if (recurs.containsKey(denOri)) {
return recurs.get(denOri);
}
/*
小学奥数知识:
1/1 = 9/9 = 0.99999999999999
1/3 = 3/9 = 0.33333333333333
1/7 = 142857/999999 = 0.14285714285714
*/
if (!denOri.equals(BigInteger.ONE)) {
int index = 1;
BigInteger denRef = BigInteger.valueOf(9);
while (!denRef.mod(denOri).equals(BigInteger.ZERO)) {
denRef = denRef.multiply(BigInteger.TEN).add(BigInteger.valueOf(9));
index++;
}
return index;
}
//如果化简后 分母为 1 其必定是不循环分数
return 0;
}
public static void main(String[] args) {
int ansNum = -1;
int maxLen = -1;
for (int i = 2; i < LIMIT; i++) {
int cycleSize = RecurCycles(i);
recurs.put(i,cycleSize);
if (cycleSize > maxLen) {
ansNum = i;
maxLen = cycleSize;
}
//System.out.format("%d 的 循环位数为 %d\n",i,cycleSize);
}
//答案:983
System.out.println(ansNum);
}
}
描述:「欧拉发现了著名的二次公式: n 2 + n + 41 n^2 + n + 41 n2+n+41,发现这个公式可以对于 0 ≤ n ≤ 39 0 \le n \le 39 0≤n≤39 的整数可以连续产生四十个素数。但是,当 n = 40 , 4 0 2 + 40 + 41 = 40 ( 40 + 1 ) + 41 n = 40, 40^2 + 40 + 41 = 40(40 + 1) + 41 n=40,402+40+41=40(40+1)+41 可以被41 整除;当 n = 41 , 4 1 2 + 41 + 41 n = 41,41^2 + 41 + 41 n=41,412+41+41 显然也可以被41 整除。另外一个著名公式是 n 2 − 79 n + 1601 n^2 - 79n + 1601 n2−79n+1601,可以对 0 ≤ n ≤ 79 0 \le n \le 79 0≤n≤79 的整数连续产生 80 个素数,这个公式的两个系数 −79 和 1601 的乘积是−126479。
考虑如下二次公式: n 2 + a n + b n^2 + an + b n2+an+b, ∣ a ∣ < 1000 |a| \lt 1000 ∣a∣<1000 , ∣ b ∣ ≤ 1000 |b| \le 1000 ∣b∣≤1000
求解:使得以上公式从n = 0 开始连续产生的素数最多的系数a 与b 的乘积。」
package Euler;
import java.util.TreeMap;
public class Prob_27 {
static boolean isPrime(int n) {
if (n <= 1) {
return false;
}
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
static int numberOfPrimes(int a, int b) {
for (int i = 0; ; i++) {
int n = i * i + i * a + b;
//可以连续产生素数,直至 i
//即 i 是该公式可以连续产生素数的个数
if (!isPrime(n)) {
return i;
}
}
}
public static void main(String[] args) {
//存储<连续产生的素数,公式系数乘积>自实现的键升序映射
TreeMap<Integer, Integer> formulae = new TreeMap<>();
for (int a = -999; a < 1000; a++) {
for (int b = -1000; b <= 1000; b++) {
formulae.put(numberOfPrimes(a, b), a * b);
}
}
System.out.println(formulae.lastEntry());
}
}
描述:「从 1 开始按顺时针方向向右移动并加一,形成的五乘五的数字螺旋如下:
可以验证对角线上的红色数字之和为101。
求解:对于一个 1001 乘以 1001 的同样的数字螺旋,其对角线上的值的和是多少?」
事实上,对于特殊顺序填数矩阵(蛇形矩阵、螺旋矩阵等),特殊位置的数字常常呈现某种内在规律性;例如,本题可以开动“高中数学数列·聪明的小脑瓜”手算出结果: S n = 1 3 n ( n + 1 ) ( 16 n − 34 ) + 16 n − 3 S_n = \frac 1 3 n(n+1)(16n-34) + 16n -3 Sn=31n(n+1)(16n−34)+16n−3,当 2 n − 1 = 1001 2n-1=1001 2n−1=1001,即 n = 501 n=501 n=501时,Sn = 669171001 =669171001 =669171001。
描述:「对于 2 ≤ a ≤ 5 和 2 ≤ b ≤ 5,考虑所有的整数 a 和 b 的组合 ab 如下:
22=4, 23=8, 24=16, 25=32
32=9, 33=27, 34=81, 35=243
42=16, 43=64, 44=256, 45=1024
52=25, 53=125, 54=625, 55=3125
如果把上面的结果按照数字顺序从小到大排列并去掉所有重复的数字,我们可以得到以下有
15 个不同数字的序列:4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125
计算:求对于 2 ≤ a ≤ 100 和 2 ≤ b ≤ 100, a、b会产生的序列中的有多少个不同的数字?」
package Euler;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Set;
public class Prob_29 {
public static void main(String[] args) {
//集合:去重
//大整数:100^100有200位;内置pow乘方运算
Set<BigInteger> n = new HashSet();
for (int a = 2; a <= 100; a++) {
for (int b = 2; b <= 100; b++){
n.add(BigInteger.valueOf(a).pow(b));
}
}
//答案:9183
System.out.println(n.size());
}
}
描述:「奇怪的是,只有三个数字可以被写成它们各位数的四次方之和:
1634 = 14 + 64 + 34 + 44
8208 = 84 + 24 + 04 + 84
9474 = 94 + 44 + 74 + 44
上面三个数的和 1634 + 8208 + 9474 = 19316。
计算:所有能被写成各位数五次方之和的数之和。
注:对于 1 = 14 由于并不是一个和,所以不包括在内。」
本题的思路较为简单,关键在于如何设置遍历循环的“上界”
如果设置为“Integer.MAX_VALUE”显然是不求甚解囫囵吞枣
分析:
倘若保证每一位数最大为 9,则这个数“最大” 为“99...99”的各位数五次方之和,为 digits*9^5
又,这个“最大值”应该介于,10^(digits-1) ~ 10^(digits)
所以,10^(digits-1) <= digits*9^5 <= 10^(digits) ,如图上界为10^7
package Euler;
import java.math.BigInteger;
/**
* Surprisingly there are only three numbers that can be written as the sum of fourth powers of their digits:
*
* 1634 = 14 + 64 + 34 + 44
* 8208 = 84 + 24 + 04 + 84
* 9474 = 94 + 44 + 74 + 44
* As 1 = 14 is not a sum it is not included.
*
* The sum of these numbers is 1634 + 8208 + 9474 = 19316.
*
* Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.
*/
public class Prob_30 {
static final int LIMIT = 10000000;
public static boolean isFifthPowerDigitSum(int n) {
int tmp = n;
int sum = 0, digit = 0;
while (n > 0) {
digit = n % 10;
sum += digit * digit * digit * digit * digit;
n /= 10;
}
return sum == tmp;
}
public static void main(String[] args) {
int ans = 0;
for (int i = 2; i < LIMIT; i++) {
if (isFifthPowerDigitSum(i)) {
ans += i;
//System.out.println(i + " is ok.");
}
}
//答案:443839
System.out.println(ans);
}
}
描述:「在英国,货币是由英镑£,便士 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 的方法?」
“可以选无限多次钱币”可以归纳为动态规划中尤为经典的“完全背包变式”求方案数问题
倘若用f(i,j)
表示在前i
个货币中选,恰好构造j
便士的所有方案集合的元素个数
按照第i个货币的个数k
对集合进行划分, f [ i , j ] = ∑ k = 0 l i m i t f [ i − 1 , j − v i ∗ k ] f[i,j]=\displaystyle\sum_{k=0}^{limit}f[i-1,j-v_i*k] f[i,j]=k=0∑limitf[i−1,j−vi∗k]
若用j-v替换j
, f [ i , j − v ] = ∑ k = 1 l i m i t f [ i − 1 , j − v i ∗ k ] f[i,j-v]=\displaystyle\sum_{k=1}^{limit}f[i-1,j-v_i*k] f[i,j−v]=k=1∑limitf[i−1,j−vi∗k]
则由此推得状态计算方程
: f [ i , j ] = f [ i − 1 , j ] + f [ i , j − v i ] f[i,j]=f[i-1,j]+f[i,j-v_i] f[i,j]=f[i−1,j]+f[i,j−vi]
package Euler;
/**
* In the United Kingdom the currency is made up of pound (£) and pence (p).
*
* There are eight coins in general circulation:
* 1p, 2p, 5p, 10p, 20p, 50p, £1 (100p), and £2 (200p).
* It is possible to make £2 in the following way:
*
* 1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
* How many different ways can £2 be made using any number of coins?
*/
public class Prob_31 {
static final int N = 200;
static int[] value = new int[]{0, 1, 2, 5, 10, 20, 50, 100, 200};
static int[][] f = new int[8 + 1][N + 10];
public static void main(String[] args) {
f[0][0] = 1;
for (int i = 1; i <= 8; i++) {
for (int j = 0; j <= N; j++) {
//朴素的二维数组
f[i][j] = f[i - 1][j];
if (j - value[i] >= 0) {
f[i][j] += f[i][j - value[i]];
//优化的滚动数组:f[j] += f[j - value[i]]
//此外,可以用增强for循环避免下标与实际意义的对齐问题
}
}
}
System.out.println(f[8][N]);
}
}
描述:「如果一个 n 位数使用了 1 到 n 中每个数字且只使用了一次,我们称其为“全数字”。
例如,15234 这个五位数,是 1 到 5 的全数字。7254 是一个不寻常的数,因为 39 × 186 = 7254 这个算式的乘数,被乘数和乘积组成了一个 1 到 9 的”全数字“组合。
求解:找出所有能组成 1 到 9 全数字的乘式中乘积的和。
提示:有的乘积数字能够被多个乘法算式得到,所以在计算时要记得只计算它们一次。」
package Euler;
import java.util.Arrays;
/**
* We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 through 5 pandigital.
*
* The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing multiplicand, multiplier, and product is 1 through 9 pandigital.
*
* Find the sum of all products whose multiplicand/multiplier/product identity can be written as a 1 through 9 pandigital.
*
* HINT: Some products can be obtained in more than one way so be sure to only include it once in your sum.
*/
public class Prob_32 {
static boolean isPandigital(String s) {
if (s.length() != 9) {
return false;
}
for (int i = 1; i <= s.length(); i++) {
if (s.contains("" + i) != true) {
return false;
}
}
return true;
}
static boolean isPandigitalProduct(int n) {
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 1; i <= top; i++) {
if (n % i == 0 && isPandigital("" + i + n / i + n)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
int sum = 0;
//反证法:对于 z=x*y, 如果 z > 10000超过 5 位数,由于是1~9的全排数
//最多剩下4个数, 4个数中最大乘积 9*999<99*99=9801也不到 5 个数字,矛盾
for (int i = 1; i < 10000; i++) {
if (isPandigitalProduct(i)) {
sum += i;
}
}
System.out.println(sum);
}
}
package Euler;
/**
* The fraction 49/98 is a curious fraction, as an inexperienced mathematician in attempting to simplify it may incorrectly believe that 49/98 = 4/8, which is correct, is obtained by cancelling the 9s.
*
* We shall consider fractions like, 30/50 = 3/5, to be trivial examples.
*
* There are exactly four non-trivial examples of this type of fraction, less than one in value, and containing two digits in the numerator and denominator.
*
* If the product of these four fractions is given in its lowest common terms, find the value of the denominator.
*/
public class Prob_33 {
static int gcd(int m, int n) {
return (m % n == 0) ? n : gcd(n, m % n);
}
static boolean isCurious(int n, int d) {
//分子个位
int n1 = n % 10;
//分子十位
int n10 = n / 10;
//分母个位
int d1 = d % 10;
//分母十位
int d10 = d / 10;
if (n1 == 0 || d1 == 0) {
return false;
}
if (n1 != d10) {
return false;
}
if (n10 / gcd(n10, d1) != n / gcd(n, d) || d1 / gcd(n10, d1) != d / gcd(n, d)) {
return false;
}
if ((int) Math.floor(n / d) >= 1) {
return false;
}
//System.out.println(""+n+"/"+d+" is ok");
return true;
}
public static void main(String[] args) {
int nn = 1;
int dd = 1;
for (int numerator = 10; numerator <= 99; numerator++) {
for (int denominator = 10; denominator <= 99; denominator++) {
if (isCurious(numerator, denominator)) {
nn *= numerator;
dd *= denominator;
}
}
}
System.out.println(dd / gcd(nn, dd));
}
}
描述:「145 是一个好奇数,因为 1! + 4! + 5! = 1 + 24 + 120 = 145,求所有这样的好奇数字之和。特殊地,因为 1! = 1 以及 2! = 2 都不是和,所以不包括在内。」
package Euler;
/**
* 145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.
*
* Find the sum of all numbers which are equal to the sum of the factorial of their digits.
*
* Note: As 1! = 1 and 2! = 2 are not sums they are not included.
*/
public class Prob_34 {
//定上界,假设最多有 n 位,10^(n-1) <= n * 9! <= 10^n
static final int LIMIT = 100000000;
//使用递归定义会导致栈帧溢出StackOverFlow!!!
static int f(int n) {
int ans = 1;
for (int i = 1; i <= n; i++) {
ans*=i;
}
return ans;
}
static int dFactorials(int n) {
int sum = 0;
while (n > 0) {
sum += f(n % 10);
n /= 10;
}
return sum;
}
static boolean isCurious(int n) {
return n == dFactorials(n);
}
public static void main(String[] args) {
int ans = 0;
for (int i = 3; i < LIMIT; i++) {
if (isCurious(i)) {
ans += i;
}
}
System.out.println(ans);
}
}
package Euler;
/**
* The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.
*
* There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.
*
* How many circular primes are there below one million?
*/
public class Prob_35 {
static boolean isPrime(int n) {
if (n <= 1) {
return false;
}
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
static boolean isCirPrime(int n) {
String ref = String.valueOf(n) + String.valueOf(n);
//例如,197的轮换借助"197197"截取定长子串"197""971""719"
for (int begin = 0, end = begin + ref.length() / 2; end < ref.length(); begin++, end++) {
if (!isPrime(Integer.parseInt(ref.substring(begin, end)))) {
return false;
}
}
return true;
}
static final int LIMIT = 1000000;
public static void main(String[] args) {
int num = 0;
for (int i = 0; i < LIMIT; i++) {
if (isCirPrime(i)) {
num++;
}
}
System.out.println(num);
}
}
package Euler;
/**
* The decimal number, 585 = 10010010012 (binary), is palindromic in both bases.
*
* Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.
*
* (Please note that the palindromic number, in either base, may not include leading zeros.)
*/
public class Prob_36 {
static final int LIMIT = 1000000;
static boolean isPalindromic(String str) {
return str.equals(new StringBuilder(str).reverse().toString());
}
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < LIMIT; i++) {
//toBinaryString是Integer的"静态方法",不用实例化对象调用
if (isPalindromic(String.valueOf(i)) && isPalindromic(Integer.toBinaryString(i))) {
sum += i;
}
}
System.out.println(sum);
}
}
package Euler;
/**
* The number 3797 has an interesting property.
* Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7.
* Similarly we can work from right to left: 3797, 379, 37, and 3.
*
* Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
*
* NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
*/
public class Prob_37 {
public static boolean isPrime(int n) {
if (n <= 1) {
return false;
}
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
static boolean isTruncatable(int n) {
String str = String.valueOf(n);
for (int i = 0; i < str.length(); i++) {
//System.out.println(str.substring(i));
if (!isPrime(Integer.parseInt(str.substring(i)))) {
return false;
}
}
for (int j = str.length(); j > 0; j--) {
//System.out.println(str.substring(0, j));
if (!isPrime(Integer.parseInt(str.substring(0, j)))) {
return false;
}
}
return true;
}
public static void main(String[] args) {
int index = 0;
int sum = 0;
for (int i = 11; index < 11; i++) {
if (isTruncatable(i)) {
System.out.format("%d is truncatable\n",i);
index++;
sum += i;
}
}
System.out.println(sum);
}
}
描述:「用数字 192 分别乘以 1, 2, 3 可以得到:
192 × 1 = 192
192 × 2 = 384
192 × 3 = 576
把每个乘积前后相接,我们可以得到一个全数字 192384576;我们把 192384576 称为 192 和 (1,2,3) 的拼接乘积。类似的,我们可以用数字 9 乘以 1 2 3 4 和 5 得到全数字 918273645 它是 9 和 (1,2,3,4,5) 的拼接乘积。
求解:用一个整数和 (1,2, … , n),形成的拼接乘积中最大的全数字(其中 n>1 ) 」
package Euler;
/**
* Take the number 192 and multiply it by each of 1, 2, and 3:
*
* 192 × 1 = 192
* 192 × 2 = 384
* 192 × 3 = 576
* By concatenating each product we get the 1 to 9 pandigital, 192384576. We will call 192384576 the concatenated product of 192 and (1,2,3)
*
* The same can be achieved by starting with 9 and multiplying by 1, 2, 3, 4, and 5, giving the pandigital, 918273645, which is the concatenated product of 9 and (1,2,3,4,5).
*
* What is the largest 1 to 9 pandigital 9-digit number that can be formed as the concatenated product of an integer with (1,2, ... , n) where n > 1?
*/
public class Prob_38 {
static boolean isPandigital(String s) {
if (s.length() != 9) {
return false;
}
for (int i = 1; i <= s.length(); i++) {
if (s.contains("" + i) != true) {
return false;
}
}
return true;
}
public static void main(String[] args) {
String concat = "";
//满足条件的只可能是 4 位数, n 为 2
for (int n = 9999; n >= 1000; n--) {
concat = "" + n + 2 * n;
if (isPandigital(concat)) {
System.out.println(concat);
break;
}
}
}
}
package Euler;
/**
* If p is the perimeter of a right angle triangle with integral length sides, {a,b,c}, there are exactly three solutions for p = 120.
*
* {20,48,52}, {24,45,51}, {30,40,50}
*
* For which value of p ≤ 1000, is the number of solutions maximised?
*/
public class Prob_39 {
static int solutions(int p) {
int feasible = 0;
for (int x = 1; x < p / 3; x++) {
for (int y = x; y < p; y++) {
int z = p - x - y;
if (z > x && z > y && x * x + y * y == z * z) {
feasible++;
}
}
}
return feasible;
}
public static void main(String[] args) {
int max = -1;
int bestP = -1;
for (int i = 12; i <= 1000; i++) {
int s = solutions(i);
if (s > max) {
max = s;
bestP = i;
}
}
System.out.println(bestP);
}
}
package Euler;
/**
* An irrational decimal fraction is created by concatenating the positive integers:
*
* 0.123456789101112131415161718192021...
*
* It can be seen that the 12th digit of the fractional part is 1.
*
* If dn represents the nth digit of the fractional part, find the value of the following expression.
*
* d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000
*/
public class Prob_40 {
static String s = "";
static final int MAX_LENGTH = 1000000;
static void strInit() {
for (int i = 0; s.length() <= MAX_LENGTH; i++) {
s += i;
}
}
static int d(int n) {
return Integer.parseInt("" + s.charAt(n));
}
public static void main(String[] args) {
strInit();
int ans = 1;
for (int i = 1; i <= MAX_LENGTH; i *= 10) {
ans *= d(i);
}
System.out.println(ans);
}
}
package Euler;
import java.util.ArrayList;
/**
* We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once. For example, 2143 is a 4-digit pandigital and is also prime.
*
* What is the largest n-digit pandigital prime that exists?
*/
public class Prob_41 {
static ArrayList<String> perms = new ArrayList<>();
//引用:https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
static boolean nextPermutation(int[] array) {
// Find longest non-increasing suffix
int i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i]) {
i--;
}
// Now i is the head index of the suffix
// Are we at the last permutation already?
if (i <= 0) {
return false;
}
// Let array[i - 1] be the pivot
// Find rightmost element greater than the pivot
int j = array.length - 1;
while (array[j] <= array[i - 1]) {
j--;
}
// Now the value array[j] will become the new pivot
// Assertion: j >= i
// Swap the pivot with j
int temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
// Reverse the suffix
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
// Successfully computed the next permutation
return true;
}
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6, 7};
do { // Must start at lowest permutation
String temp = "";
for (int a : array) {
temp += a;
}
perms.add(temp);
} while (nextPermutation(array));
for (int i = perms.size() - 1; i >= 0; i--) {
if (isPrime(Integer.parseInt(perms.get(i)))) {
System.out.println("aaa");
System.out.println(perms.get(i));
break;
}
}
}
static boolean isPrime(int n) {
if (n < 2) {
return false;
}
int top = (int) Math.floor(Math.sqrt(n) + 0.5);
for (int i = 2; i <= top; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
package Euler;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* The nth term of the sequence of triangle numbers is given by, tn = ½n(n+1); so the first ten triangle numbers are:
*
* 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
*
* By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t10. If the word value is a triangle number then we shall call the word a triangle word.
*
* Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, how many are triangle words?
*/
public class Prob_42 {
static Set<String> names = new HashSet<>();
static void readFile(String ref) {
try {
BufferedReader br = new BufferedReader(new FileReader(ref));
String tmp = "";
while ((tmp = br.readLine()) != null) {
tmp = tmp.replace("\"", "");
String[] strings = tmp.split(",");
for (String s : strings) {
names.add(s);
}
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static int getID(String s) {
int ans = 0;
char[] temp = s.toCharArray();
for (char c : temp) {
ans += c - 'A' + 1;
}
return ans;
}
static boolean isTriangle(int t) {
//½n(n+1)
int left = 1;
int right = 3;
for (int n = 3; t < left || t > right; n++) {
left = right;
right = n * (n + 1) / 2;
//System.out.println("t is not within the range" + String.format("[%d,%d]", left, right));
}
return t == left || t == right;
}
public static void main(String[] args) {
readFile("/Users/durui/Downloads/p042_words.txt");
int ans=0;
for (String name : names) {
if (isTriangle(getID(name))) {
//为什么names.remove(name);报错
ans++;
}
}
System.out.println(ans);
}
}