Leetcode第213周赛题解
1640. 能否连接形成数组
使用哈希表
class Solution {
public:
bool canFormArray(vector<int>& arr, vector<vector<int>>& pieces) {
unordered_map<int, int> dic;
for (int i = 0; i < pieces.size(); i++) {
dic[pieces[i][0]] = i;
}
for (int i = 0; i < arr.size();) {
if (dic.find(arr[i]) == dic.end()) return false;
auto& p = pieces[dic[arr[i]]];
for (int j = 0; j < p.size(); j++, i++) {
if (arr[i] != p[j]) return false;
}
}
return true;
}
};
暴力遍历方法
class Solution {
public:
bool canFormArray(vector<int>& arr, vector<vector<int>>& pieces) {
int i = 0;
while(i<arr.size()){
int j = 0;
for(; j<pieces.size(); j++){
if(pieces[j][0]==arr[i]){
int k = 0;
while(i<arr.size()&&k<pieces[j].size()){
if(pieces[j][k]!=arr[i]){
return false;
}
k++;
i++;
}
break;
}
if(j==pieces.size()-1){
return false;
}
}
}
return true;
}
};
1641. 统计字典序元音字符串的数目
组合计数方法
思路和 1621. 大小为 K 的不重叠线段的数目 是类似的。如果对「隔板法」很熟悉的读者肯定可以很快想到下面的数学方法。
假设我们选取的 \(\text{a, e, i, o, u}\)的个数分别为 \(a, e, i, o, u\)当我们确定了选取个数时,需要将这些字符按照字典序进行排序并构成字符串,因此一种选取方法恰好对应一个满足题目要求的字符串。因此我们就需要求处满足下面要求的五元组 \((a, e, i, o, u)\)的个数:
-
\(a, e, i, o, u\) 均为非负整数;
-
\(a+e+i+o+u=n\)
我们可以想象面前放了一排 \(n\)个小球,而我们需要使用 \(4\)个隔板,将小球分成\(5\)个部分,每一部分可以为空。\(n\)个小球可以有 n+1n+1 个可以放隔板的位置(包括它们之间的 \(n-1\) 个空隙位置,以及左右两端的\(2\)个位置)。我们将这 \(n+1\)个位置规定为 \([1, n+1]\)中的整数,如果这 \(4\)个隔板放置的位置为 \(b_0, b_1, b_2, b_3\) ,那么它们需要满足:
令 \(b_i' = b_i + i\),那么 \((b_0, b_1, b_2, b_3)\)与$ (b_0', b_1', b_2', b_3')$ 逐一对应,并且满足:
此时就可以使用组合求解方案数了,即在\([1,n+4]\)中选择 \(4\) 个整数,因此答案为:
递归方法
每一次枚举当前位置的可能性,当然,从上一个位置的地方开始
class Solution {
public:
int ans = 0;
void dfs(int now, int tot, int index)
{
if (index == tot) { ans ++; return;}
for (int i = now; i < 5; i ++ )
{
dfs(i, tot, index + 1);
}
}
int countVowelStrings(int n) {
dfs(0, n, 0);
return ans;
}
};
1642. 可以到达的最远建筑
优先队列法
假设有i
个bricks
和j
个梯子'ladders'
那么我们只需要维护一个优先队列,里面存着到当前位置为止的,前j
大差值的建筑
class Solution {
public:
int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
priority_queue<int, vector<int>, greater<int> > q;
int sumH;
for (int i = 1; i < heights.size(); i ++ )
{
int gapH = heights[i] - heights[i - 1];
if (gapH > 0)
{
q.push(gapH);
if (q.size() > ladders)
{
sumH += q.top();
q.pop();
}
if (sumH > bricks)
{
return i - 1; // 他还是当前位置,并没有到下一个i
}
}
}
return heights.size() - 1;
}
};
假设当前位置在(i,j),要到达$$(n,m)$$,那么方案数就是
如果我们往右移动,能么剩下可以选择的方案数就是
如果这些方案数是大于k的,说明往右走的方案中是包含第k
个方案的,只需要i++
如果是小于k的,说明要往下走,需要j++
,同时k的大小要减掉
重复上述步骤直到i==n
且j==m
class Solution {
public:
static const int maxn = 35;
long long C[maxn + 2][maxn + 2]; // long long + 两位
string kthSmallestPath(vector<int>& destination, int k) {
for (int i = 0; i <= maxn; i ++ )
{
// <= maxn
C[0][i] = 0;
C[i][0] = 1;
}
for (int i = 1; i <= maxn; i ++ )
{
for (int j = 1; j <= maxn; j ++ )
{
// i, j = 1开始
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]);
}
}
int n = destination[0];
int m = destination[1];
string ans;
int i = 0, j = 0; // 不能逗号赋值两个int i, j = 0
while (i < n && j < m)
{
int a = C[n - i + m - j - 1][n - i]; // 组合数是对称的, 且先往右走,而且每时每刻在变
if (a >= k)
{
ans += "H";
j ++ ;
}
else
{
ans += "V";
i ++;
k -= a; // k - a
// 是否会出现小于0的情况
}
}
while (i < n) i ++, ans += "V";
while (j < m) j ++, ans += "H";
return ans;
}
};