一起刷题吧
一、题目分析
输入:字符串
输出:第一个不重复的元素的下标
难度:简单
标签:哈希表,字符串
示例:
s = "leetcode"
返回 0
s = "loveleetcode"
返回 2
二、参考代码
这个题目比较简单,也有很多的解法。最直接的解法就是遍历一遍,同时把次数计算好,然后再遍历一遍,每次遍历时看下当前这个字符的次数,如果是等于 1
的,则返回当前下标。
这个题目用 Python
实现很简单,Python
的 collections
库里提供了 Counter
,用于统计 可迭代对象 里各个 对象 出现的次数。
看过原来题解的童鞋们肯定对 collections
库很熟悉了,因为用到过很多次,这里简单介绍下,个人认为这个库比较很好用,其中比较常用的是:
- Counter:用于统计个数,使用和
dict
类似,提供了most_common()
方法,可以获取到list
,且这个list
中的元素是一个tuple
,tuple
第一个元素是对象,第二个元素是这个对象出现的次数。最终这个列表是按次数倒序排序的 - deque:队列,也可以用于栈。比
list
做入、出的操作要高效 - OrderedDict:有序的
dict
。不过在3.7
之后,普通dict
就已经是有序了
因此,这个题目用Counter
其实可以很方便得到每个对象出现的次数。参考代码如下:
from collections import Counter
class Solution:
def firstUniqChar(self, s: str) -> int:
if not s:
return -1
record = Counter(s)
for i in range(len(s)):
if record[s[i]] == 1:
return i
return -1
在看题解的时候,看到两种比较好的思路,一种是在遍历的过程,去做查找,即判断是否会出现两次。那怎么通过查找能快速得到每个元素是否只会出现一次呢?很简单,即比较findLeft
和findRight
得到了index
是否相等。参考代码如下:
class Solution:
def firstUniqChar(self, s: str) -> int:
if not s:
return -1
for i in range(len(s)):
tmp = s.find(s[i])
if s.find(s[i], tmp+1) == -1:
return i
return -1
另外一种比较好的思路,使用了队列,即保证队列的首位一定是当前只出现过一次的元素。参考代码如下:
class Solution:
def firstUniqChar(self, s: str) -> int:
# 通过 dict 保证唯一性,即入队的元素一定是去重后的
position = dict()
q = deque()
n = len(s)
for i, ch in enumerate(s):
if ch not in position:
position[ch] = i
q.append((s[i], i))
else:
# 如果出现一个次数超过1的,则开始做出队判断
# 但并不是每次都需要出队,当队首的次数仍然是1时,其实是不需要出队的
position[ch] = -1
while q and position[q[0][0]] == -1:
q.popleft()
return -1 if not q else q[0][1]
# 作者:LeetCode-Solution
# 链接:https://leetcode-cn.com/problems/first-unique-character-in-a-string/solution/zi-fu-chuan-zhong-de-di-yi-ge-wei-yi-zi-x9rok/
# 来源:力扣(LeetCode)
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
三、相似题目
另外类似的题目:451. 根据字符出现频率排序:
https://leetcode-cn.com/problems/sort-characters-by-frequency/
同样如果使用 Counter 的话,一行代码就可以搞定,参考代码如下:
from collections import Counter
class Solution:
def frequencySort(self, s: str) -> str:
if not s:
return
return "".join([c[0] * c[1] for c in Counter(s).most_common()])