「知识点:暴力」
因为 arr 和 pieces 中都不包含重复的数字
,所以直接在pieces中暴力寻找 arr[i] 即可,然后连续的元素是否相同即可。
class Solution {
public:
bool canFormArray(vector<int>& arr, vector<vector<int>>& pieces) {
for (int i = 0; i < arr.size();) {
int cur = i;
for (int j = 0; j < pieces.size(); j++) {
// 在 pieces 中寻找 arr[i]
if (pieces[j][0] == arr[i]) {
bool flag = true;
// 检查连续的元素是否都相等
for (int k = 0; k < pieces[j].size() && flag; k++) {
if (pieces[j][k] != arr[i+k]) {
flag = false;
}
}
if (flag == false) {
return false;
}
i += pieces[j].size();
break;
}
}
if (cur == i) {
return false;
}
}
return true;
}
};
「知识点:排列组合,递推」
设 f(i,j) 表示长度为 i,以字符 j 结尾的字符串数量。根据题目要求,可以得出如下式子:
class Solution {
public:
int dp[51][5] = {0};
int countVowelStrings(int n) {
dp[1][0] = dp[1][1] = dp[1][2] = dp[1][3] = dp[1][4] = 1;
for (int i = 2; i <= n; i++) {
for(int j = 0; j <= 4; j++) {
for(int k = 0; k <= j; k++) {
dp[i][j] += dp[i-1][k];
}
}
}
return dp[n][0] + dp[n][1] + dp[n][2] + dp[n][3] + dp[n][4];
}
};
可以用高中时的隔板法来考虑这个问题。现在有 n 个小球排成一排,要用四块隔板将其分成五份
,每一份均可为空
,从前向后分别对应着a,e,i,o,u。
n 个小球,一共有 n+1 个缝隙可以放入隔板,设这 n+1 个位置对应 [1, n+1] 中的数字,四个隔板放置的位置为
,并满足如下关系:
。
令
, 则每一种放置方案
都有
与之一一对应,且满足如下关系:
也就是在 n+4 个数字中选取 4 个不同的数字,即
。
class Solution {
public:
int countVowelStrings(int n) {
return (n + 4) * (n + 3) * (n + 2) * (n + 1) / 24;
}
};
「知识点:贪心,排序」
假设移动到下一个建筑时,需要消耗一架梯子
或者若干块砖
,那么该如何抉择呢?
可以使用贪心
的思维来考虑:梯子相当于不可拆分的无限块砖
,应该用在高度差最大的地方
。换言之,如果有 k 个梯子,应该优先用在高度差最大的k次移动
,剩下的地方用砖补齐。
从前向后遍历 heights,遍历过程中使用优先队列维护最大的 k 个高度差,当其他高度差的累加和超过砖数时,就到达了可以最远建筑。
class Solution {
public:
int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
priority_queue<int, vector<int>, greater<int>> q;
int sum = 0;
for (int i = 1; i < heights.size(); ++i) {
if (heights[i] - heights[i - 1] > 0) {
q.push(heights[i] - heights[i - 1]);
if (q.size() > ladders) {
sum += q.top();
q.pop();
}
if (sum > bricks) {
return i - 1;
}
}
}
return heights.size() - 1;
}
};
「知识点:组合数」
一共要发送row 次 'H' 指令,cloumn 次 'V' 指令
,
因此有
种不同的指令集。
因为 'H' < 'V',所以有:
个指令集。
个指令集。
所以可以比较
和 k 的大小关系,来决定应该选取哪个指令。
依此类推,我们得到了一个递归的解法,设 f(row, column, k) 为第 k 个字符串,则有:
组合数的计算也可以借助下述递归公式来完成~
class Solution {
public:
int mat[100][100];
int calc(int n, int m) {
if (m == 0 || m == n) {
return 1;
}
if (mat[n][m] != -1) {
return mat[n][m];
}
mat[n][m] = calc(n-1, m) + calc(n-1, m-1);
return mat[n][m];
}
int combine(int H, int V) {
int n = H+V;
int m = V;
return calc(n, m);
}
std::string dfs(int H, int V, int k) {
if (H == 0 && V == 0) {
return "";
}
if (H == 0) {
return std::string(V, 'V');
}
if (V == 0) {
return std::string(H, 'H');
}
int cnt = combine(H-1, V);
if (k <= cnt) {
return "H" + dfs(H-1, V, k);
}
return "V" + dfs(H, V-1, k - cnt);
}
string kthSmallestPath(vector<int>& destination, int k) {
memset(mat, -1, sizeof(mat));
return dfs(destination[1], destination[0], k);
}
};