【回溯】A066_LC_串聯字符串的最大長度(暴搜 / 二進制枚舉)

一、Problem

Given a list of words, list of single letters (might be repeating) and score of every character.

Return the maximum score of any valid set of words formed by using the given letters (words[i] cannot be used two or more times).

It is not necessary to use all characters in letters and each letter can only be used once. Score of letters ‘a’, ‘b’, ‘c’, … ,‘z’ is given by score[0], score[1], … , score[25] respectively.

Input: words = ["dog","cat","dad","good"], letters = ["a","a","c","d","d","d","g","o","o"], 
score = [1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0]
Output: 23
Explanation:
Score  a=1, c=9, d=5, g=3, o=2
Given letters, we can form the words "dad" (5+1+5) and "good" (3+2+2+5) with a score of 23.
Words "dad" and "dog" only get a score of 21.

二、Solution

方法一:暴搜

錯誤思想:第一想法是去真的構造單詞,但是這樣做字符的順序就定死了,而題目中很多例子都是沒有按照 letters 的順序構造的,還是要看清題目啊。

這裏反過來想:枚舉每一個單詞,看是否能夠用給定的 letters 組合,而對於第 i 個單詞 word,我們可以選擇它,也可以不選擇它,分析到這一步就不難得出可以用暴搜。

需要注意的細節:每個字符只能使用一次,所以進入新的遞歸前,我們需要對字符的使用情況進行備份。

class Solution {
	int ans, N, sco[];
    String[] ws;
	void dfs(int i, int sum, int[] map) {
		if (i == N) {
			ans = Math.max(ans, sum);
			return;
		}
		int cur = 0, backup[] = Arrays.copyOf(map, map.length);
        boolean could = true;
		for (char c : ws[i].toCharArray()) {
			if (map[c-'a']-- > 0) {
				cur += sco[c-'a'];
			} else {
				could = false;
                break;
			}
		}
		if (could) 
            dfs(i+1, sum + cur, map);
		dfs(i+1, sum, backup);
	}
    public int maxScoreWords(String[] words, char[] letters, int[] score) {
    	sco = score;
        ws = words;
    	int[] map = new int[26];
        N = ws.length;
    	for (char c : letters)
    		map[c-'a']++;
    	dfs(0, 0, map);
    	return ans;
    }
}

複雜度分析

  • 時間複雜度:O(2n)O(2^n)
  • 空間複雜度:O(n)O(n)

方法二:位壓縮

words 一共有 n 個單詞,一共有 2n2^n 子集,枚舉所有子集即可…

class Solution {
	int n, tot, sc[];
    String[] ws;
    public int maxScoreWords(String[] words, char[] letters, int[] score) {
    	int max = 0, map[] = new int[26];
    	sc = score;
        ws = words;
    	n = ws.length; tot = 1 << n;
        for (char c : letters) 
            map[c-'a']++;
    	for (int i = 0; i < tot; i++) {
    		max = Math.max(max, f(i, map.clone()));
    	}
    	return max;
    }
    int f(int mask, int[] map) {
    	int sum = 0;
    	for (int j = 0; j < n; j++) {
    		if ((mask & (1 << j)) > 0) {
    			for (char c : ws[j].toCharArray()) {
    				if (--map[c-'a'] < 0)
                        return 0;
                    sum += sc[c-'a'];
    			}
    		}
    	}
    	return sum;
    }
}

複雜度分析

  • 時間複雜度:O(2n)O(2^n)
  • 空間複雜度:O(1)O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章