[Algo] 路径信息
1. 最长公共子序列
// 1. 最长公共子序列
// https://www.nowcoder.com/practice/4727c06b9ee9446cab2e859b4bb86bb8
void dp1(string& s1, string& s2, vector<vector<int>>& dp) {
int len1 = s1.length(), len2 = s2.length();
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++) {
if (s1[i - 1] == s2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
string lcs(string& s1, string& s2) {
int len1 = s1.length(), len2 = s2.length();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1));
dp1(s1, s2, dp); //构建动态规划表
int length = dp[len1][len2], i = len1, j = len2;
string ans;
ans.resize(length);
while (length > 0) {
if (s1[i - 1] == s2[j - 1]) {
ans[--length] = s1[i - 1];
i--;
j--;
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
i--;
} else {
j--;
}
}
return ans;
}
2. 最小的必要团队
// 2. 最小的必要团队
// https://leetcode.cn/problems/smallest-sufficient-team/
int dp2(vector<int> &people_skills, int n, int m, int i, int status, vector<vector<int>> &dp) {
if (status == (1 << n) - 1) return 0;
if (i == m) return INT32_MAX - 1;
if (dp[i][status] != -1) return dp[i][status];
int p1 = dp2(people_skills, n, m, i + 1, status, dp);
int p2 = 1 + dp2(people_skills, n, m, i + 1, status | people_skills[i], dp);
int ans = min(p1, p2);
dp[i][status] = ans;
return ans;
}
vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
int n = req_skills.size(), m = people.size();
unordered_map<string, int> skills_map;
for (int i = 0; i < n; i++) skills_map[req_skills[i]] = i;
vector<int> people_skills(m);
for (int i = 0; i < m; i++) {
int status = 0;
for (int j = 0; j < people[i].size(); j++) {
if (skills_map.count(people[i][j])) status |= 1 << skills_map[people[i][j]];
}
people_skills[i] = status;
}
vector<vector<int>> dp(m, vector<int>(1 << n, -1));
int num = dp2(people_skills, n, m, 0, 0, dp); // 构建动态规划表
vector<int> ans(num);
int count = 0, status = 0, i = 0;
while (count < num) {
if (i != m - 1 && dp[i][status] == dp[i + 1][status]) i++;
else {
ans[count++] = i;
status |= people_skills[i];
i++;
}
}
return ans;
}
3. 最长递增子序列
// 3. 最长递增子序列
// https://www.nowcoder.com/practice/30fb9b3cab9742ecae9acda1c75bf927
int find(vector<int> &ends, int len, int num) {
int l = 0, r = len - 1, ans = -1;
while (l <= r) {
int m = (l + r) / 2;
if (ends[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
int dp3(vector<int> &arr, vector<int> &dp) {
int n = arr.size(), len = 0;
vector<int> ends(n);
for (int i = 0; i < n; i++) {
int pos = find(ends, len, arr[i]);
if (pos == -1) {
ends[len++] = arr[i];
dp[i] = len;
} else {
ends[pos] = arr[i];
dp[i] = pos + 1;
}
}
return len;
}
vector<int> lis(vector<int> &arr) {
int n = arr.size();
vector<int> dp(n);
int len = dp3(arr, dp);
vector<int> ans(len);
for (int i = n - 1, cur = len; i >= 0; i--) {
if (dp[i] == cur) {
ans[cur - 1] = arr[i];
cur--;
}
}
return ans;
}