LeetCode 记录-811. 子域名访问计数

125 阅读3分钟

LeetCode 记录-811. 子域名访问计数

我的解法

思路

image.png

我的思路就是通过遍历每个域名的所有子域名,并用 map 记录数量。

代码

/**
 * @param {string[]} cpdomains
 * @return {string[]}
 */
var subdomainVisits = function (cpdomains) {
  const cpdMap = new Map();
  let ans = new Map();

  cpdomains.forEach((cpdomain) => {
    const [count, domain] = cpdomain.split(" ");
    cpdMap.set(domain, (cpdMap.get(domain) || 0) + count * 1);
  });

  for (let domain of cpdMap.keys()) {
    const domainArr = domain.split(".");
    const curCount = cpdMap.get(domain);
    while (domainArr.length) {
      ans.set(
        domainArr.join("."),
        (ans.get(domainArr.join(".")) || 0) + curCount
      );
      domainArr.shift();
    }
  }

  return [...ans].map((cpd) => `${cpd[1]} ${cpd[0]}`);
};

复杂度分析(自我分析,不一定对)

时间复杂度

O(cn)O(c*n),n 为传入的 cpdomains 的长度,c 为 cpdomains 中子域名个数最多的个数。(我不知道这个 c 是否可以忽略,本来觉得可以,因为它和输入的长度没有什么关系,但后面想想,其实它也是衡量输入大小的一个维度。所以觉得还是应该考虑。)

空间复杂度

O(cn)O(c*n),即为用来存所有子域名数量的 map 的空间大小,最坏情况下,cpdomains 中各项的子域名个数相同,但内容互不相同。


官方解法: 哈希表

思路

image.png

思路和我想的差不多,就不讨论啦。

代码

var subdomainVisits = function (cpdomains) {
  const ans = [];
  const counts = new Map();
  for (const cpdomain of cpdomains) {
    const space = cpdomain.indexOf(" ");
    const count = parseInt(cpdomain.slice(0, space));
    const domain = cpdomain.slice(space + 1);
    counts.set(domain, (counts.get(domain) || 0) + count);
    for (let i = 0; i < domain.length; i++) {
      if (domain[i] === ".") {
        const subdomain = domain.slice(i + 1);
        counts.set(subdomain, (counts.get(subdomain) || 0) + count);
      }
    }
  }
  for (const [subdomain, count] of counts.entries()) {
    ans.push(count + " " + subdomain);
  }
  return ans;
};

复杂度分析

时间复杂度

O(L)O(L),其中 L 是数组 cpdomains 中的所有字符串长度之和。遍历数组中所有的计数配对域名计算每个子域名的计数需要 O(L) 的时间,遍历哈希表也需要 O(L)的时间。

和我的解法有点区别:我是先 split 再去按子域名个数遍历,官方是直接遍历字符串。

空间复杂度

O(L)O(L),其中 L 是数组 cpdomains 中的所有字符串长度之和。哈希表需要 O(L)O(L) 的空间。

总之,官方的分析让我明白了,这题在分析时间复杂度时确实是要考虑输入每项的大小的。这让我怀疑我理解的时间、空间复杂度是否正确。所以我又去查了一下资料:

时间复杂度是一个函数,它定性的描述该算法的运行时间,这个函数就是算法的渐进时间复杂度:T(n)=O(f(n))T(n)=O(f(n))。它反映的是代码执行时间增长的趋势。f(n)f(n)代表的是每行代码执行次数之和。由此可见,我们这里的次数之和并不只和输入的个数 n 挂钩,而是和总体字符串长度之和 L 有关,T(n)=O(a+bL)T(n)=O(a+b*L),a,b 都是常数,OO则代表正比例关系,所以时间复杂度为O(L)O(L)

空间复杂度是对一个算法在运行过程中临时占用储存空间大小的量度,反映所需要的临时空间增长的趋势。记作S(n)=O(f(n))S(n)=O(f(n))。分析过程和时间复杂度类似。

除此之外

对于一个算法,其时间复杂度和空间复杂度往往是相互影响的。当追求一个比较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的储存空间;反之,当追求一个较好的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。

另外,算法的所有性能之间都存在着或多或少的相互影响。因此,当设计一个算法(特别是大型算法)时,要综合考虑算法的各项性能,算法的使用频率,算法处理的数据量的大小,算法描述语言的特性,算法运行的机器系统环境等各方面因素,才能够设计出比较好的算法。

算法的时间复杂度和空间复杂度合称为算法的复杂度。