给定一个字符串,找到其中的第一个非重复字符并返回其索引。如果它不存在,则返回-1。
first_unique('leetcode') # 0
first_unique('loveleetcode') # 2
我提出了以下解决方案。如何才能使非常长的输入字符串更有效?
def first_unique(self, s):
if s == '':
return -1
for item in s:
if s.count(item) == 1:
return s.index(item)
break
return -1
答案 0 :(得分:4)
我的解决方案使用Counter
模块中的collections
。
from collections import Counter
def first_unique(s):
c = Counter(s)
for i in range(len(s)):
if c[s[i]] == 1:
return i
return -1
答案 1 :(得分:4)
Suave版本:
from collections import Counter, OrderedDict
class OrderedCounter(Counter, OrderedDict):
pass
def first_unique(s):
counter = OrderedCounter(s)
try:
return counter.values().index(1)
except ValueError:
return -1
奇怪的版本:
from collections import OrderedDict
def first_unique(s):
nah = {0}-{0} # funny pair of eyes
yeah = OrderedDict()
for i,c in enumerate(s):
if c not in nah:
try:
del yeah[c]
except KeyError:
yeah[c] = i
else:
nah.add(c)
return next(yeah.itervalues(), -1)
答案 2 :(得分:1)
对于“好”字符串的少数情况,你的版本也不错......但对于长“坏”字符串使用count非常昂贵,我建议你缓存项目,例如:
def f1(s):
if s == '':
return -1
for item in s:
if s.count(item) == 1:
return s.index(item)
break
return -1
def f2(s):
cache = set()
if s == '':
return -1
for item in s:
if item not in cache:
if s.count(item) == 1:
return s.index(item)
else:
cache.add(item)
return -1
import timeit
import random
import string
random.seed(1)
K, N = 500, 100000
data = ''.join(random.choice(string.ascii_uppercase + string.digits)
for _ in range(K))
print(
timeit.timeit('f1(data)', setup='from __main__ import f1, data', number=N))
print(
timeit.timeit('f2(data)', setup='from __main__ import f2, data', number=N))
我的笔记本电脑上的结果是:
32.05926330029437
4.267771588590406
使用缓存的版本为您提供8倍的加速因子,而不是您使用计数功能。所以,我的一般建议是......尽可能地缓存是否可能
编辑:
我已经将Patrick Haugh版本添加到基准测试中,它给了10.92784585620725
EDIT2:
我已将Mehmet Furkan Demirel版本添加到基准测试中,它给了10.325440507549331
EDIT3:
我已经在基准测试中添加了wim版本,它给了12.47985351744839
结论:
我使用的是我最初提出的使用简单缓存而不依赖于Python计数器模块的版本,它没有必要(就性能而言)
答案 3 :(得分:0)
我会使用for循环从开头和每个索引迭代php artisan migrate
,我会使用Substring检查String
的其余部分是否在当前索引处具有该字符。 / p>
试试这个:
String
希望它有所帮助!
答案 4 :(得分:0)
此解决方案的想法是使用一对默认值。第一个包含每个字符的整数计数,第二个包含最新字符读取的索引位置。
在阅读完所有字符后,列表理解用于查找仅发生过一次的所有字符(result
)。这些字符的最小索引位置(在我们的其他defaultdict order
中找到)将为我们提供非重复字符的第一个索引位置。
from collections import defaultdict
# To Create random string:
from string import ascii_lowercase
from random import choice, randint, seed
# Create a random sentence of 1000 words (1-8 characters each).
seed(0)
gibberish = ' '.join(''.join(choice(ascii_lowercase)
for _ in range(randint(1, 8)))
for _ in range(1000))
print(len(gibberish))
# Output: 5614
# Solution.
def first_unique(s):
dd = defaultdict(int)
order = defaultdict(int)
for n, c in enumerate(s):
dd[c] += 1
order[c] = n
result = [order[c] for c in dd if dd[c] == 1]
return min(result) if result else -1
%timeit first_unique(gibberish)
100 loops, best of 3: 2.13 ms per loop
@wim solution:
%timeit first_unique(gibberish)
100 loops, best of 3: 5.06 ms per loop
@PatrickHaugh solution (which is much easier to understand than mine):
%timeit first_unique(gibberish)
100 loops, best of 3: 4.2 ms per loop
@BPL solution:
%timeit f1(gibberish)
10 loops, best of 3: 39.2 ms per loop
%timeit f2(gibberish)
1000 loops, best of 3: 890 µs per loop
使用更短的20个单词(133个字符)的句子:
%timeit first_unique(gibberish)
10000 loops, best of 3: 62.8 µs per loop
@wim solution:
%timeit first_unique(gibberish)
10000 loops, best of 3: 169 µs per loop
@PatrickHaugh solution:
%timeit first_unique(gibberish)
10000 loops, best of 3: 101 µs per loop
@BPL solution:
%timeit f1(gibberish)
10000 loops, best of 3: 55.1 µs per loop
%timeit f2(gibberish)
10000 loops, best of 3: 31 µs per loop
s1 = 'leetcode'
s2 = 'loveleetcode'
>>> first_unique(s1)
0
>>> first_unique(s2)
2
答案 5 :(得分:0)
public class Main{
public static void main(String[] args) {
System.out.println("Input String : GirishRathi");
System.out.println("Output String : " +firstUniqChar("GirishRathi"));
}
public static int firstUniqChar(String s) {
Map<Character , Integer> map = new HashMap<Character , Integer>();
for(int i = 0 ; i < s.length() ; i++) {
char current = s.charAt(i);
if(map.containsKey(current)) {
map.put(current, -1);
}else {
map.put(current , i);
}
}
int min = Integer.MAX_VALUE;
for(char c : map.keySet()) {
if(map.get(c) > -1 && map.get(c) < min) {
min = map.get(c);
}
}
return min == Integer.MAX_VALUE ? -1 : min;
}
}
答案 6 :(得分:0)
字符串中的第一个唯一字符具有以下属性。
public int firstUniqChar(String s) {
int result = s.length();
for(char c = 'a'; c <= 'z'; c++){
int i = s.indexOf(c);
if(i != -1 && i == s.lastIndexOf(c)){
result = Math.min(result, i);
}
}
return result == s.length() ? -1 : result;
}
答案 7 :(得分:0)
这种方法是什么?
def first_unique_letter(text):
for c in range(0, len(text)):
if text[c] not in text[0:c] and text[c] not in text[c + 1:len(text)]:
return text[c]
return "_"
它会在找到第一个唯一字母后中断for循环,因此比等待整个循环结束更好。如果没有唯一字符,则返回“ _”