5.6.1.3 喝汽水問題
問題:共有1000瓶汽水,每喝完後一瓶得到的一個空瓶子,每3個空瓶子又能換1瓶汽水,喝掉以後又得到一個空瓶子,問總共能喝多少瓶汽水,最後還剩余多少個空瓶子?
這個問題其實是個比較典型的遞推問題,每3個空瓶都可以再換1瓶新的汽水,這樣一直遞推下去,直到最後不能換到汽水為止。
第一種思路:每次喝一瓶,每有三個空瓶子就去換一瓶新的汽水,直到最後沒有汽水可以喝為止。在程序中記憶汽水的數量和空瓶子的數量即可。
則實現的代碼如下:
int num = 1000; //汽水數量
int drinkNum = 0; //喝掉的汽水數量
int emptyNum = 0; //空瓶子的數量
while(num > 0){ //有汽水可以喝
num--; //喝掉一瓶
emptyNum++;//空瓶子數量增加1
drinkNum++; //喝掉的汽水數量增加1
if(emptyNum == 3){//有3個空瓶子,則去換
num++; //汽水數量增加1
emptyNum = 0; //空瓶子數量清零
}
}
System.out.println(“總共喝掉瓶數:” + drinkNum);
System.out.println(“剩余空瓶子數:” + emptyNum);
執行該程序,輸出結果如下:
總共喝掉瓶數:1499
剩余空瓶子數:2
在該代碼中,每次循環喝掉一瓶汽水,則汽水數量減少1,空瓶子數增加1,喝掉的總汽水瓶數增加1,每次判斷空瓶子的數量是否達到3,如果達到3則換1瓶汽水,同時空瓶子的數量變為零。這種思路比較直觀,但是循環的次數比較多,所以就有了下面的邏輯實現。
第二種思路:一次把所有的汽水喝完,獲得所有的空瓶子,再全部換成汽水,然後再一次全部喝完,再獲得所有的空瓶子,依次類推,直到沒有汽水可喝為止。
則實現的代碼如下:
int num = 1000; //汽水數量
int drinkNum = 0; //喝掉的汽水數量
int emptyNum = 0; //空瓶子的數量
while(num > 0){ //有汽水可以喝
drinkNum += num;//喝掉所有的汽水
emptyNum += num; //空瓶子數量等於上次剩余的加上這次喝掉的數量
num = emptyNum / 3;//兌換的汽水數量
emptyNum -= num * 3;//本次兌換剩余的空瓶子數量
}
System.out.println(“總共喝掉瓶數:” + drinkNum);
System.out.println(“剩余空瓶子數:” + emptyNum);
在該代碼中,每次喝掉所有的汽水,也就是num瓶,則喝掉的總瓶數每次增加num,因為每次都可能剩余空瓶子(不足3個的),則總的空瓶子數量是上次空瓶子數量加上本次喝掉的num瓶。接著是對話汽水,則每次可以兌換的汽水數量是空瓶子的數量的1/3,注意這裡是整數除法,而本次兌換剩余的空瓶子數量是原來的空瓶子數量減去兌換得到汽水數量的3倍,這就是一次循環所完成的功能,依次類推即可解決該問題。
5.6.1.4水仙花數
問題:水仙花數指三位數中,每個數字的立方和和自身相等的數字,例如370,3 × 3 × 3 + 7 × 7 × 7 + 0 × 0 × 0 =370,請輸出所有的水仙花數。
該問題中體現了一個基本的算法——數字拆分,需要把一個數中每位的數字拆分出來,然後才可以實現該邏輯。
實現思路:循環所有的三位數,拆分出三位數字的個位、十位和百位數字,判斷3個數字的立方和是否等於自身。
則實現的代碼如下所示:
for(int i = 100;i < 1000;i++){ //循環所有三位數
int a = i % 10; //個位數字
int b = (i / 10) % 10; //十位數字
int c = i / 100; //百位數字
//判斷立方和等於自身
if(a * a * a + b * b * b + c * c * c == i){
System.out.println(i);
}
}
在該代碼中,拆分個位數字使用i和10取余即可,拆分十位數字時首先用i除以十,去掉個位數字,並使原來的十位數字變成個位,然後和10取余即可,因為i是一個三位數,所以i除以100即可得百位數字,因為這裡都是整數除法,不存在小數的問題。然後只需要判斷立方和是否等於自身即可。
注意:因為i是循環變量,這裡不能改變i的值,不然可能造成死循環。