您的位置:首页 > Web前端 > Node.js

【Leetcode经典题目】1257. Smallest Common Region -- [Mid][Tree/DFS][ListNode]

2020-04-03 07:28 1271 查看

【题目】

You are given some lists of regions where the first region of each list includes all other regions in that list.

Naturally, if a region X contains another region Y then X is bigger than Y. Also by definition a region X contains itself.

Given two regions region1, region2, find out the smallest region that contains both of them.

If you are given regions r1, r2 and r3 such that r1 includes r3, it is guaranteed there is no r2 such that r2 includes r3.

It's guaranteed the smallest region exists.

 

Example 1:

Input:
regions = [["Earth","North America","South America"],
["North America","United States","Canada"],
["United States","New York","Boston"],
["Canada","Ontario","Quebec"],
["South America","Brazil"]],
region1 = "Quebec",
region2 = "New York"
Output: "North America"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-common-region
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

【思路1】

转化成求一个树中两个节点共同最小祖先节点问题。

使用DFS及helper方程,遍历树的节点,直到找到target节点。

【易错点】

如果子节点中已发现满足条件的节点后,如何向上一级函数传递容易出错。

【代码】

[code]class Solution {
private:
//Node* root;
unordered_map<string, vector<string>> map;
unordered_set<string> roots;
public:
string findSmallestRegion(vector<vector<string>>& regions, string region1, string region2) {
string res = "";
for(auto r: regions) {
roots.insert(r[0]);
}
for(auto r: regions) {
for(int i = 1; i < r.size(); ++i) {
map[r[0]].push_back(r[i]);
if(roots.find(r[i]) != roots.end()) roots.erase(r[i]);
}
}
/*for(auto m: map) {
cout << m.first << ": ";
for(auto v: m.second) cout << v << ", ";
cout << endl;
}*/
for(auto r: roots) {
res = helper(r, region1, region2);
if(res != "") return res;
}
return res;
}
string helper(string root, string r1, string r2) {
if(root == r1 || root == r2) return root;
if(map.find(root) == map.end()) return "";
bool rg1 = false, rg2 = false;
for(string child: map[root]) {
string temp = helper(child,r1,r2);
//cout << temp << endl;
if(temp == r1) rg1 = true;
if(temp == r2) rg2 = true;
if(rg1 && rg2) return root;
if(temp != "" && temp != r1 && temp != r2) return temp;
}
if(rg1) return r1;
if(rg2) return r2;
return "";
}
};

【分析】

1. 基于树的纵向遍历使用DFS算法和helper函数也是一类典型题目。

2. 未保存整个树结构,以及确认是否为根节点进行了很多重复操作。此外在寻找目标节点时,也遍历了很多不相关子树和节点,造成很多多余时间开销。

【思路2】

转化成求链表中两个节点相交的节点问题。

1. 先建立每一个节点与其上一层节点对应关系,找到每一个节点的父节点;

2. 求出两个目标节点深度d1, d2;

3. 将两节点移动到同一深度位置后,查看他们是否相等,若相等则返回此节点值,否则继续向根节点移动。

【代码】

[code]class Solution {
private:
unordered_map<string, string> par;
public:
string findSmallestRegion(vector<vector<string>>& regions, string region1, string region2) {
for(auto r: regions) {
string r0 = r[0];
for(int i = 1; i < r.size(); ++i)
par[r[i]] = r0;
}
int d1 = 0, d2 = 0;
string r1 = region1, r2 = region2;
while(par.find(r1) != par.end()) {
r1 = par[r1];
d1++;
}
while(par.find(r2) != par.end()) {
r2 = par[r2];
d2++;
}
while(d1 > d2) {
region1 = par[region1];
d1--;
}
while(d2 > d1) {
region2 = par[region2];
d2--;
}
while(region1 != region2) {
region1 = par[region1];
region2 = par[region2];
}
return region1;
}
};

【分析】

1. 类似的链表题还有:

查看一个链表是否存在环(快慢指针);

若存在环寻找环的入口(快慢指针一个断掉,变成寻找两个节点相交的第一个节点,同上题)

2. 对字符串的存储占据了很多空间,或许可以更优化一些。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
xiyang0405 发布了4 篇原创文章 · 获赞 0 · 访问量 73 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐