2013年9月22日 阿里巴巴校招 算法、研發 題之(僅供學習討論)
在黑板上寫下50個數字:1至50,在接下來的49輪操作中,每次做如下操作,選取兩個黑板上的數字a和b,擦去,在黑板上寫|b-a|,請問最後一次動作之後剩下數字可能是什麼?爲什麼?(不用寫代碼,不寫原因不得分)。
1至n的數字,剩餘的數字肯定爲0至n的數字,假如剩下k,則可以這樣認爲,1至n的數字中除k外的數字全部抵消了。當任意選擇a、b時,假如a較小,這些數字的總和將減少2a,即使是b,最後消爲0時,也將減去2b,最後全部消失。所以這些數字的和一定是偶數2*m,m是這些數字中(k除外)的數字組合,如存在這個組合,那麼就可以。
分析及就到此爲止了,以下是我Java實現的代碼,
package algorithm;
public class Remove2s1 {
public void WhatLeft(int n){
int total = n*(n+1)/2;
int beginNum;
if(total%2 == 0){
beginNum = 0;
}else{
beginNum = 1;
}
System.out.println("These numbers maybe left: ");
for(;beginNum<=n;beginNum+=2){
if(MaybeLeft(n,beginNum,total)){
System.out.print(beginNum+", ");
}
}
}
public boolean MaybeLeft(int n, int num, int total){
int leftTotal = (total-num)/2;
int[] numArr = new int[n+1];
for(int i=0; i<=n; i++){
numArr[i] = i;
}
numArr[num] = 0;
int sum = 0;
int index = n;
while(index>0){
if(sum+numArr[index] == leftTotal){
return true;
}else if(sum+numArr[index] < leftTotal){
sum += numArr[index];
}
index --;
}
return false;
}
public boolean MaybeLeft(int n, int num){
int total = n*(n+1)/2;
if(MaybeLeft(n,num,total)){
System.out.println("OK!");
printOrder(n,num,total);
return true;
}else{
System.out.println("No!");
return false;
}
}
public void printOrder(int n, int num, int total){
int leftTotal = (total-num)/2;
int[] numArr = new int[n+1];
for(int i=0; i<=n; i++){
numArr[i] = i;
}
numArr[num] = 0;
int sum = 0;
int index = n;
System.out.println("Select there numbers:");
while(index>0){
if(sum+numArr[index] == leftTotal){
System.out.print(numArr[index]);
break;
}else if(sum+numArr[index] < leftTotal){
sum += numArr[index];
if(numArr[index] != 0){
System.out.print(numArr[index]+", ");
}
}
index --;
}
}
public static void main(String args[]){
Remove2s1 rem = new Remove2s1();
rem.WhatLeft(50);
rem.MaybeLeft(50,9);
}
}
運行結果就是1至50,可能剩餘的數字
輸出結果爲:
These numbers maybe left:
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, OK!
Select there numbers:
50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 24
就是1到50之間的奇數都有可能。
或單獨查看某個數字是否能留下,一種可能是擦出順序是,從輸出的數字中,依次,從剩餘的其他數字中找數字,將該數字抵消掉,直到爲0.
例如,n=10,
Remove2s1 rem = new Remove2s1();
rem.WhatLeft(10);
rem.MaybeLeft(10,5);
輸出:
These numbers maybe left:
1, 3, 5, 7, 9, OK!
Select there numbers:
10, 9, 6
要剩餘5,可以這樣:
1到10: 1、2、3、4、5、6、7、8、9、10
5要剩餘,先去掉: 1、2、3、4、6、7、8、9、10
先選10,從1、2、3、4、7、8中選兩個數消除掉,就8和2吧,剩下:1、3、4、6、7、9
再選9,從1、3、4、7中,選數字7、1吧,剩餘1、3、4、6,
最後選6,將剩餘1、3、4,想辦法抵消掉,比如6-4=2、3-2=1、1-1=0,到此爲止。