週五參加阿里暑期實習的筆試,一共兩道編程題,一小時時間,在這裏總結記錄一下此次筆試題!
第一題
題目描述:
有一疊撲克牌,每張牌介於1和10之間
有四種出牌方法:
- 單出一張
- 出兩張相同的牌(對子)
- 出五張順子(如12345)
- 出三連對子(如112233)
給10個數,表示1-10每種牌有幾張,問最少要多少次能出完?
題目解析:
該題目需要去考慮到多種狀態,起初考慮使用DP求解,但是沒有找到動態轉移方程,所以採用暴力回溯法求解:
1、每次根據當前牌的情況優先執行連對 -> 順子 -> 對子 -> 單子;
2、執行完當前情況,回溯到執行前的狀態,若滿足下一優先級的執行方式,則繼續執行,以此類推,遞歸查詢到最少次數;
代碼如下:
public class Main {
/**
* 測試用例:
* 1 1 1 2 2 2 2 2 1 1
*
* 輸出結果:3
*
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//num記錄牌的總數
int num = 0;
//ans記錄最終出牌次數
int ans = 0;
int temp;
int[] cards = new int[10];
for(int i=0; i<10; i++){
temp = scanner.nextInt();
cards[i] = temp;
num += temp;
}
//如果只有一張牌則直接返回
if(num == 1){
System.out.println(1);
return;
}
//使用暴力回溯發求解
ans = getNum(cards, 0);
System.out.println(ans);
}
private static int getNum(int[] cards, int k){
int ans = Integer.MAX_VALUE;
if(k >= cards.length)
return 0;
//若牌數爲0則繼續下一張
else if (cards[k] == 0){
return getNum(cards,k+1);
}
//優先出連對
if(k <= cards.length-3 && cards[k] >= 2 && cards[k+1] >= 2 && cards[k+3] >= 2){
cards[k] -= 2;
cards[k+1] -= 2;
cards[k+2] -= 2;
ans = Math.min(1+getNum(cards, k), ans);
cards[k] += 2;
cards[k+1] += 2;
cards[k+2] += 2;
}
//出順子
if(k <= cards.length - 5 && cards[k] >= 1 && cards[k+1] >=1 && cards[k+2] >= 1 && cards[k+3] >= 1 && cards[k+4] >=1){
cards[k] -= 1;
cards[k+1] -= 1;
cards[k+2] -= 1;
cards[k+3] -= 1;
cards[k+4] -= 1;
ans = Math.min(1+getNum(cards, k), ans);
cards[k] += 1;
cards[k+1] += 1;
cards[k+2] += 1;
cards[k+3] += 1;
cards[k+4] += 1;
}
//出對子
if(cards[k] >= 2){
cards[k] -= 2;
ans = Math.min(1+getNum(cards, k), ans);
cards[k] += 2;
}
//出單子
if(cards[k] >= 1){
cards[k] -= 1;
ans = Math.min(1+getNum(cards, k), ans);
cards[k] += 1;
}
return ans;
}
}
//
第二題
題目解析:
使用dp來進行求解,關鍵在於狀態轉移的存儲,這裏定義一個一維數組,存儲當前位置的最長字符串長度。
初始化:dp[i] = string.length;
狀態方程:dp[i] = max((dp[j] + temp.length), dp[i]) , i代表當前位置
代碼如下:
public class Test2 {
/**
* 測試用例:
* 4
* aaa
* bcd
* zzz
* bcdef
*
* 答案輸出:
* 11
*
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
if(n == 1){
System.out.println(sc.nextLine());
return;
}
//list存儲輸入的字符串
ArrayList<String> list = new ArrayList<>();
for(int i=0; i<n; i++){
list.add(sc.next());
}
Collections.sort(list);
int ans = longestlength(list);
System.out.println(ans);
}
/**
* 獲取最長字符串長度
* 使用DP進行求解,dp[i] = string.length;
* @param list 所有輸入的字符串
* @return 返回int類型的長度
*/
private static int longestlength(ArrayList<String> list){
int[] dp = new int[list.size()];
String temp,str ;
for(int i=list.size()-1; i>=0; i--){
temp = list.get(i);
for(int j=i; j<list.size(); j++){
str = list.get(j);
if(i == j){
dp[i] = temp.length();
}
/**
* 注意這裏的條件判斷,當i == j時
* 測試用例:4
* aaa
* bcd
* zzz
* bcdef
*
* dp初始化過程中,第一步執行zzz, 此時若沒有 i!=j 的判斷,則會進入該if條件句,導致dp[3] = 6,結果錯誤!!!
*
*/
if(temp.charAt(temp.length() - 1) <= str.charAt(0) && i != j){
dp[i] = Math.max(temp.length() + dp[j], dp[i]);
}
}
}
return dp[0];
}
}
歡迎讀者一起交流,代碼實現如有錯誤和優化之處還望指出,期待有其他解決思路的讀者可以分享一下,感謝!