如下所述: https://leetcode.com/problems/first-unique-character-in-a-string/description/
我在这里尝试了一次,但还是没能完成: https://paste.pound-python.org/show/JuPLgdgqceMQYh5kk0Sf/
#Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.
#xamples:
#s = "leetcode"
#return 0.
#s = "loveleetcode",
#return 2.
#Note: You may assume the string contain only lowercase letters.
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: int
"""
for i in range(len(s)):
for j in range(i+1,len(s)):
if s[i] == s[j]:
break
#But now what. let's say i have complete loop of j where there's no match with i, how do I return i?
我只对蛮力N ^ 2解决方案感兴趣,没什么好看的。上述解决方案的想法是启动一个双循环,其中内循环搜索与外循环的char匹配,如果匹配,则打破内循环并继续到外循环上的下一个char。
但问题是,当没有匹配时我该如何处理,哪时我需要将外循环的索引作为第一个唯一的索引返回。
无法找到优雅的方法,并且可以处理像单个字符串一样的边缘情况。
答案 0 :(得分:1)
迭代每个字符,并检查它是否出现在以下任何字符中。我们需要跟踪我们已经看过的角色,以避免陷入边缘情况。试试这个,它是一个O(n^2)
解决方案:
def firstUniqChar(s):
# store already seen chars
seen = []
for i, c in enumerate(s):
# return if char not previously seen and not in rest
if c not in seen and c not in s[i+1:]:
return i
# mark char as seen
seen.append(c)
# no unique chars were found
return -1
为了完整性'为了这里有一个O(n)
解决方案:
def firstUniqChar(s):
# build frequency table
freq = {}
for i, c in enumerate(s):
if c not in freq:
# store [frequency, index]
freq[c] = [1, i]
else:
# update frequency
freq[c][0] += 1
# find leftmost char with frequency == 1
# it's more efficient to traverse the freq table
# instead of the (potentially big) input string
leftidx = float('+inf')
for f, i in freq.values():
if f == 1 and i < leftidx:
leftidx = i
# handle edge case: no unique chars were found
return leftidx if leftidx != float('+inf') else -1
例如:
firstUniqChar('cc')
=> -1
firstUniqChar('ccdd')
=> -1
firstUniqChar('leetcode')
=> 0
firstUniqChar('loveleetcode')
=> 2
答案 1 :(得分:0)
将else
添加到您返回的for
循环中。
for j ...:
...
else:
return i
答案 2 :(得分:0)
我首先要注意的是,您当前查找唯一字符的算法无法正常工作。那是因为你不能假设索引i
中的字符是唯一的,因为没有索引j
在字符串后面找到相同的字符。索引i
处的字符可能是较早字符的重复(当前一个j
等于当前i
时,您已跳过该字符。)
您可以通过让j
遍历整个索引范围来修复算法,并添加额外的检查以在索引与if
相同时忽略匹配:
for i in range(len(s)):
for j in range(len(s)):
if i != j and s[i] == s[j]:
break
正如Ignacio Vazquez-Abrams在他的回答中建议的那样,您可以在内部else
循环中添加for
块,以便在找不到匹配项时返回代码:
else: # this line should be indented to match the "for j" loop
return i
如果使用Python中提供的内置函数和类型,还有一些方法可以更简单地解决这个问题。
例如,您可以仅使用一个显式循环实现与上述解决方案等效的O(n^2)
解决方案,并使用str.count
替换内部循环:
def firstUniqChar(s):
for i, c in enumerate(s):
if s.count(c) == 1:
return i
return None
我也使用enumerate
一步获取字符值和索引,而不是迭代range
并稍后编制索引。
还有一种非常简单的方法可以使用O(n)
制作collections.Counter
解决方案,在开始检查字符之前可以在一次传递中完成所有计数,以便尝试找到第一个是独一无二的:
from collections import Counter
def firstUniqChar(s):
count = Counter(s)
for i, c in enumerate(s):
if count[c] == 1:
return i
return None
答案 3 :(得分:0)
我不确定你的方法是否适用于偶数回文,例如"redder"
(请注意第二个d
)。试试这个:
s1 = "leetcode"
s2 = "loveleetcode"
s3 = "redder"
def unique_index(s):
ahead, behind = list(s), set()
for idx, char in enumerate(s):
ahead = ahead[1:]
if (char not in ahead) and (char not in behind):
return idx
behind.add(s[idx])
return -1
assert unique_index(s1) == 0
assert unique_index(s2) == 2
assert unique_index(s3) == -1
对于每个角色,我们展望未来。只有与两个组不相交的字符才会返回索引。随着迭代的进行,观察到的ahead
列表会缩短,而behind
所见的内容会延伸。默认值为-1
,如实际的leetcode挑战中所述。
不需要第二个清单。 @ÓscarLópez的答案是简化的答案。