ποΈ Problems
Maximum Length of a Concatenated String with Unique Characters - LeetCode
You are given an array of strings arr.
A string s is formed by the concatenation of a subsequence of arr
that has unique characters.
Return the maximum possible length of s.
A subsequence is an array that can be derived from another array
by deleting some or no elements without changing the order of the remaining elements.
Input: arr = ["un","iq","ue"]
Output: 4
Explanation: All the valid concatenations are:
- ""
- "un"
- "iq"
- "ue"
- "uniq" ("un" + "iq")
- "ique" ("iq" + "ue")
Maximum length is 4.
π€ First attempt
- iλ²μ§Έ word λ₯Ό μ νν κ²½μ°, μ ννμ§ μμ κ²½μ°μ λν΄μ μ²λ¦¬.
- νμ¬κΉμ§ μΆκ°λ word λ₯Ό character frequency map μ κ°μ§κ³ λ€λλ©΄μ conflict κ° μλμ§ λΉκ΅νκΈ°.
var maxLength = function (arr) {
const N = arr.length;
let max = -Infinity;
const dfs = (index, cur, set) => {
if (index >= N) {
if (max < cur.length) max = cur.length;
return;
}
// not add
dfs(index + 1, cur, set);
// add
const localSet = new Set();
for (const ch of arr[index]) {
if (localSet.has(ch)) return;
localSet.add(ch);
}
for (const ch of arr[index]) {
if (set.has(ch)) return;
}
for (const ch of arr[index]) {
set.add(ch);
}
dfs(index + 1, cur + arr[index], set);
for (const ch of arr[index]) {
set.delete(ch);
}
};
dfs(0, "", new Set());
return max;
};
character μ μ€λ³΅ μ¬λΆ 체ν¬λ₯Ό character frequencyλ₯Ό object λ‘ μ²λ¦¬νλλ°... <br /> μ΄ λΆλΆμ΄ κΉλνμ§ μμμ bitset μ΄μ©ν λ°©λ²μ΄ λ μ’μ κ² κ°μμ μλ μ 리ν΄λ΄ λλ€.
β¨ Idea
- μ£Όμ΄μ§ array index
[0, ..., N-1]
recursive λ‘ μννλ©΄μ - ν΄λΉ word λ₯Ό μΆκ°νκ±°λ μΆκ°νμ§ μκ±°λ μ ν.
- μΆκ°νλ κ²½μ°μλ κΈ°μ‘΄ μΆκ°λ characterλ€κ³Ό conflict κ° μλμ§λ₯Ό νμΈν΄μ μ²λ¦¬.
- μ΄ character μ conflict μ²λ¦¬λ₯Ό μνμ¬ bitset μ΄μ©ν¨.
π Intuition
bitset
alphabet characterμ μ€λΆ μ¬λΆ 체ν¬λ₯Ό μνμ¬ alphabet μ μμλλ‘ ν΄λΉ bit μ μ μ₯νκΈ°.
// "ab" μ κ²½μ°
a b c ... z
0 1 2 ... 26
1 1 0 ... 0
π‘ bitset κ° λμ (bitwise OR)
- ν΄λΉ
word
μμch
character λ¨μλ‘ μ²λ¦¬νλ©΄μ - ν΄λΉ ch μμΉλ₯Ό κ³μ° (
ch.charCodeAt(0) - 'a'.charCodeAt(0)
) ν΄μ - μμ chμ conflict κ° μμΌλ©΄ bitwise OR ν΄μ κ°μ λμ νκ³ μ΅μ’ return ν¨.
const getSet = (word) => {
let b = 0;
for (const ch of word) {
const d = ch.charCodeAt(0) - "a".charCodeAt(0);
if ((b & (1 << d)) > 0) return -1;
b |= 1 << d;
}
return b;
};
π‘ bitset νμΈ (bitwise AND)
- character μ conflict λΉκ΅λ character λ³λ‘ νλμ© λΉκ΅νλ κ²μ΄ μλλΌ bitsetμΌλ‘ λ³κ²½λ κ°μ bitwise and ν΄μ νμΈν μ μμ.
=== 0
: conflict μλ κ²½μ°> 0
: ν΄λΉ bit λ 1 μ΄ λλ―λ‘ 0 μ΄μμ κ°μ κ°κ² λ¨.
- conflict κ° μλ 쑰건 νμΈ
- ν΄λΉ word (
arr[index]
)μlookup[index]
κ° μ‘΄μ¬ν΄μΌνλ©° (word λ΄μ conflict κ° μλ€λ©΄ lookup μμ²΄κ° μ‘΄μ¬νμ§ μμ.) - κΈ°μ‘΄ bitset κ³Ό bitwise AND ν κ²°κ³Όκ° 0 μΌλ‘ conflict κ° μμ΄μΌ νλ€.
- ν΄λΉ word (
const dfs = (index, currentS, currentL) => {
...
// use
if (lookup[index] !== -1 && (currentS & lookup[index]) === 0) {
dfs(index + 1, currentS | lookup[index], currentL + arr[index].length)
}
}
π₯ My Solution
/**
* @param {string[]} arr
* @return {number}
*/
var maxLength = function (arr) {
const N = arr.length;
const lookup = [];
const getSet = (word) => {
let b = 0;
for (const ch of word) {
const d = ch.charCodeAt(0) - "a".charCodeAt(0);
if ((b & (1 << d)) > 0) return -1;
b |= 1 << d;
}
return b;
};
let max = -Infinity;
const dfs = (index, currentS, currentL) => {
if (index >= N) {
if (max < currentL) max = currentL;
return;
}
// not use
dfs(index + 1, currentS, currentL);
// use
if (lookup[index] !== -1 && (currentS & lookup[index]) === 0) {
dfs(index + 1, currentS | lookup[index], currentL + arr[index].length);
}
};
for (const word of arr) {
lookup.push(getSet(word));
}
dfs(0, 0, 0);
return max;
};