java實現:2018年9月7日下午的科大訊飛筆試題:平安夜殺手
下邊是自己理解的解答,如果有問題歡迎指出。
java實現:2018年9月7日下午的科大訊飛筆試題:平安夜殺手
題目:(這裡是按照原題打字的)
有n個殺手排成一行,每一個殺手都有不同的編號(編號為1~n),在每個夜晚殺手都會行動,如果殺手編號大於他右邊的殺手的編號,他就會殺死他右邊的殺手,殺手的行動是瞬間的,所以一個人可能在某一個夜晚既殺死了別人,又被別人殺死。例如3 2 1這個順序,在第一個夜晚2會殺死1,同時3也會殺死2.顯而易見,一段時間後,就不會有人殺或者被殺了,平安夜也就到來了,請問在平安夜之前有多少個夜晚。
輸入說明:(按照原題打字的)
第一行是一個整數n,表示殺手的數量
接下來一行有n個數,是一個1~n的全排列
輸出說明:(按照原題打字的)
輸出包含一個整數,表示平安夜之前經歷的多少個夜晚
樣例一:
樣例輸入:
10
10 9 7 8 6 5 3 4 2 1
樣例輸出:
2
對樣例一的說明:樣例一中殺手變化為[10 9 7 8 6 5 3 4 2 1]->[10 8 4]->[10]
下邊樣例二:
樣例輸入:
6
1 2 3 4 5 6
樣例輸出:
0
我的理解:
平安夜到來是因為所有殺手順序都是從小到大了,有兩種情況:1)只剩一個;2)類似1 2 3這種都是從小到大的順序。
出現以上兩種情況,就不需要繼續殺人了。一晚只能殺相鄰右邊的殺手。
上邊問題就轉化為:需要殺幾個晚上,才可以把殺手序號變為上邊兩種情況?
解題思路:把殺手編號按照輸入順序放入到list中,看是否滿足上邊的兩種情況,如果滿足,就停止了,如果不滿足,就從後往前比較,如果相鄰的後一個比前一個小,就remove掉後面一個,然後依次往前。遍歷完一次,就相當於過了一個夜晚。一直遍歷直到滿足上邊兩種情況為止。遍歷一次for迴圈就k++一次,這樣來計數。
那麼怎麼判斷是否滿足上邊兩種情況呢?
第一種情況很好判斷,如果只剩一個殺手了,那麼list.size()是為1
第二種情況,如果序列滿足第二種情況,那麼,我們經歷一次for迴圈,我們list.size()大小不變(因為如果是按照從小到大順序排列,list裡面就沒有元素會被remove掉),如果list.seze()在for迴圈前後相等,那麼就使用break退出這個迴圈
我的程式碼:
package test20190907;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
while (sc.hasNext()) {
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
list.add(sc.nextInt());
}
// 呼叫一個函式:
int result = f(list, n);
System.out.println(result);
}
}
private static int f(List<Integer> list, int n) {
/*下邊註釋是對這個函式下邊的迴圈和判斷等做說明。
* 利用k來計數,就是迴圈的次數,只要while迴圈一次,就計數一次
* (看if中:
* 為什麼要有這個判斷?,
* 考慮到如果list是按照從小到大的順序,
* 那麼我們k就不用計數 了, 同時直接跳出我們的while迴圈)
* ( 看else中:
* 由於上邊的if的判斷,
* 需要把本次list.size()和 上次的list.size()做比較
* 這裡n,在if中就是表示前一次的list.seze();)
*/
// TODO Auto-generated method stub
int k = 0;
while (list.size() > 1) {
for (int i = list.size() - 1; i >= 1; i--) {
if (list.get(i) < list.get(i - 1)) {
list.remove(i);
// i++;
}
}
if (list.size() == n) {// 這裡n表示迴圈前的list.size();
break;
} else {
n = list.size();
k++;
}
}
return k;
}
}
控制檯:(這裡輸入了三組)包括題目中給出的輸入輸出例子)