这是我参与「第四届青训营 」笔记创作活动的第9天
6148. 矩阵中的局部最大值
给你一个大小为 n x n 的整数矩阵 grid 。
生成一个大小为 (n - 2) x (n - 2) 的整数矩阵 maxLocal ,并满足:
maxLocal[i][j]等于grid中以i + 1行和j + 1列为中心的3 x 3矩阵中的 最大值 。
换句话说,我们希望找出 grid 中每个 3 x 3 矩阵中的最大值。
返回生成的矩阵。
输入:grid = [[9,9,8,1],[5,6,2,6],[8,2,6,4],[6,2,2,2]]
输出:[[9,9],[8,6]]
解释:原矩阵和生成的矩阵如上图所示。
注意,生成的矩阵中,每个值都对应 grid 中一个相接的 3 x 3 矩阵的最大值。
提示:
n == grid.length == grid[i].length3 <= n <= 1001 <= grid[i][j] <= 100
思路分析:签到题,根据100的数据量直接暴力即可。
class Solution {
public:
vector<vector<int>> largestLocal(vector<vector<int>>& grid) {
vector<vector<int>> res;
int n = grid.size();
for (int i = 0; i < n - 2; i ++ ) {
vector<int> t;
for (int j = 0; j < n - 2; j ++ ) {
int num = 0;
for (int a = i; a < 3 + i; a ++ )
for (int b = j; b < 3 + j; b ++ )
num = max(num,grid[a][b]);
t.push_back(num);
}
res.push_back(t);
}
return res;
}
};
6149. 边积分最高的节点
给你一个有向图,图中有 n 个节点,节点编号从 0 到 n - 1 ,其中每个节点都 恰有一条 出边。
图由一个下标从 0 开始、长度为 n 的整数数组 edges 表示,其中 edges[i] 表示存在一条从节点 i 到节点 edges[i] 的 有向 边。
节点 i 的 边积分 定义为:所有存在一条指向节点 i 的边的节点的 编号 总和。
返回 边积分 最高的节点。如果多个节点的 边积分 相同,返回编号 最小 的那个。
示例 1:
输入:edges = [1,0,0,0,0,7,7,5]
输出:7
解释:
- 节点 1、2、3 和 4 都有指向节点 0 的边,节点 0 的边积分等于 1 + 2 + 3 + 4 = 10 。
- 节点 0 有一条指向节点 1 的边,节点 1 的边积分等于 0 。
- 节点 7 有一条指向节点 5 的边,节点 5 的边积分等于 7 。
- 节点 5 和 6 都有指向节点 7 的边,节点 7 的边积分等于 5 + 6 = 11 。
节点 7 的边积分最高,所以返回 7 。
提示:
n == edges.length2 <= n <= 1050 <= edges[i] < nedges[i] != i
思路分析: 依据题意,要求我们找出每个点指向自己的权值,这里的权值就是点的数值。那我们可以直接开始搜索,然后只需要用一个数组存起来每个点指向自己的权值和,最后遍历一遍数组找出答案即可。由于每个点只搜到了一遍,所以时间复杂度为O(n).
class Solution {
public:
long long res[200010];
bool st[200010];
vector<int> e;
void dfs(int u) {
if (st[u]) return ;
st[u] = 1;
int t = e[u];
if (t == -1) return;
res[t] += u;
if (!st[t]) dfs(t);
}
int edgeScore(vector<int>& edges) {
e = edges;
int n = e.size();
for (int i = 0; i < n; i ++ ) {
dfs(i);
}
long long ans = 0,root = 0;
for (int i = 0; i < n; i ++ ) {
if (res[i] > ans){
ans = res[i];
root = i;
}
}
return root;
}
};
6150. 根据模式串构造最小数字
给你下标从 0 开始、长度为 n 的字符串 pattern ,它包含两种字符,'I' 表示 上升 ,'D' 表示 下降 。
你需要构造一个下标从 0 开始长度为 n + 1 的字符串,且它要满足以下条件:
num包含数字'1'到'9',其中每个数字 至多 使用一次。- 如果
pattern[i] == 'I',那么num[i] < num[i + 1]。 - 如果
pattern[i] == 'D',那么num[i] > num[i + 1]。
请你返回满足上述条件字典序 最小 的字符串 **num。
示例 1:
输入: pattern = "IIIDIDDD"
输出: "123549876"
解释: 下标 0 ,1 ,2 和 4 处,我们需要使 num[i] < num[i+1] 。
下标 3 ,5 ,6 和 7 处,我们需要使 num[i] > num[i+1] 。
一些可能的 num 的值为 "245639871" ,"135749862" 和 "123849765" 。
"123549876" 是满足条件最小的数字。
注意,"123414321" 不是可行解因为数字 '1' 使用次数超过 1 次。
提示:
1 <= pattern.length <= 8pattern只包含字符'I'和'D'。
思路分析: 依据题意,我们需要根据所给的字符串pattern求出满足要求的答案,这个题目好像又结论,但是看完数据量后发现不需要猜结论,题目的数据范围只有8,那我们直接构造全排列答案的计算量也才36w+,每次求出一个答案后再check一下看看是否满足情况,并且由于我们搜的顺序是按字典序大小,所以搜到的第一个答案就是最优解。
class Solution {
public:
bool st[10];
string res,p;
int n;
bool flag = 0;
bool check(string t) {
for (int i = 0; i < n; i ++ ) {
int a = t[i] - '0',b = t[i + 1] - '0';
if (p[i] == 'I') {
if (a >= b) return false;
}
else {
if (a <= b) return false;
}
}
return true;
}
bool dfs(int u,string t){
if (u > n) {
if(check(t)) {
res = t;
return true;
}
return false;
}
for (int i = 1; i <= n + 1; i ++ ) {
if (!st[i]) {
st[i] = 1;
if (dfs(u + 1,t + to_string(i))) return true;
st[i] = 0;
}
}
return false;
}
string smallestNumber(string pattern) {
p = pattern;
n = p.size();
dfs(0,"");
return res;
}
};
6151. 统计特殊整数
如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。
给你一个 正 整数 n ,请你返回区间 **[1, n] 之间特殊整数的数目。
示例 1:
输入: n = 20
输出: 19
解释: 1 到 20 之间所有整数除了 11 以外都是特殊整数。所以总共有 19 个特殊整数。
示例 2:
输入: n = 5
输出: 5
解释: 1 到 5 所有整数都是特殊整数。
示例 3:
输入: n = 135
输出: 110
解释: 从 1 到 135 总共有 110 个整数是特殊整数。
不特殊的部分数字为:22 ,114 和 131 。
提示:
1 <= n <= 2 * 10e9
思路分析:题意很好理解,就那么回事。这是一个数位dp的问题,在这里我们先把n有多少位取出来,然后根据位数来计算答案。把位数取出来后,我们可以把总数分为两大部分来考虑,第一部分是小于n位的位次的,第二部分和n同以位次的。他俩总和就是答案。
第一部分: 这一部分很好求,我们举个例子来解释:当n=23104时,n有5位,那我们可以先求出他只有1,2,3,4位的情况。
比如我们再求4位的情况,(这里有点容斥原理的内容)
第一位可以选1-9,但是0不能选,因此能选9个。
第二位可以选0-9,但是需要减去第一位选的数,因此只能选9个。
第三位可以选0-9,但是需要减去前两位选的数,因此只能选8个。
第四位可以选0-9,但是需要减去前两位选的数,因此只能选7个。
所以sum = 9 * 9 * 8 * 7
其他位次也一样...
第二部分: 这一部分就比较难了,还是用上面那个例子:当n=23104时,选五位的情况。 因为我们只能统计小于n的,所以我们每一次位次最多等于当前的值。比如第一位次时2,那么我此时只能选择1和2的情况,再第三次位,我只能选择0这种情况。
好那么我们就可以根据上面的分法来求出答案(画到纸上会发现这其实是一棵树)
在第一位次时,我只能选择1和2,当选1时:那我们就回到上面那种计算的情况了,可求出当选1时,sum = 9 * 8 * 7 * 6,当选择2时,我们就直接跳转考虑第二位的情况。
在第二位次时,我们就可以选择0,1,2,3这些情况,但是由于之前选过1了,所以我们需要用st数组记录选过了哪些数字。
以此类推....
最后我们加上两部分的和,最后我们需要判断一下n是否也位合法情况,如果是就最后答案+1。 至此题目分析完毕,由于我们每次只选进了一个数而已,因此时间复杂度为O(n)
class Solution {
public:
bool st[10];
int countSpecialNumbers(int n) {
vector<int> nums;
while(n) {
nums.push_back(n % 10);
n /= 10;
}
reverse(nums.begin(),nums.end());
int res = 0;
for (int i = 1; i < nums.size(); i ++ ) {
int t = 9;
for (int j = 0,k = 9; j < i - 1; k -- ,j ++ )
t *= k;
res += t;
}
for (int i = 0; i < nums.size(); i ++ ) {
for (int j = !i; j < nums[i]; j ++ ) {
if (st[j]) continue;
int t = 1;
for (int k = 0,u = 9 - i; k < nums.size() - i - 1; k ++ ,u -- )
t *= u;
res += t;
}
if(st[nums[i]]) break;
st[nums[i]] = 1;
}
set<int> h(nums.begin(),nums.end());
if (h.size() == nums.size()) res ++;
return res;
}
};