我这里有这个代码,它应该从列表n1和n2中删除常用字母。但是当我运行这个代码时,它只运行一次,因为它只从n1和n2中删除'a'并且不会删除'k'。
只是为了澄清这段代码应该只能用于2个单词。
name1 = "abdjek"
name2 = "doarhsnk"
n1l = list(name1)
n2l = list(name2)
for i in range(len(n1l)):
for j in range(len(n2l)):
if n1l[i] == n2l[j]:
n1l.pop(i)
n2l.pop(j)
n1l.append('0')
n2l.append('1')
好的等等,它似乎适用于上述两个名字但是当我有name1 =“naveen”而name2 =“darshana”时它不起作用!
答案 0 :(得分:5)
我建议采用一种更简单的方法:
def removecommon(name1, name2):
common = set(name1).intersection(name2)
res1 = ''.join(n for n in name1 if n not in common)
res2 = ''.join(n for n in name2 if n not in common)
return res1, res2
n1, n2 = removecommon('naveen', 'darshana')
print n1, n2
根据需要发出vee drsh
。
修改:正如现在指定的OP(在评论中 - 请记住编辑你的问题,哦OP!)他实际上只想删除在每个普通字母的每个单词中出现第一次,所需的算法当然是完全不同的。一种简单的方法(如果单词的长度不是太高,则可行):
def removefirstcommon(name1, name2):
common = set(name1).intersection(name2)
n1 = list(name1)
for c in common: n1.remove(c)
n2 = list(name2)
for c in common: n2.remove(c)
return ''.join(n1), ''.join(n2)
一个更精细的方法(对于正常长度的单词来说速度慢)对于极长的单词会更快(因为以下是O(N)而前者的O(N平方)):
def removefirstcommonlongwords(name1, name2):
common = set(name1).intersection(name2)
def mustrem(c, copycom):
res = c not in copycom
copycom.discard(c)
return res
cop = set(common)
n1 = [c for c in name1 if mustrem(c, cop)]
n2 = [c for c in name2 if mustrem(c, common)]
return ''.join(n1), ''.join(n2)
答案 1 :(得分:2)
更多 pythonic 方法是使用set
和列表推导。
name1 = "naveen"; name2 = "darshana"
name1_set=set(name1)
name2_set=set(name2)
clean1=[x for x in name1 if x not in name2_set]
clean2=[x for x in name2 if x not in name1_set]
clean1.extend(['0']*(len(name1)-len(clean1)))
clean2.extend(['1']*(len(name2)-len(clean2)))
print clean1,clean2
set
为我们提供了O(1)查找,从而通过将O(N)代替O(N ^ 2)使整个过程更快。
编辑:根据您之后的评论,发生次数很重要,这是考虑到这一点的更新版本。
name1 = "naveen"; name2 = "darshana"
count1={}
count2={}
for x in name1:
count1[x]=count1.get(x,0)+1
for x in name2:
count2[x]=count2.get(x,0)+1
def remove_dups(name,count,null):
clean=[]
for x in name:
if count.get(x,0):
count[x]-=1
else:
clean.append(x)
clean.extend([null]*(len(name)-len(clean)))
return clean
clean1=remove_dups(name1,count2,'0')
clean2=remove_dups(name2,count1,'1')
print clean1,clean2
它使用dict
来保持发生次数。每当删除一个字符时,另一个名称的相应计数就会减少。复杂性仍然是O(N)。
它会打印['v', 'e', 'e', 'n', '0', '0']
和['d', 'r', 's', 'h', 'a', 'a', '1', '1']
。那是你想要的吗?
答案 2 :(得分:0)
它在这里为我工作。也就是说,如果我这样添加print语句:
name1 = "abdjek"
name2 = "doarhsnk"
n1l = list(name1)
n2l = list(name2)
print "Lists before loop:"
print n1l
print n2l
for i in range(len(n1l)):
for j in range(len(n2l)):
if n1l[i] == n2l[j]:
n1l.pop(i)
n2l.pop(j)
n1l.append('0')
n2l.append('1')
print "Lists after loop:"
print n1l
print n2l
字符'a','d'和'k'全部删除:
> python test.py
Lists before loop:
['a', 'b', 'd', 'j', 'e', 'k']
['d', 'o', 'a', 'r', 'h', 's', 'n', 'k']
Lists after loop:
['b', 'j', 'e', '0', '0', '0']
['o', 'r', 'h', 's', 'n', '1', '1', '1']
答案 3 :(得分:0)
您的代码可能无法正常工作,因为它正在删除成对的字母。例如,你看到a,然后从你的单词中删除两个......
答案 4 :(得分:0)
您的代码很可能失败,因为您从列表中的任何位置弹出常用字母,但将替换(“0”和“1”)附加到列表的 end 。它们应分别位于 i 和 j 的位置。
所以循环应该看起来像这样:
for i in range(len(n1l)):
for j in range(len(n2l)):
if n1l[i] == n2l[j] and n1l[i] not in ("0", "1"):
print "common letter ", n1l[i]
# Replace i-th and j-th element
n1l[i] = "0"
n2l[j] = "1"
无论如何,还有更多“pythonic”方式,已经在其他答案中显示出来了。
编辑:对name1 = "naveen"
/ name2 = "darshana"
进行了测试和工作。
答案 5 :(得分:0)
这是一些在O(n)中运行的完全(恕我直言,相当优雅)的代码。如果单词1出现字母x的N次,它会从单词2中删除前N个(反之亦然) - 我认为这就是你想要的,但我可能是错的。
from collections import defaultdict
def build(s, chars_s, chars_t):
"""Return characters of s, with duplicate characters from t removed."""
for i, char in enumerate(s):
indexes_s, indexes_t = chars_s[char], chars_t[char]
if len(indexes_s) > len(indexes_t) and i >= indexes_s[len(indexes_t)]:
yield char
def rm_dup(a, b):
"""Pairwise remove duplicate letters in a and b."""
chars_a, chars_b = defaultdict(list), defaultdict(list)
for i, char in enumerate(a): chars_a[char].append(i)
for i, char in enumerate(b): chars_b[char].append(i)
return (''.join(build(a, chars_a, chars_b)),
''.join(build(b, chars_b, chars_a)))
print rm_dup('naveen', 'darshana')