5499. 重复至少 K 次且长度为 M 的模式
知识点:枚举
这道题太直白了,没啥花里胡哨的东西,直接枚举起点,然后检查是否至少有 K 段重复即可。
class Solution {
public:
bool containsPattern(vector<int>& arr, int m, int k) {
for(int i = 0; i+m <= arr.size(); i++) {
int pre = i+m;
int hit = 0;
while(pre+m <= arr.size()) {
bool flag = true;
for(int p = 0; p < m; p++) {
if(arr[pre+p] != arr[i+p]) {
flag = false;
break;
}
}
if(flag) {
hit++;
pre += m;
} else {
break;
}
if(hit+1 >= k) {
return true;
}
}
}
return false;
}
};
5500. 乘积为正数的最长子数组长度
知识点:递推
设 POS[i] 是以 nums[i] 结尾,乘积为正的最长子数组的长度。
设 NEG[i] 是以 nums[i] 结尾,乘积为负的最长子数组的长度。
为了编写代码方便,设 nums 下标从 1 开始。那么 POS[0] = NEG[0] = 0。
接下来讨论一下 nums[i] 的值如何影响 POS[i] 及 NEG[i] 的计算。
- 当 nums[i] 为 0 时,显然有 POS[i] = NEG[i] = 0,即这样的子数组不存在。
- 当 nums[i] 为正时:
- POS[i] = POS[i-1] + 1。
- NEG[i] = NEG[i-1] ? (NEG[i-1] + 1) : 0。
为何计算NEG[i]时要判断 NEG[i-1] 不为 0 ?因为 nums[i] 自己没法成为一个乘积为负的数组。
- 当 nums[i] 为负时:
- POS[i] = NEG[i-1] ? (NEG[i-1] + 1) : 0。
判断 NEG[i-1] 是否为 0 的原因同上。 - NEG[i] = POS[i-1] + 1;
- POS[i] = NEG[i-1] ? (NEG[i-1] + 1) : 0。
int dp[100001][2]; // dp[i][0] 即 POS,dp[i][1] 即 NEG。
class Solution {
public:
int getMaxLen(vector<int>& nums) {
dp[0][0] = dp[0][1] = 0;
int anw = 0;
for(int i = 1; i <= nums.size(); i++) {
if(nums[i-1] == 0) {
dp[i][0] = 0;
dp[i][1] = 0;
} else if(nums[i-1] > 0) {
dp[i][0] = dp[i-1][0] + 1;
dp[i][1] = dp[i-1][1] ? (dp[i-1][1] + 1) : 0;
} else {
dp[i][0] = dp[i-1][1] ? (dp[i-1][1] + 1) : 0;
dp[i][1] = dp[i-1][0] + 1;
}
anw = max(anw, dp[i][0]);
}
return anw;
}
};
5501. 使陆地分离的最少天数
知识点:BFS,思维题
有个比较搞喜的地方:最多删除两次必可使陆地分离。
每个格子最多会有四条边和其他格子相连。在边上的格子最多有三条边。在角上的最多有两条边。无论岛屿长成什么样子,肯定是会有角的,所以最多只需删除两次。
首先,判断输入本身就是分离的。 其次,暴力枚举删除输入中的一个 1,然后判断是否分离。 再其次,直接返回 2 就 ok 啦~
class Solution {
public:
bool check(const vector<vector<int>>& grid) {
int x = 0, y = 0;
int cnt = 0;
for(int i = 0; i < grid.size(); i++) {
for(int j = 0; j < grid[i].size(); j++) {
if(grid[i][j] == 0) continue;
cnt++;
x = i;
y = j;
}
}
if(cnt == 0) {
return true;
}
queue<pair<int, int>> q;
bool mark[30][30] = {0};
q.push(make_pair(x, y));
mark[x][y] = true;
cnt--;
while(q.empty() == false) {
auto f = q.front();
q.pop();
int dx[] = {-1, 1, 0, 0};
int dy[] = { 0, 0, -1, 1};
for(int i = 0; i < 4; i++) {
int nx = dx[i] + f.first;
int ny = dy[i] + f.second;
if(0 <= nx && nx < grid.size() && 0 <= ny && ny < grid[0].size() && grid[nx][ny] == 1) {
auto p = make_pair(nx, ny);
if(mark[nx][ny]) { continue; }
mark[nx][ny] = true;
q.push(p);
cnt--;
}
}
}
return cnt != 0;
}
int minDays(vector<vector<int>>& grid) {
if(check(grid)) {
return 0;
}
for(int i = 0; i < grid.size(); i++) {
for(int j = 0; j < grid[0].size(); j++) {
if(grid[i][j] == 0) {
continue;
}
grid[i][j] = 0;
if(check(grid)) {
return 1;
}
grid[i][j] = 1;
}
}
return 2;
}
};
5502. 将子数组重新排序得到同一个二叉查找树的方案数
知识点:二叉搜索树;排列组合
二叉查找树,又称二叉排序树,二叉搜索树。其特点是,右子树中的元素都小于根节点,左子树的元素都大于根节点,且左右子树也都是二叉搜索树。当构造一棵二叉搜索树时,第一个插入的元素必然是根节点,其后插入的元素根据与根节点的大小关系被插入到左子树或右子树。
由此可知,如果两种排列对应的二叉搜索树相同,那么必然第一个元素是相同的。
设,小于第一个的元素构成的序列为 less,大于第一个的元素构成的序列为 greater。在不修改 less,greater 内部顺序的前提下,调整 less + greater 这个大序列的顺序,就能得到一个可以构造相同二叉树的新序列。
换个说法,less 的顺序确定了元素插入左子树的顺序,同样的,greater 确定了元素插入右子树的顺序。至于,是先构造左子树还是构造右子树,并不重要。所以 less + greater 的顺序可以调整。
那为何 less 和 greater 的内部顺序不能调整呢?其实不是不能调整,而是要放到构造左右子树的时候再去调整。
那么,还剩最后一个问题,less + greater,一共有多少符合要求排列方式呢?答案为 。也就是说,一共有 x 个坑,先选出一部分放 less,剩下的放 greater。
最后将每个子树的组合数累乘即可。
const int64_t mod = 1000000007;
class Solution {
public:
int64_t com[1001][1001];
int64_t combine(int a, int b) {
//cout << a << " " << b << " " << com[a][b] << endl;
return com[a][b];
}
void dfs(const vector<int> &num, int L, int R, int64_t &mul) {
if(R-L+1 <= 2) {
return;
}
vector<int> less, greater;
for(int i = L+1; i <= R; i++) {
if(num[i] < num[L]) {
less.push_back(num[i]);
} else {
greater.push_back(num[i]);
}
}
mul *= combine(greater.size() + less.size(), greater.size());
if(mul >= mod) {
mul %= mod;
}
dfs(less, 0, less.size()-1, mul);
dfs(greater, 0, greater.size()-1, mul);
}
int numOfWays(vector<int>& nums) {
//C(n,m)=C(n-1,m)+C(n-1,m-1)
com[1][0]=com[1][1]=1;
for(int i=2;i<=1000;i++){
com[i][0]=1;
for(int j=1;j<=i;j++)
com[i][j]=(com[i-1][j]+com[i-1][j-1]) % mod;
}
int64_t mul = 1;
dfs(nums, 0, nums.size()-1, mul);
return (mul - 1 + mod) % mod;
}
};