Q1 找到冠军 I
-
解题思路:
- 遍历矩阵每行
- 如果只存在一行满足行内有n-1个1,返回该行的行号
- 否则返回-1
-
解题代码:
class Solution {
public:
int findChampion(vector<vector<int>>& grid) {
int n = grid.size();
for(int i = 0; i < n; i++)
{
int cnt = count(grid[i].begin(), grid[i].end(), 1);
if(cnt == n-1)
return i;
}
return -1;
}
};
- 当然也可以从列的角度来考虑,如果j列全部为0,则表示没有任何选手可以击败j
- 解题代码:
class Solution {
public:
int findChampion(vector<vector<int>>& grid) {
int n = grid.size();
for(int j = 0; j < n; j++)
{
bool state = true;
for(int i = 0; i < n; i++)
{
if(grid[i][j] == 1)
{
state = false;
break;
}
}
if(state)
return j;
}
return -1;
}
};
Q2 找到冠军 II
-
解题思路:
- 统计入度为0的点
- 如果恰好只有一个点,返回该点
- 否则返回-1
-
解题代码:
class Solution {
public:
int findChampion(int n, vector<vector<int>>& edges) {
vector<int> deg(n, 0);
for(auto &edge : edges)
{
int x = edge[0];
int y = edge[1];
deg[y] += 1;
}
int ans = -1;
for(int i = 0; i < n; i++)
{
if(deg[i] == 0)
{
if(ans == -1)
ans = i;
else
return -1;
}
}
return ans;
}
};
Q3 在树上执行操作以后得到的最大分数
-
解题思路:
-
定义dfs(x, fa),表示从x节点(选取/未选取)开始遍历到根节点可以得到的最大分数
-
状态转移:
- 如果不选x,则可以选x的所有子树中的所有元素
- 如果选了x,则x的每一颗子树上都得有一个不选的元素,dfs(x, fa, state) = sum(dfs(y, x)),其中y是x的子节点
-
当到了叶子节点,必须不选了,返回0
-
递归入口:dfs(0, -1)
-
可以不用记忆化搜索的
-
-
解题代码:
class Solution {
public:
long long maximumScoreAfterOperations(vector<vector<int>>& edges, vector<int>& values) {
int n = values.size();
vector<vector<int>> g(n);
for(auto edge : edges)
{
int x = edge[0];
int y = edge[1];
g[x].push_back(y);
g[y].push_back(x);
}
vector<long long> sum(n, 0);
function<long long(int, int)> dfs = [&](int x, int fa) -> long long
{
long long ans = values[x];
for(auto y : g[x])
{
if(y != fa)
ans += dfs(y, x);
}
sum[x] = ans;
return ans;
};
dfs(0, -1);
vector<long long> f(n, -1);
function<long long(int, int)> dfs2 = [&](int x, int fa) -> long long
{
if(g[x].size() == 1 && g[x][0] == fa)
return 0;
if(f[x] != -1)
return f[x];
long long ans1 = sum[x] - values[x];
long long ans2 = values[x];
for(auto y : g[x])
{
if(y != fa)
ans2 += dfs2(y, x);
}
f[x] = max(ans1, ans2);
return f[x];
};
return dfs2(0, -1);
}
};
Q4 平衡子序列的最大和
- 题目链接
- 解题思路:
-
数据结构优化 DP
-
定义b[i] = nums[i] - i,问题变成从b中选出一个非降子序列,求对应的nums的元素和的最大值
-
定义f[i]表示子序列最后一个数的下标是i时,对应的nums的元素和的最大值,答案会是max(f)
-
f[i] = max(max(f[j], 0)) + nums[i],j满足 j < i 且 b[j] <= b[i]
-
使用权值树状数组优化,树状数组维护前缀最大值
- 设下标x = b[i],维护的值为max(f[x],f[x-1],f[x-2],…)
-
实现时需要将nums[i] - i 离散化,在使用树状数组 复制 + 排序 + 去重
-
树状数组 区间最大值 + 单点更新
-
- 解题代码:
class BIT{
public:
BIT(){}
BIT(int n):tree(n, LONG_LONG_MIN){}
void update(int i, long long val)
{
while(i < tree.size())
{
tree[i] = max(tree[i], val);
i += i & -i;
}
}
long long preMax(int i)
{
long long res = LONG_LONG_MIN;
while(i > 0)
{
res = max(res, tree[i]);
i &= i-1;
}
return res;
}
private:
vector<long long> tree;
};
class Solution {
public:
long long maxBalancedSubsequenceSum(vector<int>& nums) {
int n = nums.size();
vector<int> b(n);
for(int i = 0; i < n; i++)
b[i] = nums[i] - i;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end()); //去重
BIT t = BIT(b.size() + 1);
for(int i = 0; i < n; i++)
{
int j = lower_bound(b.begin(), b.end(), nums[i] - i) - b.begin() + 1;
long long temp = max(t.preMax(j), 0ll) + nums[i];
t.update(j, temp);
}
return t.preMax(b.size());
}
};