最近看到一道騰訊面試題,覺得很有意思。題干如下:
有甲乙兩家伙用一個英語單詞玩游戲(無聊的人還是很多的!!!)。兩個人輪流進行,每個人每次從中刪掉任意一個字母,如果剩余的字母序列是嚴格單調遞增的(按字典序a < b < c <....<z,假設單詞字母不區分大小寫,也就是說,a與A算相等),則這個人勝利。假設兩個人都足夠聰明(即如果有贏的方案,都不會選輸的方案 ),甲先開始,問他能贏么?
輸入: 一連串英文小寫字母,長度任意(當然要在計算機能承受的范圍內),保證最開始的狀態不是一個嚴格單增的序列。
輸出:1表示甲可以贏,0表示甲不能贏。
例如: 輸入 bad, 則甲可以刪掉b或者a,剩余的是ad或者bd,他就贏了,輸出1。
又如: 輸入 aaa, 則甲只能刪掉1個a,乙刪掉一個a,剩余1個a,乙獲勝,輸出0。
下面給出我用Java實現的算法,如果大家有其他的實現方法,歡迎跟帖和探討。語言不限。
我的基本實現思路將給定的單詞分成若干個單調遞增的序列。然后按每個序列中包含單詞個數多少進行遞減排序,也就是說,排在前面的單調遞增序列中包含的字母個數最少。然后由甲開始從排在前面的遞增序列中選擇一個字母。直到該遞增序列中的字母全部被選中。然后繼續從下一個遞增序列選擇字母。按着這樣的方法做,直到剩下最后一個單調遞增序列,隨最后選擇了倒數第二個單調遞增序列中的最后一個字母,誰就贏了。
例如,單詞hela,可以分為三個單調遞增序列:h、a、el。從甲開始選擇。
甲:h
乙:a
由於a是倒數第二個單調遞增序列的最后一個字母,所以乙贏了。
對於單詞money可以分成三個單調遞增序列:mo、n、ey。排序后:n、mo、ey。
甲:n
乙:m
甲:o
所以甲贏。
具體的實現算法如下:
public class Test { // 實現算法的方法,in為一個給定的單詞 public static int who(String in) { // 基本思路就是找到該單詞中所有遞增的子序列,然后從字符最少的子序列甲乙輪回刪除字母,直到還剩下最后一個子序列為止 // 誰刪除了最后一個字母,誰就贏了! // in不能為null if(in == null) return 0; // 單詞至少需要有一個字母 if(in.length() == 0) return 0; in = in.toLowerCase(); // 都變成小寫字母 // 所有遞增數列集合 java.util.List<StringBuilder> ascendingList = new java.util.ArrayList<StringBuilder>(); char lastChar = in.charAt(0); StringBuilder sb = new StringBuilder(); // 存儲當前遞增的字符列表 sb.append(lastChar); for(int i = 1; i < in.length(); i++) { // 當前字符屬於當前的遞增序列 if(in.charAt(i) > lastChar) { sb.append(in.charAt(i)); } // 當前字符屬於下一個遞增序列,所以需要存儲上一個遞增序列 else { ascendingList.add(sb); sb = new StringBuilder(); sb.append(in.charAt(i)); } lastChar = in.charAt(i); } if(sb.length() > 0) { ascendingList.add(sb); } // 下面就開始游戲了 // 從甲開始刪字母,從字符最少的遞增序列開始刪除第一個字母,直到之后只剩下一個遞增序列為止,誰刪除的最后一個之母,誰就贏了 // 這里本應該判斷如果單詞本身就是遞增序列,那么甲就win了,不過既然題目說沒有這種情況,所以就注釋掉了 /*if(ascendingList.size() == 1) { return 1; }*/ java.util.Collections.sort(ascendingList, new java.util.Comparator<StringBuilder>() { @Override public int compare(StringBuilder sb1, StringBuilder sb2) { if(sb1.length() > sb2.length()) { return 1; } else if(sb1.length() == sb2.length()) { return 0; } else { return -1; } } }); int win = 0; // 1代表甲贏,0代表乙贏 while(ascendingList.size() > 1) { if(win == 0) win = 1; // 甲開始 else win = 0; // 乙開始 // 刪除第一個遞增序列的第一個字母,如果該遞增序列 ascendingList.get(0).delete(0, 1); if(ascendingList.get(0).length() == 0) { ascendingList.remove(0); } } return win; } public static void main(String[] args) { System.out.println(who("money")); } }
誰有更NB的算法,歡迎跟帖,語言不限!