2397. 被列覆盖的最多行数
给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix ;另给你一个整数 numSelect,表示你必须从 matrix 中选择的 不同 列的数量。
如果一行中所有的 1 都被你选中的列所覆盖,则认为这一行被 覆盖 了。
形式上,假设 s = {c1, c2, …, cnumSelect} 是你选择的列的集合。对于矩阵中的某一行 row ,如果满足下述条件,则认为这一行被集合 s 覆盖:
对于满足 matrix[row][col] == 1 的每个单元格 matrix[row][col](0 <= col <= n - 1),col 均存在于 s 中,或者
row 中 不存在 值为 1 的单元格。
你需要从矩阵中选出 numSelect 个列,使集合覆盖的行数最大化。
返回一个整数,表示可以由 numSelect 列构成的集合 覆盖 的 最大行数 。
示例 1:
输入:matrix = [[0,0,0],[1,0,1],[0,1,1],[0,0,1]], numSelect = 2
输出:3
解释:
图示中显示了一种覆盖 3 行的可行办法。
选择 s = {0, 2} 。
- 第 0 行被覆盖,因为其中没有出现 1 。
- 第 1 行被覆盖,因为值为 1 的两列(即 0 和 2)均存在于 s 中。
- 第 2 行未被覆盖,因为 matrix[2][1] == 1 但是 1 未存在于 s 中。
- 第 3 行被覆盖,因为 matrix[2][2] == 1 且 2 存在于 s 中。
因此,可以覆盖 3 行。
另外 s = {1, 2} 也可以覆盖 3 行,但可以证明无法覆盖更多行。
示例 2:
输入:matrix = [[1],[0]], numSelect = 1
输出:2
解释:
选择唯一的一列,两行都被覆盖了,因为整个矩阵都被覆盖了。
所以我们返回 2 。
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 12
matrix[i][j] 要么是 0 要么是 1
1 <= numSelect <= n
二进制枚举(灵神题解):
class Solution {
public:int maximumRows(vector<vector<int>> &mat, int numSelect) {int m = mat.size(), n = mat[0].size();vector<int> mask(m);for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {mask[i] |= mat[i][j] << j;}}int ans = 0;for (int subset = 0; subset < (1 << n); subset++) {if (__builtin_popcount(subset) == numSelect) {int covered_rows = 0;for (int row : mask) {if ((row & subset) == row) {covered_rows++;}}ans = max(ans, covered_rows);}}return ans;}
};
而我的代码时间和空间占用都太高了,虽然是比较直观的:
class Solution {
public:int maximumRows(vector<vector<int>>& mat, int cols) {int m = mat.size(), n = mat[0].size();if(cols == n) return m;int ans = 0;vector<int> tmp;for(int i = 0; i < m; i++) {int num = 0;for(int j = 0; j < n; j++) {if(mat[i][j]) num++;}tmp.push_back(num);}for(int i = 1; i < (1<<n); i++) {vector<int> v;int k = i;for(int j = 0; j < n && k > 0; j++) {if(k & 1) v.push_back(j);k >>= 1;}if(v.size() == cols) {int res = 0;for(int t = 0; t < m; t++) {if(tmp[t] > cols) continue;int sum = 0;for(int q = 0; q < v.size(); q++) {if(mat[t][v[q]]) sum++;}if(sum == tmp[t]) res++;}ans = max(ans, res);}}return ans;}
};
1944. 队列中可以看到的人数
有 n 个人排成一个队列,从左到右 编号为 0 到 n - 1 。给你以一个整数数组 heights ,每个整数 互不相同,heights[i]
表示第 i 个人的高度。
一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人 矮 。更正式的,第 i 个人能看到第 j 个人的条件是 i < j 且 min(heights[i], heights[j]) > max(heights[i+1], heights[i+2], ..., heights[j-1])
。
请你返回一个长度为 n 的数组 answer
,其中 answer[i]
是第 i 个人在他右侧队列中能 看到 的 人数 。
示例 1:
输入:heights = [10,6,8,5,11,9]
输出:[3,1,2,1,1,0]
解释:
第 0 个人能看到编号为 1 ,2 和 4 的人。
第 1 个人能看到编号为 2 的人。
第 2 个人能看到编号为 3 和 4 的人。
第 3 个人能看到编号为 4 的人。
第 4 个人能看到编号为 5 的人。
第 5 个人谁也看不到因为他右边没人。
示例 2:
输入:heights = [5,1,2,3,10]
输出:[4,1,1,1,0]
提示:
n == heights.length
1 <= n <= 105
1 <= heights[i] <= 105
heights 中所有数 互不相同 。
虽然是hard题,但是实际上是中等题的难度(但我还是看了题解,太菜了),很明显的单调栈解决,及时去掉无用数据:
class Solution {
public:vector<int> canSeePersonsCount(vector<int>& heights) {int n = heights.size();vector<int> stack;vector<int> res(n, 0);for (int i = n - 1; i >= 0; i--) {int h = heights[i];while (!stack.empty() && stack.back() < h) {stack.pop_back();res[i] += 1;}if (!stack.empty()) {res[i] += 1;}stack.push_back(h);}return res;}
};
2807. 在链表中插入最大公约数
给你一个链表的头 head ,每个结点包含一个整数值。
在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。
请你返回插入之后的链表。
两个数的 最大公约数 是可以被两个数字整除的最大正整数。
示例 1:
输入:head = [18,6,10,3]
输出:[18,6,6,2,10,1,3]
解释:第一幅图是一开始的链表,第二幅图是插入新结点后的图(蓝色结点为新插入结点)。
- 18 和 6 的最大公约数为 6 ,插入第一和第二个结点之间。
- 6 和 10 的最大公约数为 2 ,插入第二和第三个结点之间。
- 10 和 3 的最大公约数为 1 ,插入第三和第四个结点之间。
所有相邻结点之间都插入完毕,返回链表。
示例 2:
输入:head = [7]
输出:[7]
解释:第一幅图是一开始的链表,第二幅图是插入新结点后的图(蓝色结点为新插入结点)。
没有相邻结点,所以返回初始链表。
提示:
链表中结点数目在 [1, 5000] 之间。
1 <= Node.val <= 1000
这个题灵神的题解实在是太优雅了,这里就不贴出我的菜鸡代码了orz
遍历链表
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode *insertGreatestCommonDivisors(ListNode *head) {for (auto cur = head; cur->next; cur = cur->next->next) {cur->next = new ListNode(gcd(cur->val, cur->next->val), cur->next);}return head;}
};