Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 是否可以在不使用sorted()或比O(n^2)性能更好的字典的情况下检查字谜?_Python_Algorithm - Fatal编程技术网

Python 是否可以在不使用sorted()或比O(n^2)性能更好的字典的情况下检查字谜?

Python 是否可以在不使用sorted()或比O(n^2)性能更好的字典的情况下检查字谜?,python,algorithm,Python,Algorithm,我目前正在学习,有人告诉我不要在python中使用“魔法”python技巧,如sorted()或字符串拆分 我误认为这只是使用数组来检查输入字符串是否是字谜。因此,虽然我想到的第一件事是使用字典,但我没有继续使用它,因为我认为它是被禁止的。使用字典,我可以通过使用字母作为键,计数作为值,向下计数(减去)输入字符串中遇到的字母频率,并对频率字典进行循环以查看是否有零来计算字母的频率 所以…由于对限制设置了错误的概念,我创建了一个嵌套循环,如下所示(问题假设长度相等,没有空间) 显然,这是不可取的,

我目前正在学习,有人告诉我不要在python中使用“魔法”python技巧,如sorted()或字符串拆分

我误认为这只是使用数组来检查输入字符串是否是字谜。因此,虽然我想到的第一件事是使用字典,但我没有继续使用它,因为我认为它是被禁止的。使用字典,我可以通过使用字母作为键,计数作为值,向下计数(减去)输入字符串中遇到的字母频率,并对频率字典进行循环以查看是否有零来计算字母的频率

所以…由于对限制设置了错误的概念,我创建了一个嵌套循环,如下所示(问题假设长度相等,没有空间)

显然,这是不可取的,因为对于使用字典的解决方案,大o表示法是o(n^2),即o(3n),两次迭代计算频率,最后一次迭代检查字典中的任何条目是否具有非零频率(这意味着这不是一个字谜)

因此,这是我的理解问题,但我没有继续,而是在想,有没有可能在不使用字典和仅依赖数组/列表的情况下产生一个比我的解决方案O(n^2)更好的性能更好的字谜检查器

我有另一个想法,但我停止了:

1) 将字符串列表转换为数字列表-但这意味着我仍然需要循环参考字符(原始)以查找数字位置


它一直在蚕食着我,我意识到我对这些简单的算法问题想得太多了……但我仍然好奇是否有一个解决方案符合标准。

这取决于您输入的定义。是要处理所有字符,还是只处理可打印/拉丁-1集?你关心理论上的复杂性,还是真正的性能

对于第一个问题-如果您不关心字符编码到多个字节,您可以创建一个包含256个元素的列表,而不是索引到dict中,而是索引该数组。对于每个字符,在列表中的特定位置添加/删除
1
。它的复杂性与dict解决方案相同:
O(n+m)
。(数组中的计数是
O(1)
,因为它具有预定义的大小)


对于第二个问题-如果您想不受限制地使用字符,您可以做同样的事情,但是创建一个包含
1114112
元素的列表,并按unicode字符编号进行索引。它不会比字典解决方案快,但同样-复杂性仍然是
O(n+m)

回答这个问题的python方法是使用
集合。Counter
对象:

from collections import Counter

def anagram(s1, s2):
    return Counter(s1) == Counter(s2)
但由于这些都受到限制,您可以使用普通字典(也称为hashmaps,它是许多高效算法的基本组成部分)


一个高层次的过程如下。首先,为
string1
构建计数的哈希映射。对
string2
重复此过程。最后,比较两个哈希映射是否相等

首先,辅助函数-

def build_counts(string):
    ctr = {}
    for c in string:
        ctr[c] = ctr.setdefault(c, 0) + 1

    return ctr
现在,司机-

def anagram(string1, string2):  
    c1 = build_counts(string1)
    c2 = build_counts(string2)

    return c1 == c2
复杂性分析-构建每个hashmap需要O(N)个时间,执行比较也需要O(N),因为您必须,一个测试键是否相同,另一个测试键是否相同,比较相应键的值。总之,一个线性算法


由于散列映射和散列集非常常见,您不应该认为这是有限制的,除非您计划使用数组和开放寻址实现自己的散列映射

不,没有一种高效的算法不依赖于哈希映射或更复杂的东西。除非您使用viraptor的答案,它基本上是hashmap(!)的数组版本,但是ASCII集中的每个字符都有一个唯一的条目。例如,ASCII字符65的计数将通过
arr[65]
访问,依此类推。因此,您需要有一个足够大的数组来容纳每个ASCII字符


只要ASCII字母是可以管理的,但是当你考虑其他更广泛的编码(Unicode)时,情节就会变得更复杂。最后,只使用hashmap会节省很多空间

如果不允许使用魔法功能,您可以构建自己的计数器

def计数器(字符串):
返回{i:string.count(i)for i in set(string)}


然后您可以简单地使用cᴏʟᴅsᴘᴇᴇᴅ's解决方案

这里有一种替代方法,可以在线性时间内处理“合理”长度的单词。如果不计算任意精度乘法,则该算法运行O(n)

逻辑,如果你把每个字母都分配给一个素数。两个字谜的这些素数的乘法是相同的

我希望reduce不算是一个神奇的函数

from operator import mul
from functools import reduce


def is_anagram(word_a, word_b):
    primes_26 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
                 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]

    def prime_product(word):
        return reduce(mul, [primes_26[ord(ch) - 65] for ch in word.upper() if ch.isalpha()])

    return prime_product(word_a) == prime_product(word_b)


assert is_anagram("abc", "cba") 
assert not is_anagram("abc", "cbad") 
通过比较所有26个字母并计数,得出T(n)=2n+26

O(n)

def anagram解决方案4(s1、s2):
c1=[0]*26
c2=[0]*26
对于范围内的i(len(s1)):
pos=ord(s1[i])-ord('a')
c1[pos]=c1[pos]+1
对于范围内的i(len(s2)):
pos=ord(s2[i])-ord('a'))
c2[pos]=c2[pos]+1
j=0
stillOK=True

而你可以用一个
Counter(original)=Counter(input)
应该相当于一个字谜检查。@PatrickHaugh这很好,但在这种情况下,这样的神奇功能受到限制。
Counter
实际上是一个dict,所以如果排除dict,我假设计数器也被排除。如果我要这样做,而不使用任何类型的映射类型,我会使用数组按其0-25偏移量(或0-51,如果认为大写字母不同)索引每个字母,并将计数构建到其中。如果这是为了研究,那么它可能值得精确-您提供的函数是
O(n*m)
,而您使用的字典解决方案是
from operator import mul
from functools import reduce


def is_anagram(word_a, word_b):
    primes_26 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
                 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]

    def prime_product(word):
        return reduce(mul, [primes_26[ord(ch) - 65] for ch in word.upper() if ch.isalpha()])

    return prime_product(word_a) == prime_product(word_b)


assert is_anagram("abc", "cba") 
assert not is_anagram("abc", "cbad") 
def check_anagram(data1,data2):
    
    flag = False
    if (len(data1)==len(data2)):
        if (set(data1.lower()) == set(data2.lower())):
            for i in range(len(data1)-1):
                if data1[i] != data2[i]:
                    flag = True

    return flag

print(check_anagram("Theclassroom","Schoolmaster"))