阿里巴巴2020春招暑期實習筆試題

週五參加阿里暑期實習的筆試,一共兩道編程題,一小時時間,在這裏總結記錄一下此次筆試題!

第一題

在這裏插入圖片描述

題目描述

有一疊撲克牌,每張牌介於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];
    }
}

歡迎讀者一起交流,代碼實現如有錯誤和優化之處還望指出,期待有其他解決思路的讀者可以分享一下,感謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章