以前写的几道力扣题的题解

leetcode-1719

题目关键点:

  • 树对 pairs[i]=[x_i,y_i],表示一个结点与其祖先,其中祖先可以是两者中的任意一个
  • 别搞错了祖先的定义:
    父亲(parent node):对于除根以外的每个结点,定义为从该结点到根路径上的第二个结点。 根结点没有父结点。
    祖先(ancestor):一个结点到根结点的路径上,除了它本身外的结点。 根结点的祖先集合为空。
  • pairs 包含树中所有可能构成祖先的树对。

n:树中节点数
degree[x]:pairs 中包含节点 x 的数对的数目
adj[x]:节点 x 的祖先和后代的节点集合

degree[x] = adj[x].size(),adj[x] 是个 vector,存储的是节点,因此是个集合;degree[x] 是个数字,即 adj[x] 的大小。

找出能够构成有根树的充分必要条件即可。

重点在于 degree 的性质:

  • degree[root]=n-1 根节点与其他所有节点都能构成树对;adj[root]={node[1],node[2],...,node[n-1]} 树中除了它自己,其余的都是后代节点,并且没有祖先。
  • 对于数对 [x_i,y_i],如果 x_iy_i 的祖先,则一定满足 degree[x_i]\geq degree[y_i], adj[y_i]\in adj[x_i]
  • 对于数对 [x_i,y_i],如果 x_iy_i 的祖先,且 degree[x_i]=degree[y_i], adj[x_i]=adj[y_i],则 x_iy_i 之间到路径上均只有一个节点。即,x_i 只有一个分支,y_i 在这个分支上。

In conclusion, for any pair [x_i,y_i] :

  • If degree[x_i]>degree[y_i], then x_i is the ancestor of y_i , and vice versa;
  • If degree[x_i]=degree[y_i], then there exists multiple ways to build the rooted tree, ancestor can either be x_i or y_i .

Code:

class Solution {
	public:
	int checkWays(vector<vector<int>>& pairs) {
		unordered_map<int, unordered_set<int>> adj;
		for (auto &p : pairs) {
			adj[p[0]].emplace(p[1]);
			adj[p[1]].emplace(p[0]);
		}
		/* 检测是否存在根节点*/
		int root = -1;
		for (auto &[node, neighbours] : adj) {
			if (neighbours.size() == adj.size() - 1) {
				root = node;
				break;
			}
		}
		if (root == -1) {
			return 0;
		}

		int res = 1;
		for (auto &[node, neighbours] : adj) {
			if (node == root) {
				continue;
			}
			int currDegree = neighbours.size();
			int parent = -1;
			int parentDegree = INT_MAX;

			/* 根据 degree 的大小找到 node 的父节点 parent */
			for (auto &neighbour : neighbours) {
				if (adj[neighbour].size() < parentDegree && adj[neighbour].size() >= currDegree) {
					parent = neighbour;
					parentDegree = adj[neighbour].size();
				}
			}
			if (parent == -1) {
				return 0;
			}

			/* 检测 neighbours 是否是 adj[parent] 的子集 */
			for (auto &neighbour : neighbours) {
				if (neighbour == parent) {
					continue;
				}
				if (!adj[parent].count(neighbour)) {
					return 0;
				}
			}
			if (parentDegree == currDegree) {
				res = 2;
			}
		}
		return res;
	}
};

leetcode-2045

这道题是用 BFS 求严格次短路径。

  • 用邻接表存储地图
  • 用两个 vector 分别存储最短路径和次短路径。也可以用 path[i][0], path[i][1] 表示
  • 用 queue 装的是 pair,注意 queue<pair<int, int>> q; q.push({a, b});,其中第一个是当前节点编号,第二个是路径长度
  • 最重要的技巧:queue 的 while 循环终止条件不是 empty 而是 path[n][1]==INT_MAX

代码如下:

class Solution {
	public:
	int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
		vector<vector<int>> graph(n + 1);
		for (auto &e : edges) {
			graph[e[0]].push_back(e[1]);
			graph[e[1]].push_back(e[0]);
		}

		// path[i][0] 表示从 1 到 i 的最短路长度,path[i][1] 表示从 1 到 i 的严格次短路长度
		vector<vector<int>> path(n + 1, vector<int>(2, INT_MAX));
		path[1][0] = 0;
		queue<pair<int, int>> q;
		q.push({1, 0});
		while (path[n][1] == INT_MAX) {
			auto [cur, len] = q.front();
			q.pop();
			for (auto next : graph[cur]) {
				if (len + 1 < path[next][0]) {
					path[next][0] = len + 1;
					q.push({next, len + 1});
				} else if (len + 1 > path[next][0] && len + 1 < path[next][1]) {
					path[next][1] = len + 1;
					q.push({next, len + 1});
				}
			}
		}

		int ret = 0;
		for (int i = 0; i < path[n][1]; i++) {
			if (ret % (2 * change) >= change) {
				ret = ret + (2 * change - ret % (2 * change));
			}
			ret = ret + time;
		}
		return ret;
	}
};
posted @ 2022-06-15 09:36  Ryomk  阅读(25)  评论(0编辑  收藏  举报