14 字符串中的第一个唯一字符-20200324
题目
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
示例
s = "leetcode"
返回 0.
说明
您可以假定该字符串只包含小写字母。
注意事项
- 空字符串的情况。
思路一
因为题目要求是小写的英文字母,一共就26个,ASCII码从97到122。所以可以设置一个长度为26的数组,里面存储着对应字母在字符串中的索引,遇过重复了就将值改为-1,最后除-1外找到最小的值。
修改经历:
1. 忘记考虑没有不重复的情况了。(第一次提交)
- 解答错误。
2. 修改后提交,提交成功。(第二次提交)
- 执行用时 :152 ms, 在所有 Python3 提交中击败了45.43%的用户
- 内存消耗 :13.6 MB, 在所有 Python3 提交中击败了6.57%的用户
心得体会:
字符转ASCII码相互转化的知识点放在下面的Python 3 知识点复习中了,第6条。感觉肯定有比着更好的算法。
最终代码展示:
class Solution:
def firstUniqChar(self, s: str) -> int:
ca = [] # char array
for _ in range(0, 26):
ca.append(-1)
for i in range(0, len(s)):
ind = ord(s[i])-97
if ca[ind] >= 0:
ca[ind] = -2
elif ca[ind] == -1:
ca[ind] = i
else:
pass
if max(ca) < 0:
return -1
else:
mav = max(ca) # max value
for j in range(0, 26):
ca[j] = mav if ca[j] in [-1, -2] else ca[j]
return min(ca)
思路二
利用 Python 中的 Collections 包中的 Counter 来实现自动统计元素重复次数。把第一个重复次数为1的元素,index输出就行。柑橘有点作弊,哈哈哈。
修改经历:
1.一次成功。(第一次提交)
- 执行用时 :192 ms, 在所有 Python3 提交中击败了28.46%的用户
- 内存消耗 :13.7 MB, 在所有 Python3 提交中击败了6.57%的用户
心得体会:
这也不快啊。。。不过真得很简单。
最终代码展示:
from collections import Counter
class Solution:
def firstUniqChar(self, s: str) -> int:
count = Counter(s)
for ind, item in enumerate(s):
if count[item] == 1:
return ind
else:
pass
return -1
思路三
这个是从大神那里看到的,因为字母就26个,所以采用 String 的特有方法, find() 和 rfind() ,一个从左向右查,一个从右往左查,两个相等时就是不重复的元素了。比较那个不重复的元素index小,就行了。虽然要遍历26遍,但也是O(N)的复杂度。
修改经历:
1. 一次成功。(第一次提交)
- 执行用时 :36 ms, 在所有 Python3 提交中击败了98.73%的用户
- 内存消耗 :13.4 MB, 在所有 Python3 提交中击败了6.81%的用户
心得体会:
自带的算法优化得很好了,find 和 rfind 相当于两个指针了。
最终代码展示:
class Solution(object):
def firstUniqChar(self, s: str) -> int:
chStr = "abcdefghijklmnopqrstvuwxyz"
mInd = len(s)
for ch in chStr:
if s.find(ch) != -1 and s.find(ch)==s.rfind(ch):
mInd = min(mInd, s.find(ch))
return mInd if mInd != len(s) else -1
思路四
用到了有序字典,这和一般的字典不一样。相比于一般的字典都是任意位置,有序字典会记录插入顺序。这也就是说只要两个字典的元素相同就可以,而有序字典的顺序也必须相同。这个函数在 collections 包中的 OrderedDict() 函数。该函数可以想数组一样操作。
修改经历:
1. 一次成功。(第一次提交)
- 执行用时 :124 ms, 在所有 Python3 提交中击败了63.75%的用户
- 内存消耗 :13.6 MB, 在所有 Python3 提交中击败了6.57%的用户
心得体会:
有序字典也慢啊。
最终代码展示:
from collections import OrderedDict
class Solution(object):
def firstUniqChar(self, s: str) -> int:
orDic = OrderedDict()
for ch in s:
orDic[ch] = orDic[ch] + 1 if ch in orDic else 1
for k, v in orDic.items():
if v == 1:
return s.index(k)
else:
pass
return -1
思路五
题解大神的思路,字典加过滤器(filter)。这里介绍下 filter() 这个 Python 的内置函数。
- 函数形式:filter(judge function(), iterable)
- 说明:filter 会将 iterable 中的元素逐一放入 judge function 中判断,并返回一个符合条件的list,这个list和iterable的形式一致。
再介绍下字典的 items() 方法。keyValuePair = dict.items() 返回的一个元组,keyValuePair[0] 是 key,keyValuePair[1] 是 value。
修改经历:
1. 没有考虑到filter返回的list的形式,在这里的filter返回的list依然是字典的形式,所以只需要把key取出来就好。(第一次提交)
- 解答错误。
2. 提交成功。(第二次提交)
- 执行用时 :128 ms, 在所有 Python3 提交中击败了60.68%的用户
- 内存消耗 :13.7 MB, 在所有 Python3 提交中击败了6.57%的用户
心得体会:
学会了filter,开心。
最终代码展示:
from collections import OrderedDict
class Solution(object):
def firstUniqChar(self, s: str) -> int:
dic = {}
for item in s:
dic[item] = dic[item] + 1 if item in dic else 1
uniqueChar = [key for key, value in filter(lambda x: x[1] == 1, dic.items())]
for ind, item in enumerate(s):
if item in uniqueChar:
return ind
else:
pass
return -1