leetcode 剑指 Offer 50. 第一个只出现一次的字符

106 阅读2分钟

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

示例:

s = "abaccdeff"
返回 "b"
s = "" 
返回 " "

限制:

  • 0 <= s 的长度 <= 50000

第一次想法就是使用对象保存各个字母出现的次数,然后再遍历如果出现的次数为 1 的那么就返回:

/**
 * @param {string} s
 * @return {character}
 */
var firstUniqChar = function(s) {
  const obj = {}
  // 先转化字母为对象,并记录出现的次数
  for (let i = 0; i < s.length; i ++) {
    obj[s.charAt(i)] = (obj[s.charAt(i)] || 0) + 1;
  }
  // 看是否出现一次
  for (let j = 0; j < s.length; j ++) {
    if (obj[s.charAt(j)] === 1) {
      return s.charAt(j);
    }
  }
  return " ";
};

时间复杂度分析:第一个 for 循环没得说肯定是 n 次;第二个 for 最差的情况也就是 n ,至于 js 中对象的存储的使用的什么数据结构,目标我还不知道,可能就是哈希表,不知道也就不知道判断其查找的时间复杂度了,那我就把时间复杂度假定为 X ,那么第二个 for 循环最好的情况是 1*X ,最差的情况是 n*X,那么整体来说最好的时间复杂度为 O(n*X) ,最差的情况是 O(2*n*X),结合起来发现仍然是 O(n*X)

我觉得这样子不好,代码感觉很多,也就是一点抽象都没有,也就是我的常规思维,我还想再用其他方法来进一步优化代码,或者换一种思路,或者抽象呀什么的。

我想到了使用 indexOf 函数来帮助我简化代码,只不过在搜索的时候需要查看当前字母前面和后面有没有自身,如果都没有就返回,我想到这样效率更低,我于是想到了结合对象和 lastIndexOf 来达到自己想要的目标:

/**
 * @param {string} s
 * @return {character}
 */
var firstUniqChar = function(s) {
  // 用于遍历当前已经走过的路
  const obj = {};
  for (let i = 0; i < s.length; i ++) {
    // 如果前面没有并且从后到当前字母也没有那就说明这个是第一次出现
    if (!obj[s.charAt(i)] && s.lastIndexOf(s.charAt(i)) === i) {
      return s.charAt(i);
    }
    obj[s.charAt(i)] = true;
  }
  return " ";
};

今天就到这里了。再看看官网的讲解,发现没有,说明这个很简单。


来源:力扣(LeetCode)