參見了中華英才網的編程大賽,算法題很簡單,但還是做的不熟,一道用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;
}