LC378. 字符串中的第一个唯一字符(第20题)

129 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

菜鸟就要从第20题继续

一、题目描述:

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

示例 :

输入: s = "leetcode" 输出: 0 示例 2:

输入: s = "loveleetcode" 输出: 2 示例 3:

输入: s = "aabb" 输出: -1   提示:

1 <= s.length <= 105 s 只包含小写字母

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

二、思路分析:

第一版(错误代码):开始看到这个题目,直观想到了map的新增删除,但写完发现对于"aaa",类的出现奇数个的是无法正常计算的,因此不能采用delete的方案。

同时存次数、索引:如果还考虑在第一版基础上改,可以把储存的value变为次数和位置,然后找到次数为1的那一个,取其位置。

只存索引:还在第一版上改,只存索引,不用delete而是重置为-1,最后再遍历找到不是-1的那一个最小值。(这里是摘抄了官方解决,他对于字符串的遍历,采用了Array.from(s).entries()

  • Array.from()  方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
  • entries() 方法返回一个数组的迭代对象,该对象包含数组的键值对 (key/value)。迭代对象中数组的索引值作为 key, 数组元素作为 value。

只存次数:思路上也很清晰,先存次数,最后找到为1的那一个。官方的写法很有趣

  • _.countBy()创建一个对象,对数组或者对象的每个元素或属性调用iteratee迭代器后生成这个对象的键,键的值是这个键出现的次数

队列思路:这个思路开始时我想过,后来感觉比较复杂,并不直观就没写,重点就在于要在每次有变化的时候重新处理前面的删除内容。

三、AC 代码:

1、第一版(错误代码)

/**
 * @param {number} x
 * @return {number}
 */
var firstUniqChar = function(s) {
    let map = new Map()
    for(let i=0;i<s.length;i++){
        if(map.has(s[i])){
            map.delete(s[i])
        }
        else{
            map.set(s[i],i)
        }
    }
    if(map.size==0){
        return -1
    }
    else {return map.entries().next().value[1]}
};

2、同时存次数、索引

/**
 * @param {number} x
 * @return {number}
 */
var firstUniqChar = function(s) {
    let map = new Map()
    for(let i=0;i<s.length;i++){
        map.set(s[i],[i,(map.get(s[i]) || 0) + 1])
    }
    for (let [index, occurrences] of map.values()) {
    if (occurrences === 1) {
      return index;
    }
  }
   return -1;
};

3、只存索引

/**
 * @param {number} x
 * @return {number}
 */
var firstUniqChar = function(s) {
    const position = new Map();
    const n = s.length;
    for (let [i, ch] of Array.from(s).entries()) {
        if (position.has(ch)) {
            position.set(ch, -1);
        } else {
            position.set(ch, i);
        }
    }
    let first = n;
    for (let pos of position.values()) {
        if (pos !== -1 && pos < first) {
            first = pos;
        }
    }
    if (first === n) {
        first = -1;
    }
    return first;
};

4、只存次数

/**
 * @param {number} x
 * @return {number}
 */
var firstUniqChar = function(s) {
    const frequency = _.countBy(s);
    for (const [i, ch] of Array.from(s).entries()) {
        if (frequency[ch] === 1) {
            return i;
        }
    }
    return -1;
};

5、队列思路

/**
 * @param {number} x
 * @return {number}
 */
var firstUniqChar = function(s) {
    const position = new Map();
    const q = [];
    const n = s.length;
    for (let [i, ch] of Array.from(s).entries()) {
        if (!position.has(ch)) {
            position.set(ch, i);
            q.push([s[i], i]);
        } else {
            position.set(ch, -1);
            while (q.length && position.get(q[0][0]) === -1) {
                q.shift();
            }
        }
    }
    return q.length ? q[0][1] : -1;
};