参见了中华英才网的编程大赛,算法题很简单,但还是做的不熟,一道用BigInteger的没有AC
下面是三道题的题目和程序
问题1:求小于n的自然数中,17或者18的倍数和 java
有一点需要注意的是当n>17*18时,17*18只需要算一次
而且k*18>n不一定有k*17>n,所以当k*18>n后,一定要再增加k直到17*k>n
<span style="white-space:pre"> </span>public int mySum(int n) {
if (n < 17) {
return 0;
}
int res = 0;
int k = 1;
while (true) {
int tmp1 = k * 17;
int tmp2 = k++ * 18;
if (tmp2 >= n) {
break;
}
if (tmp1 % 18 != 0) {
res += tmp1;
}
res += tmp2;
}
while (true) {
int tmp1 = k++ * 17;
if (tmp1 >= n) {
break;
}
if (tmp1 % 18 != 0) {
res += tmp1;
}
}
return res;
}
问题2:n*n(n<20)的正方形块,延正方形边从左上角走到右下角,一共有几种方式 java
解答:前几个比较好求n=1:2,n=2:6,n=3:20,n=4:70
可以总结为有从左上到右下一共要走2n步,其中向右或向下有n步,这样就是C2n n
中间结果很容易溢出,这样就用java的BigInteger类,理论上内存有多大,就可以计算多大的算法。
然后把公式写出来很容易发现2n*(2n-1)...*(n+1) 下面的是n*(n-1)*...*2 ,上下肯定有公因子2n,因此就减少了一次大数乘法。
public long pathcount(int n) {
BigInteger res1 = BigInteger.valueOf(1), res2 = BigInteger.valueOf(1);
int i;
if (n == 1) {
return 2;
}
if (n == 2) {
return 6;
}
for (i = n * 2 - 1; i > n; i--) {
res1 = res1.multiply(BigInteger.valueOf(i));
}
for (i = n - 1; i > 2; i--) {
res2 = res2.multiply(BigInteger.valueOf(i));
}
return res1.divide(res2).longValue();
}
问题3:求小n的素数和 java
用到一个公式:一个非素数一定可以分解成几个素数的乘积
这样在求取答案过程中,再维护一个素数的链表,这样可以提高求素数的速度
写博客的时候想到,没必要将素数链表遍历完,只需要遍历到sqrt(n)就可以。
public int primesSum(int n) {
if (n < 2) {
return 0;
}
if (n == 2) {
return 2;
}
List<Integer> primes = new ArrayList<Integer>();
primes.add(2);
int res = 2;
for (int i = 3; i <= n; i += 2) {
if (!divisible(i, primes)) {
primes.add(i);
res += i;
}
}
return res;
}
private boolean divisible(int n, List<Integer> primes) {
for (Integer prime : primes) {
if (n % prime == 0) {
return true;
}
}
return false;
}