grid[][]
,若 grid[i][j] == 1
,则说明 i
队比 j
队强;若 grid[i][j] == 1
,则说明 i
队比 j
队强,也说明 j
队比 i
队弱。
而如果不存在强于 a
队的队伍,则 a
为冠军。
因此,如果对于所有的 i
,grid[i][a] != 1
成立,就说明没有比 a
强的队伍,那么 a
队就是冠军。
class Solution {
public:
int findChampion(vector<vector<int>>& grid) {
int n = grid.size();
for(int j = 0; j < n; j++)
{
bool flag = true;
for(int i = 0; i < n; i++)
{
if(i != j && grid[i][j] == 1)
{
flag = false;
break;
}
}
if(flag) return j;
}
return -1;
}
};
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
(a, b)
,则说明 a
队比 b
队强。若图中存在边 (a, b)
,则说明 a
队比 b
队强,或者说, b
队比 a
队弱。因此,对于图中的点来说,他的 入度表示了比它强的队伍的数量。
class Solution {
public:
int findChampion(int n, vector<vector<int>>& edges) {
vector<int> in(n, 0);
vector<vector<int> > m_edges(n);
for(auto e : edges)
{
int u = e[0], v = e[1];
m_edges[u].push_back(v);
in[v]++;
}
int ans = -1;
queue<int> q;
int cnt = 0;
for(int i = 0; i < n; i++)
{
if(in[i] == 0)
q.push(i);
}
if(q.size() != 1) return -1; // 多个入度为0的点
ans = q.front();
return ans;
}
};
时间复杂度:
O
(
m
+
n
)
O(m + n)
O(m+n),m 为边的数量,n 为点的数量;
空间复杂度:
O
(
n
)
O(n)
O(n)
树的问题一般都是宏观上自上而下递归,回溯上自下而上考虑的。
从孩子的角度考虑:
leaf
。因此,最开始的得分(obtain
)为 0
,而留下的得分(remain
)为 leaf->value
;node
,而 p->value < remain
,那么显然,我们可以将结点 node
作为它相关的路径上的结点,而把之前留下的结点作为新的得分收下;反之,因为这些路径上已经有节点了,所以我收下结点 node
作为新的得分。从父亲的角度考虑:
对于一个非叶节点 node
来说,假设它有孩子结点 child1
,child2
,child3
。那么在比较 p->value
和 remain
时,应当是比较 p->value
和 remain(child1) + child(2) + child(3)
,因为假使我选择留下当前结点 node
,那么它可以保证以他为根的子树所有路径健康,所以我可以收回所有之前留下的结点。
题目里还有一个坑是:给定的是无向边,但是在遍历树时,是一个自上而下的有向遍历。因此我选择了先用层次遍历记录每个结点的层,从而来分辨父亲结点和孩子结点。
class Solution {
public:
// 返回留下的值
int recur(vector<vector<int>>& g, int node, vector<int>& values, long long& ans, vector<int>& rank)
{
long long tmp = 0;
for(auto v : g[node]) // 遍历 node 的邻接点
{
if(rank[v] > rank[node]) // v 是 node 的孩子
tmp += 1ll * recur(g, v, values, ans, rank); // 所有孩子留下的和
}
int res = 0;
if(tmp == 0)
{
res = values[node];
return res;
}
if(tmp > values[node])
{
ans += 1ll * tmp; // 拿走所有孩子,留它
res = values[node];
}
else
{
ans+=values[node]; // 拿走他,留孩子们
res=tmp;
}
return res;
}
long long maximumScoreAfterOperations(vector<vector<int>>& edges, vector<int>& values) {
int n = values.size();
vector<vector<int> > g(n);
vector<int> rank(n, -1);
for(auto e : edges)
{
int u = e[0], v = e[1];
g[u].push_back(v);
g[v].push_back(u);
}
int r = 0;
queue<int> q;
q.push(0);
while(!q.empty())
{
for(int i = q.size(); i > 0; i--)
{
int u = q.front();
q.pop();
rank[u] = r;
for(auto v :g[u])
{
if(rank[v] == -1) q.push(v);
}
}
r++;
}
long long ans = 0;
recur(g, 0, values, ans, rank);
return ans;
}
};
时间复杂度:
O
(
m
+
n
)
O(m + n)
O(m+n),m 是边的数量,n 是结点的数量;
空间复杂度:
O
(
n
)
O(n)
O(n)。