【回溯】B065_LC_串聯字符串的最大長度(二進制 (枚舉 / 遞歸))

一、Problem

Given an array of strings arr. String s is a concatenation of a sub-sequence of arr which have unique characters.

Return the maximum possible length of s.

Input: arr = ["un","iq","ue"]
Output: 4
Explanation: All possible concatenations are "","un","iq","ue","uniq" and "ique".
Maximum length is 4.

Constraints:

1 <= arr.length <= 16
1 <= arr[i].length <= 26
arr[i] contains only lower case English letters.

二、Solution

方法一:錯誤解法

錯誤解法:WA 74/83

class Solution {
    public int maxLength(List<String> sl) {
    	int max = 0;
        l1:
    	for (int i = 0; i < sl.size(); i++) {
            Set<Character> st = new HashSet<>();
            StringBuilder sb = new StringBuilder(sl.get(i));
            for (char c : sl.get(i).toCharArray()) if (st.add(c) == false) {
                if (sl.size() == 1) 
                    return 0;
                continue l1;
            }
    		l2:
            for (int j = i+1; j < sl.size(); j++) {
				for (char c : sl.get(j).toCharArray()) if (st.add(c) == false) {
					continue l2;
				}
                sb.append(sl.get(j));	// 錯
			}
			if (max < sb.length())
                max = sb.length();
    	}
    	return max;
    }
}
["a", "abc", "d", "de", "def"]
輸出:4
預期:6

想的有點簡單了,用 sb append 掉一個字符串 s 後,如果下一個字符串 s1 比該還要長,但是卻有相同字符,這就錯了。所以這涉及到選 s1 與不選 s1


方法二:二進制枚舉

1 <= arr[i].length <= 26,告訴我們用 32 位二進制即可表示每一個字符串的選或否.

老毛病: 經常性地把 i & (1 << j)mask & (1 << shift) 的結果看成是 0/1,比賽時改了好久,其實這個結果表示的某一項選沒選而已,所以,但 i 和 mask 的其它位置還是有意義的。

class Solution {
	int mask;
	boolean isUnique(String s) {
		for (char c : s.toCharArray()) {
			int shift = c - 'a';
			if ((mask & (1 << shift)) > 0)
				return false;
			mask |= (1 << shift);
		}
		return true;
	}
    public int maxLength(List<String> sl) {
    	int n = sl.size(), tot = 1 << n, max = 0;
    	
    	for (int i = 0; i < tot; i++) {
    		int cur = 0;
    		mask = 0;
			for (int j = 0; j < n; j++)  {
                if ((i & (1 << j)) > 0 && isUnique(sl.get(j)))
				    cur += sl.get(j).length();
			}
			if (cur > max) max = cur;
    	}
    	return max;
    }
}

複雜度分析

  • 時間複雜度:O(n2×2n)O(n^2 × 2^n),最壞情況是,每一個字符串都選
  • 空間複雜度:O(1)O(1)

方法三:回溯

思想和 二級制枚舉是一樣的,只不過,遞歸幫我們把每一種合法情況都給隱式地枚舉出來了,而不是手寫 for (i < tot),但不清楚爲什麼,遞歸比較快。。。

class Solution {
	int N, max;
	StringBuilder sb;
	List<String> sl;
	void dfs(int i, int mask) {
		if (i == N) { 
			if (sb.length() > max)
				max = sb.length();
			return;
		}
		int m = mask;
		boolean fl = true;
		String s = sl.get(i);
		for (char c : s.toCharArray()) {
			int shift = c - 'a';
			if ((m & (1 << shift)) > 0) {
				fl = false;
				break;
			}
			m |= (1 << shift);
		}
		if (fl) {
			sb.append(s);
			dfs(i+1, m);
			sb.setLength(sb.length()-s.length());
		}
		dfs(i+1, mask);
	}
    public int maxLength(List<String> sl) {
    	N = sl.size();
    	this.sl = sl;
        sb = new StringBuilder();
    	dfs(0, 0);
    	return max;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章