题目
题目链接:leetcode-cn.com/leetbook/re…
题解
1、暴力方法
第一个想到的就是直接两层循环套上去,虽然简单,但却有用,上代码;
/**
* @param {string} s
* @return {number}
*/
var firstUniqChar = function(s) {
let isReapet = false;
let len = s.length;
for(let i = 0;i < len;i++) {
isReapet = false;
for(let j = 0;j<len;j++) {
if( i !== j && s[i] === s[j]) {
isReapet = true;
break;
}
}
if(isReapet === false) {
return i;
}
}
return -1;
};
2、改进:空间换时间
暴力方法的时间复杂度是,肯定会想去降低它的时间复杂度,按照空间换时间的理论,看能不能在 的时间复杂度内完成; 如下,使用 对象(当然这里也可以用 Map)先记录字符是否重复,再找出第一个不重复字符的位置;
使用 Object 记录
/**
* @param {string} s
* @return {number}
*/
var firstUniqChar = function(s) {
let len = s.length;
let isRepeat = {};
for(let item of s) {
if( isRepeat[item] === undefined) {
isRepeat[item] = false;
}else {
isRepeat[item] = true;
}
}
for(let i = 0;i < len;i++) {
if(isRepeat[s[i]] === false) {
return i;
}
}
return -1;
};
使用 Map 记录
/**
* @param {string} s
* @return {number}
*/
var firstUniqChar = function(s) {
let len = s.length;
let map = new Map();
// 使用一个 Map 将字符是否重复记录下来,重复则值为true,不重复则值为false
for(let item of s) {
if( map.get(item) === undefined) {
map.set(item,false);
}else {
map.set(item,true);
}
}
for(let i = 0;i < len;i++) {
if(map.get(s[i]) === false) {
return i;
}
}
return -1;
};
既然 Object 和 Map 都能使用,它们之间有什么区别呢? 如下,From MDN
-
Object 继承了原型链上的所有键名,因此可能和自己设置的键名产生冲突;而 Map 默认只包含了自己的键名;
-
Object 的键必须是一个 String 或 Symbol;而 Map 的键可以是任意类型;
-
Object 的键是无序的,Map 中的键的顺序和插入顺序一致;
-
Object 的键值对个数只能手动计算,Map 中可以通过 size 获取;
-
Object 不是可迭代的,Map 是可迭代的;
-
在频繁增删键值对的场景下,Map 表现更好;
3、改进:使用 JS 字符串的方法
str.indexOf()
和 str.lastIndexOf()
确定字符在字符串中第一次和最后一次出现的位置;
/**
* @param {string} s
* @return {number}
*/
var firstUniqChar = function(s) {
let len = s.length;
for(let i = 0;i < len;i++) {
var str = s[i];
if(s.indexOf(str) === s.lastIndexOf(str)) {
return i;
}
}
return -1;
};
大家如果有更好的思路和解法,欢迎大家一起来讨论啊~
这是使用 JavaScript 对 LeetCode《初级算法》的每道题的总结和实现的其中一篇,汇总篇在这里: