Medium
题目描述
网站域名 “discuss.leetcode.com” 由多个子域名组成。顶级域名为 “com”,下一级为 “leetcode.com”,最低一级为 “discuss.leetcode.com”。当访问域名 “discuss.leetcode.com” 时,同时也会隐式访问父域名 “leetcode.com” 和 “com”。
计数配对域名是一个格式为 “rep d1.d2.d3” 或 “rep d1.d2” 的域名,其中 rep 是访问域名的次数,d1.d2.d3 是域名本身。
例如,“9001 discuss.leetcode.com” 是一个计数配对域名,表示 discuss.leetcode.com 被访问了 9001 次。
给你一个计数配对域名组成的数组 cpdomains,返回输入中每个子域名对应的计数配对域名数组。可以按任意顺序返回答案。
示例 1:
输入:cpdomains = ["9001 discuss.leetcode.com"]
输出:["9001 leetcode.com","9001 discuss.leetcode.com","9001 com"]
解释:例子中只有一个网站域名:"discuss.leetcode.com"。
按照前文描述,子域名 "leetcode.com" 和 "com" 都会被访问,所以它们都被访问了 9001 次。
示例 2:
输入:cpdomains = ["900 google.mail.com", "50 yahoo.com", "1 intel.mail.com", "5 wiki.org"]
输出:["901 mail.com","50 yahoo.com","900 google.mail.com","5 wiki.org","5 org","1 intel.mail.com","951 com"]
解释:按照假设,会访问 "google.mail.com" 900 次,"yahoo.com" 50 次,"intel.mail.com" 1 次,"wiki.org" 5 次。
而对于父域名,会访问 "mail.com" 900 + 1 = 901 次,"com" 900 + 50 + 1 = 951 次,和 "org" 5 次。
提示:
1 <= cpdomains.length <= 1001 <= cpdomains[i].length <= 100cpdomains[i]会遵循 “repi d1i.d2i.d3i” 或 “repi d1i.d2i” 格式repi是范围[1, 10^4]内的整数d1i、d2i和d3i由小写英文字母组成
解题思路
解题思路
这是一个典型的字符串处理和哈希表计数问题。核心思路是:
- 解析输入:对每个计数配对域名,分离出访问次数和完整域名
- 提取子域名:从完整域名中提取所有可能的子域名(包括自身)
- 累计计数:使用哈希表记录每个子域名的总访问次数
- 格式化输出:将哈希表中的结果转换为要求的格式
关键步骤:
- 对于域名 “discuss.leetcode.com”,需要提取的子域名有:
- “discuss.leetcode.com”(完整域名)
- “leetcode.com”(去掉第一部分)
- “com”(顶级域名)
实现方法:
- 使用字符串分割获取访问次数和域名
- 通过查找 “.” 的位置来逐步提取子域名
- 使用哈希表累计每个子域名的访问次数
时间复杂度主要取决于处理所有域名字符串的总长度,空间复杂度取决于不同子域名的数量。
代码实现
class Solution {
public:
vector<string> subdomainVisits(vector<string>& cpdomains) {
unordered_map<string, int> count;
for (const string& domain : cpdomains) {
int spacePos = domain.find(' ');
int visits = stoi(domain.substr(0, spacePos));
string fullDomain = domain.substr(spacePos + 1);
// 添加完整域名
count[fullDomain] += visits;
// 添加所有子域名
for (int i = 0; i < fullDomain.length(); i++) {
if (fullDomain[i] == '.') {
string subdomain = fullDomain.substr(i + 1);
count[subdomain] += visits;
}
}
}
vector<string> result;
for (const auto& pair : count) {
result.push_back(to_string(pair.second) + " " + pair.first);
}
return result;
}
};
class Solution:
def subdomainVisits(self, cpdomains: List[str]) -> List[str]:
count = {}
for domain in cpdomains:
visits, full_domain = domain.split(' ', 1)
visits = int(visits)
# 添加完整域名
count[full_domain] = count.get(full_domain, 0) + visits
# 添加所有子域名
for i in range(len(full_domain)):
if full_domain[i] == '.':
subdomain = full_domain[i + 1:]
count[subdomain] = count.get(subdomain, 0) + visits
return [f"{visits} {domain}" for domain, visits in count.items()]
public class Solution {
public IList<string> SubdomainVisits(string[] cpdomains) {
var count = new Dictionary<string, int>();
foreach (string domain in cpdomains) {
int spaceIndex = domain.IndexOf(' ');
int visits = int.Parse(domain.Substring(0, spaceIndex));
string fullDomain = domain.Substring(spaceIndex + 1);
// 添加完整域名
if (count.ContainsKey(fullDomain)) {
count[fullDomain] += visits;
} else {
count[fullDomain] = visits;
}
// 添加所有子域名
for (int i = 0; i < fullDomain.Length; i++) {
if (fullDomain[i] == '.') {
string subdomain = fullDomain.Substring(i + 1);
if (count.ContainsKey(subdomain)) {
count[subdomain] += visits;
} else {
count[subdomain] = visits;
}
}
}
}
var result = new List<string>();
foreach (var pair in count) {
result.Add($"{pair.Value} {pair.Key}");
}
return result;
}
}
var subdomainVisits = function(cpdomains) {
const domainCount = new Map();
for (const cpdomain of cpdomains) {
const [count, domain] = cpdomain.split(' ');
const visitCount = parseInt(count);
const parts = domain.split('.');
for (let i = 0; i < parts.length; i++) {
const subdomain = parts.slice(i).join('.');
domainCount.set(subdomain, (domainCount.get(subdomain) || 0) + visitCount);
}
}
const result = [];
for (const [domain, count] of domainCount) {
result.push(`${count} ${domain}`);
}
return result;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(N × M),其中 N 是 cpdomains 的长度,M 是每个域名的平均长度 |
| 空间复杂度 | O(K),其中 K 是所有不同子域名的数量 |