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