comments | difficulty | edit_url | rating | source | tags | |||
---|---|---|---|---|---|---|---|---|
true |
Medium |
1898 |
Biweekly Contest 115 Q3 |
|
You are given a string array words
, and an array groups
, both arrays having length n
.
The hamming distance between two strings of equal length is the number of positions at which the corresponding characters are different.
You need to select the longest subsequence from an array of indices [0, 1, ..., n - 1]
, such that for the subsequence denoted as [i0, i1, ..., ik-1]
having length k
, the following holds:
- For adjacent indices in the subsequence, their corresponding groups are unequal, i.e.,
groups[ij] != groups[ij+1]
, for eachj
where0 < j + 1 < k
. words[ij]
andwords[ij+1]
are equal in length, and the hamming distance between them is1
, where0 < j + 1 < k
, for all indices in the subsequence.
Return a string array containing the words corresponding to the indices (in order) in the selected subsequence. If there are multiple answers, return any of them.
Note: strings in words
may be unequal in length.
Example 1:
Input: words = ["bab","dab","cab"], groups = [1,2,2]
Output: ["bab","cab"]
Explanation: A subsequence that can be selected is [0,2]
.
groups[0] != groups[2]
words[0].length == words[2].length
, and the hamming distance between them is 1.
So, a valid answer is [words[0],words[2]] = ["bab","cab"]
.
Another subsequence that can be selected is [0,1]
.
groups[0] != groups[1]
words[0].length == words[1].length
, and the hamming distance between them is1
.
So, another valid answer is [words[0],words[1]] = ["bab","dab"]
.
It can be shown that the length of the longest subsequence of indices that satisfies the conditions is 2
.
Example 2:
Input: words = ["a","b","c","d"], groups = [1,2,3,4]
Output: ["a","b","c","d"]
Explanation: We can select the subsequence [0,1,2,3]
.
It satisfies both conditions.
Hence, the answer is [words[0],words[1],words[2],words[3]] = ["a","b","c","d"]
.
It has the longest length among all subsequences of indices that satisfy the conditions.
Hence, it is the only answer.
Constraints:
1 <= n == words.length == groups.length <= 1000
1 <= words[i].length <= 10
1 <= groups[i] <= n
words
consists of distinct strings.words[i]
consists of lowercase English letters.
We define
In addition, we define a variable
We traverse
Finally, we find the index
The time complexity is
class Solution:
def getWordsInLongestSubsequence(
self, n: int, words: List[str], groups: List[int]
) -> List[str]:
def check(s: str, t: str) -> bool:
return len(s) == len(t) and sum(a != b for a, b in zip(s, t)) == 1
f = [1] * n
g = [-1] * n
mx = 1
for i, x in enumerate(groups):
for j, y in enumerate(groups[:i]):
if x != y and f[i] < f[j] + 1 and check(words[i], words[j]):
f[i] = f[j] + 1
g[i] = j
mx = max(mx, f[i])
ans = []
for i in range(n):
if f[i] == mx:
j = i
while j >= 0:
ans.append(words[j])
j = g[j]
break
return ans[::-1]
class Solution {
public List<String> getWordsInLongestSubsequence(int n, String[] words, int[] groups) {
int[] f = new int[n];
int[] g = new int[n];
Arrays.fill(f, 1);
Arrays.fill(g, -1);
int mx = 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (groups[i] != groups[j] && f[i] < f[j] + 1 && check(words[i], words[j])) {
f[i] = f[j] + 1;
g[i] = j;
mx = Math.max(mx, f[i]);
}
}
}
List<String> ans = new ArrayList<>();
for (int i = 0; i < n; ++i) {
if (f[i] == mx) {
for (int j = i; j >= 0; j = g[j]) {
ans.add(words[j]);
}
break;
}
}
Collections.reverse(ans);
return ans;
}
private boolean check(String s, String t) {
if (s.length() != t.length()) {
return false;
}
int cnt = 0;
for (int i = 0; i < s.length(); ++i) {
if (s.charAt(i) != t.charAt(i)) {
++cnt;
}
}
return cnt == 1;
}
}
class Solution {
public:
vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) {
auto check = [](string& s, string& t) {
if (s.size() != t.size()) {
return false;
}
int cnt = 0;
for (int i = 0; i < s.size(); ++i) {
cnt += s[i] != t[i];
}
return cnt == 1;
};
vector<int> f(n, 1);
vector<int> g(n, -1);
int mx = 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (groups[i] != groups[j] && f[i] < f[j] + 1 && check(words[i], words[j])) {
f[i] = f[j] + 1;
g[i] = j;
mx = max(mx, f[i]);
}
}
}
vector<string> ans;
for (int i = 0; i < n; ++i) {
if (f[i] == mx) {
for (int j = i; ~j; j = g[j]) {
ans.emplace_back(words[j]);
}
break;
}
}
reverse(ans.begin(), ans.end());
return ans;
}
};
func getWordsInLongestSubsequence(n int, words []string, groups []int) []string {
check := func(s, t string) bool {
if len(s) != len(t) {
return false
}
cnt := 0
for i := range s {
if s[i] != t[i] {
cnt++
}
}
return cnt == 1
}
f := make([]int, n)
g := make([]int, n)
for i := range f {
f[i] = 1
g[i] = -1
}
mx := 1
for i, x := range groups {
for j, y := range groups[:i] {
if x != y && f[i] < f[j]+1 && check(words[i], words[j]) {
f[i] = f[j] + 1
g[i] = j
if mx < f[i] {
mx = f[i]
}
}
}
}
ans := make([]string, 0, mx)
for i, x := range f {
if x == mx {
for j := i; j >= 0; j = g[j] {
ans = append(ans, words[j])
}
break
}
}
for i, j := 0, len(ans)-1; i < j; i, j = i+1, j-1 {
ans[i], ans[j] = ans[j], ans[i]
}
return ans
}
function getWordsInLongestSubsequence(n: number, words: string[], groups: number[]): string[] {
const f: number[] = Array(n).fill(1);
const g: number[] = Array(n).fill(-1);
let mx = 1;
const check = (s: string, t: string) => {
if (s.length !== t.length) {
return false;
}
let cnt = 0;
for (let i = 0; i < s.length; ++i) {
if (s[i] !== t[i]) {
++cnt;
}
}
return cnt === 1;
};
for (let i = 0; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (groups[i] !== groups[j] && f[i] < f[j] + 1 && check(words[i], words[j])) {
f[i] = f[j] + 1;
g[i] = j;
mx = Math.max(mx, f[i]);
}
}
}
const ans: string[] = [];
for (let i = 0; i < n; ++i) {
if (f[i] === mx) {
for (let j = i; ~j; j = g[j]) {
ans.push(words[j]);
}
break;
}
}
return ans.reverse();
}
impl Solution {
pub fn get_words_in_longest_subsequence(
n: i32,
words: Vec<String>,
groups: Vec<i32>,
) -> Vec<String> {
fn check(s: &str, t: &str) -> bool {
s.len() == t.len() && s.chars().zip(t.chars()).filter(|(a, b)| a != b).count() == 1
}
let n = n as usize;
let mut f = vec![1; n];
let mut g = vec![-1; n];
let mut mx = 1;
for i in 0..n {
let x = groups[i] as usize;
for j in 0..i {
let y = groups[j] as usize;
if x != y && f[i] < f[j] + 1 && check(&words[i], &words[j]) {
f[i] = f[j] + 1;
g[i] = j as i32;
mx = mx.max(f[i]);
}
}
}
let mut ans = vec![];
let mut i = n - 1;
while f[i] != mx {
i -= 1;
}
let mut j = i as i32;
while j >= 0 {
ans.push(words[j as usize].clone());
j = g[j as usize];
}
ans.reverse();
ans
}
}
In Solution 1, we need to enumerate all
class Solution {
public List<String> getWordsInLongestSubsequence(int n, String[] words, int[] groups) {
int[] dp = new int[n];
int[] next = new int[n];
Map<String, List<Integer>> strToIdxMap = new HashMap<>();
int maxIdx = n;
for (int i = n - 1; i >= 0; i--) {
int prevIdx = n;
char[] word = words[i].toCharArray();
for (int j = 0; j < word.length; j++) {
// convert word to pattern with '*'.
char temp = word[j];
word[j] = '*';
String curr = new String(word);
// search matches and update dp.
List<Integer> prevList = strToIdxMap.getOrDefault(curr, List.of());
for (int prev : prevList) {
if (groups[prev] == groups[i] || dp[prev] < dp[i]) {
continue;
}
dp[i] = dp[prev] + 1;
prevIdx = prev;
}
// append current pattern to dictionary.
strToIdxMap.computeIfAbsent(curr, k -> new ArrayList<>()).add(i);
// restore pattern to orignal word.
word[j] = temp;
}
if (maxIdx >= n || dp[i] > dp[maxIdx]) {
maxIdx = i;
}
next[i] = prevIdx;
}
int curr = maxIdx;
List<String> ans = new ArrayList<>();
while (curr < n) {
ans.add(words[curr]);
curr = next[curr];
}
return ans;
}
}