题目
给你一个整数 n 和一个下标从 0 开始的字符串数组 words ,和一个下标从 0 开始的数组 groups ,两个数组长度都是 n 。
两个长度相等字符串的 汉明距离 定义为对应位置字符 不同 的数目。
你需要从下标 [0, 1, …, n - 1] 中选出一个 最长子序列 ,将这个子序列记作长度为 k 的 [i0, i1, …, ik - 1] ,它需要满足以下条件:
相邻 下标对应的 groups 值 不同。即,对于所有满足 0 < j + 1 < k 的 j 都有 groups[ij] != groups[ij + 1] 。
对于所有 0 < j + 1 < k 的下标 j ,都满足 words[ij] 和 words[ij + 1] 的长度 相等 ,且两个字符串之间的 汉明距离 为 1 。
请你返回一个字符串数组,它是下标子序列 依次 对应 words 数组中的字符串连接形成的字符串数组。如果有多个答案,返回任意一个。
子序列 指的是从原数组中删掉一些(也可能一个也不删掉)元素,剩余元素不改变相对位置得到的新的数组。
注意:words 中的字符串长度可能 不相等 。
提取题目中的重要信息
这一题的题意来说还是要从原始的数组当中选择出一个最长子串,使得其满足:
1.相邻两元素group不同;
2.相邻两元素长度相同但是hamming距离为1;
相对于2900. 最长相邻不相等子序列 I多了第二个限制条件。
这是一个典型的动态规划的题目。
思路
子序列+考虑相邻元素:枚举选哪个。
动态规划本质性的解题步骤:
1.dp数组的定义以及下标的含义
对于本题,定义f[i]表示从下表i~n-1中选出的最短子序列的长度。
2.递推公式(一般是自己找规律得到的)
当满足条件相邻两元素group不同和相邻两元素长度相同但是hamming距离为1时,
若这个f[j]>f[i],说明最长相邻不相等子序列需要更新,则
f[i] = f[j]
from[i] = j
所以最长子序列是max(f)
3.dp数组如何初始化(前提是想清楚1)
设初始值 f[i]=1,表示选择它自己作为子序列。
4.遍历顺序
一维数组,本题无需考虑遍历顺序。可以尝试从0 ~ n-1遍历、从n-1 ~ 0遍历,看看区别。
5.打印dp数组(用于检查是哪里有问题)
可以自行编写代码根据自己的思路进行检查
代码
从n-1~0遍历
class Solution {
public:
//判断输入是否满足相邻两元素group不同和相邻两元素长度相同但是hamming距离为1
bool Judge(string &s, string &t) {
if (s.length() != t.length()) {
return false;
}
bool diff = false;
for (int i = 0; i < s.length(); i++) {
if (s[i] != t[i]) {
if (diff) return false;
diff = true;
}
}
return diff;
}
public:
vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) {
vector<int> f(n,1);//定义DP数组
vector<int> from(n);//记录流转过程
int mx = n - 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = i + 1; j < n; j++) {
if (f[j] + 1 > f[i] && groups[j] != groups[i] && Judge(words[i], words[j])) {
f[i] = f[j] + 1;//i>j,所以从i开始的最长子序列应该更新为从j开始的最长子序列,因为words[i]满足条件,所以最长子序列的长度+1,相当于将words[i]放入结果集中
from[i] = j;//从i开始的最长相邻不相等子序列来自从j开始的最长子序列
}
}
//求最长子序列对应的开始字符的下标
if (f[i] > f[mx]) {
mx = i;
}
}
int m = f[mx];
vector<string> ans(m);
// 追根溯源,一个一个回溯找到ans[i]的值
for (int i = 0; i < m; i++) {
ans[i] = words[mx];
mx = from[mx];
}
return ans;
}
};
从0~n-1遍历
class Solution {
public:
bool Judge(string &s, string &t) {
if (s.length() != t.length()) {
return false;
}
bool diff = false;
for (int i = 0; i < s.length(); i++) {
if (s[i] != t[i]) {
if (diff) return false;
diff = true;
}
}
return diff;
}
public:
vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) {
vector<int> f(n,1);
vector<int> from(n);
int mx = n-1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (f[j] + 1 > f[i] && groups[j] != groups[i] && Judge(words[i], words[j])) {
f[i] = f[j] + 1;
from[i] = j;
}
}
if (f[i] > f[mx]) {
mx = i;
}
}
int m = f[mx];
vector<string> ans(m);
for (int i = m-1; i >= 0; i--) {
ans[i] = words[mx];
mx = from[mx];
}
return ans;
}
};