leetcode:活字印刷
題目來源:力扣
題目描述:
你有一套活字字模 tiles,其中每個字模上都刻有一個字母 tiles[i]。返回你可以印出的非空字母序列的數目。
====================================================
輸入:“AAB”
輸出:8
解釋:可能的序列為 “A”, “B”, “AA”, “AB”, “BA”, “AAB”, “ABA”, “BAA”。
===================================================
提示:
1 <= tiles.length <= 7
tiles 由大寫英文字母組成
審題:
本題有點類似與排列組合中的排列問題,其中子集的大小可以為任意大小但非空.本題主要的復雜性在于字符串中可能存在重復字符.
對于這類題目,大都可以使用回溯的思路解決,區別在于考慮每一步的可能選擇子集.如果字符串中不包含重復值,則我們的下一步可以選擇任意未被選中的字符,或者不選(在第一步我們必須選擇一個值,因為最終結果字符串不能為空).而由于存在重復字符,因此我們選擇第一個字符’A’與第二個字符’A’對最終的結果是沒有任何區別的,如果按照原有思路,則會存在重復計數.因此,對于存在重復字符的字符串,我們的每一步選擇只能在所有未被選擇且不重復的字符中選擇.
可以使用鍵值對結構保存字符串中每一個字符的個數,基于此,我們的每一步選擇即為所有值不為空的鍵,或者空集(在第一步不能選擇空);當我們選擇空集時,表示當前選擇結束,計數+1;
java算法:
class Solution {Map<Character, Integer> map = new HashMap<>();int totalNum;//當前可選的字符集合為所有至不為0的鍵,或者不選任何元素,直接返回private void dfs(boolean end){//如果構建結束,則計數+1if(end){totalNum++;return;}for(Character k: map.keySet()){if(map.get(k) != 0){System.out.println(k);map.put(k, map.get(k)-1); //入棧,該鍵對應的值減1dfs(false); //由于我們在該步選擇了字符k,所以選擇并未結束,傳入falsemap.put(k, map.get(k)+1); //退棧,該鍵對應的值加1}}//從第二步起,在每一步,我們均可以選擇空集,表示當前構造子集結束.dfs(true);}public int numTilePossibilities(String tiles) {//統計字符串中各字符數量for(int i = 0; i < tiles.length(); i++){char c = tiles.charAt(i);if(map.containsKey(c))map.put(c, map.get(c)+1);elsemap.put(c, 1);}//由于第一步不能選擇空集,因此第一步單獨考慮for(char c: map.keySet()){map.put(c, map.get(c)-1);dfs(false);map.put(c, map.get(c)+1);}return totalNum;} }更新:
在參考其他人關于此題的題解后,發現我最初的思路很不是很簡潔,存在很多可以優化的地方.
1.首先由于原始字符串僅有大寫字符組成,因此我們可是使用整數數組保存每一個字符出現的次數來代替代碼中的HashMap結構.經對比,使用整數數組能夠大幅減少程序執行時間.
2.其次,回溯的思路可以重新設計.我們每一步的可選集合為所有值不為0的鍵,在選完當前值后,我們可以終止選擇,此時總的方案數加1,我們也可以繼續進行下一個字符的選擇,此時我們遞歸調用,將當前選中鍵的值減1,在遞歸退出后,將該鍵對應的值加1.每次遞歸調用的結果為當前剩余字符中可能的選擇結果.如果當前剩余字符為空,則返回0.
總結
以上是生活随笔為你收集整理的leetcode:活字印刷的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运算放大器的稳定性分析(一)
- 下一篇: M35感想