查找一个单词在字符串中出现的次数的几种方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查找一个单词在字符串中出现的次数的几种方法相关的知识,希望对你有一定的参考价值。

参考技术A var str= "i am tom today sendty moring totay today is jack today"

查找today出现的次数

第一种方法:把字符串以空格分割成数组

var strArr = str.split(' ')

var count = 0

for(var i=0;i<strArr.length;i++)

if(strArr[i]==='today')

count++



console.log(count)

第二种:递归查找

function counts(s,index)

  if(str.indexOf(s,index)!==-1 && str)

    count=count+1

    counts(s,str.indexOf(s,index)+s.length)

  



counts('today',0)

console.log(count)

3.第三种 replace 匹配元组

str.replace(/(\btoday\b)/g,function(ele)

  count++

  console.log(ele)

)

console.log(count)

查找给定单词的字谜

【中文标题】查找给定单词的字谜【英文标题】:Finding anagrams for a given word 【发布时间】:2012-09-10 17:40:37 【问题描述】:

如果其中一个词与另一个词的字符完全相同,则两个词是字谜。

例如:Anagram & Nagaram 是字谜(不区分大小写)。

现在有很多类似的问题。找出两个字符串是否是字谜的几种方法是:

1) Sort 字符串并比较它们。

2) 为这些字符串创建一个frequency map 并检查它们是否相同。

但是在这种情况下,我们得到了一个单词(为了简单起见,我们假设只有一个单词,并且它只有一个单词字谜),我们需要为此找到字谜。

我想到的解决方案是,我们可以为单词生成所有排列,并检查这些单词中的哪些存在于字典中。但显然,这是非常低效的。是的,词典也有。

那么我们有什么选择呢?

我还在一个类似的帖子中读到,可以使用 Tries 来完成某些事情,但该人没有解释算法是什么以及为什么我们首先使用 Trie,只是提供了一个实现在 Python 或 Ruby 中。所以这并没有真正的帮助,这就是我创建这个新线程的原因。如果有人想分享他们的实现(C、C++ 或 Java 除外),也请解释一下。

【问题讨论】:

可以帮助您寻找答案的方法:***.com/questions/7896694/… 基本上,您可以做的是使用哈希函数为字谜产生相同的值,然后将您的字典转换为允许获取给定此类哈希的单词列表。 你真正想做什么?从给定的一组字母中找出存在于固定字典中的所有字谜?或者在固定字典中的所有单词上建立一个字谜关系,即给定该字典中的一个单词,有效地检索所有有效的字谜? 给定一个具有固定单词集的字典和一个随机单词(可能在字典中或不在字典中),找到它的字谜(在字典中存在)。有意义吗? 【参考方案1】:

示例算法:

Open dictionary
Create empty hashmap H
For each word in dictionary:
  Create a key that is the word's letters sorted alphabetically (and forced to one case)
  Add the word to the list of words accessed by the hash key in H

检查给定单词的所有字谜:

Create a key that is the letters of the word, sorted (and forced to one case)
Look up that key in H
You now have a list of all anagrams

构建速度相对较快,查找速度极快。

【讨论】:

按字母顺序对单词进行排序以生成密钥是一个好主意。尽管查找后要小心,但您仍然需要清除潜在的误报。仅仅因为两个单词具有相同的哈希值,并不意味着它们必然相等(尽管在通用语言中很可能如此)。仍然有一些错误的余地。 @mprivat 如果您能找到两个具有相同排序字母序列且彼此不是字谜的单词,我会很高兴(注意,我们不会丢弃任何字母,关键是"banana" 将是 'aaabnn',而任何具有该键的其他词必然必须是 "banana" 的变位词)。 我不是在谈论排序的字母序列,我是在谈论它的数字哈希(哈希映射实际上将用作键)。但我猜根据您使用的语言,hashmap 实现将处理密钥冲突。 @mprivat 啊,是的,一个典型的 hashmap 实现应该在给你结果之前区分两个具有相同哈希的不同键。 @Vatine 我们在哪里使用了 TRIE ds?【参考方案2】:

我想我想出了一个新的解决方案。它使用算术基本定理。所以这个想法是使用前 26 个素数的数组。然后对于输入单词中的每个字母,我们得到相应的素数 A = 2、B = 3、C = 5、D = 7 ……然后我们计算输入单词的乘积。接下来,我们对字典中的每个单词执行此操作,如果一个单词与我们的输入单词匹配,那么我们将其添加到结果列表中。所有字谜都将具有相同的签名,因为

任何大于 1 的整数要么是素数,要么可以写成 作为素数的唯一乘积(忽略顺序)。

这是代码。我将单词转换为大写,65 是 A 的位置,对应于我的第一个素数:

private int[] PRIMES = new int[]  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, 103,
        107, 109, 113 ;

这是方法:

 private long calculateProduct(char[] letters) 
    long result = 1L;
    for (char c : letters) 
        if (c < 65) 
            return -1;
        
        int pos = c - 65;
        result *= PRIMES[pos];
    
    return result;

【讨论】:

它本质上是另一种创建密钥的方法,该密钥对于所有相互变位的单词都是唯一的,即具有相同的字母集。这是一个好主意,但更明显的方法是按字母顺序对字母进行排序(或者你想要的任何方式,只要它是一致的)。例如。按字母顺序排列的键是 aaabcehilllpty。我想知道您是否会产生更紧凑的密钥,因此有可能提高计算效率。 你的也是一个好主意,确实。排序比乘法要贵一点。 Sorting is a bit more expensive than multiplication 好点。在这种情况下,我认为我更喜欢您使用素数的方法。我会进一步调查。 我用过这个方法 之前。当我看到有人在我之前想到它时,我有点沮丧,哈哈。一个实验是(我没有尝试过)尝试非常长的单词来查看产品是否可以存储一个长整数。肺超显微硅火山尘肺病示例。【参考方案3】:

我们知道,如果两个词的长度不同,它们就不是字谜。因此,您可以将字典划分为相同长度的单词组。

现在我们只关注其中一个组,基本上所有单词在这个较小的宇宙中都具有完全相同的长度。

如果每个字母位置都是一个维度,并且该维度中的值基于字母(例如 ASCII 码)。然后就可以计算词向量的长度了。

例如,说“A”=65、“B”=66,然后是length("AB") = sqrt(65*65 + 66*66)。显然,length("AB") = length("BA")

显然,如果两个词是字谜,那么它们的向量具有相同的长度。下一个问题是,如果两个单词(具有相同数量的字母)向量具有相同的长度,它们是字谜吗?直觉上,我会说不,因为所有具有该长度的向量都形成一个球体,所以有很多。不确定,因为在这种情况下我们在整数空间中,实际上有多少。

但至少它允许您进一步划分您的字典。对于字典中的每个单词,计算向量的距离: for(each letter c) distance += c*c ; distance = sqrt(distance);

然后为所有长度为n 的单词创建一个映射,并用距离作为关键字,值是产生该特定距离的长度为n 的单词列表。

您将为每个距离创建一张地图。

那么你的查找变成如下算法:

    根据单词的长度使用正确的字典图 计算单词向量的长度 查找与该长度匹配的单词列表 浏览列表并使用简单算法挑选字谜,现在候选列表大大减少了

【讨论】:

这更像是一种启发式方法?【参考方案4】: 将单词缩减为小写 (clojure.string/lower-case)。 按字母频率图 (frequencies) 对它们进行分类 (group-by)。 删除频率图, ...离开字谜集合。

(These) 是 Lisp 方言 Clojure 中的对应函数。

整个函数可以这样表示:

(defn anagrams [dict]
  (->> dict
       (map clojure.string/lower-case)
       (group-by frequencies)
       vals))

例如,

(anagrams ["Salt" "last" "one" "eon" "plod"])
;(["salt" "last"] ["one" "eon"] ["plod"])

将每个事物映射到其集合的索引函数是

(defn index [xss]
  (into  (for [xs xss, x xs] [x xs])))

例如,

((comp index anagrams) ["Salt" "last" "one" "eon" "plod"])
;"salt" ["salt" "last"], "last" ["salt" "last"], "one" ["one" "eon"], "eon" ["one" "eon"], "plod" ["plod"]

... 其中comp 是函数组合运算符。

【讨论】:

【参考方案5】:

Well Tries 可以更容易地检查单词是否存在。 因此,如果您将整个字典放在一个 trie 中:

http://en.wikipedia.org/wiki/Trie

然后您可以信守诺言并通过获取一个字符并递归地检查我们是否可以使用其余字符的任何组合(一次添加一个字符)“走”下 Trie 来进行简单的回溯。当递归分支中使用了所有字符并且 Trie 中存在有效路径时,则该单词存在。

Trie 有帮助,因为它是一个很好的停止条件: 我们可以检查字符串的一部分,例如“Anag”是否是 trie 中的有效路径,如果不是,我们可以打破那个特定的递归分支。这意味着我们不必检查字符的每一个排列。

在伪代码中

checkAllChars(currentPositionInTrie, currentlyUsedChars, restOfWord)
    if (restOfWord == 0)
    
         AddWord(currentlyUsedChar)
    
    else 
    
        foreach (char in restOfWord)
        
            nextPositionInTrie = Trie.Walk(currentPositionInTrie, char)
            if (nextPositionInTrie != Positions.NOT_POSSIBLE)
            
                checkAllChars(nextPositionInTrie, currentlyUsedChars.With(char), restOfWord.Without(char))
            
           
    

显然,您需要一个不错的 Trie 数据结构,它允许您逐步“走”下树并检查每个节点是否存在具有给定字符的路径到任何下一个节点...

【讨论】:

你能举个例子吗?从你的描述看不太清楚。【参考方案6】:
static void Main(string[] args)


    string str1 = "Tom Marvolo Riddle";
    string str2 = "I am Lord Voldemort";

    str2=  str2.Replace(" ", string.Empty);
    str1 = str1.Replace(" ", string.Empty);
    if (str1.Length != str2.Length)
        Console.WriteLine("Strings are not anagram");
    else
    
        str1 = str1.ToUpper();
        str2 = str2.ToUpper();
        int countStr1 = 0;
        int countStr2 = 0;
        for (int i = 0; i < str1.Length; i++)
        
            countStr1 += str1[i];
            countStr2 += str2[i];

        
        if(countStr2!=countStr1)
            Console.WriteLine("Strings are not anagram");
        else Console.WriteLine("Strings are  anagram");

    
    Console.Read();

【讨论】:

您能否详细说明您的答案并描述它是如何解决问题的,并提及除了现有答案之外它还提供了什么?【参考方案7】:

生成所有排列很容易,我猜你担心在字典中检查它们的存在是“非常低效”的部分。但这实际上取决于您用于字典的数据结构:当然,单词列表对于您的用例来说效率低下。说到Tries,它们可能是一个理想的表示,而且效率也很高。

另一种可能性是对您的字典进行一些预处理,例如构建一个哈希表,其中键是排序后的单词字母,值是单词列表。您甚至可以序列化此哈希表,以便将其写入文件并在以后快速重新加载。然后要查找字谜,您只需对给定的单词进行排序并在哈希表中查找相应的条目。

【讨论】:

生成排列本身是 O(n!) 并且非常低效。 @sTEAK O(n!) 算不上平均单词长度。 即使是 10 长的单词也会像 O(3628800)【参考方案8】:

这取决于您存储字典的方式。如果是简单的单词数组,没有算法比线性更快。

如果它已排序,那么这是一种可行的方法。我刚刚发明了它,但我猜它比线性方法更快。

    将您的字典表示为 D,当前前缀为 S。S = 0; 您为您的单词创建频率图。让我们用 F 来表示它。 使用二分查找查找字典中每个字母开头的指针。让我们用 P 来表示这个指针数组。 对于从 A 到 Z 的每个字符 c,如果 F[c] == 0,则跳过它,否则 S += c; F[c] --; P 递归调用第 4 步,直到找到与您的单词匹配或直到您发现不存在这样的匹配。

无论如何,我会这样做。应该有更传统的方法,但这种方法比线性方法更快。

【讨论】:

将字典存储为 TRIE。【参考方案9】:

尝试实现hashmap解决方案

public class Dictionary 

    public static void main(String[] args)

    String[] Dictionary=new String[]"dog","god","tool","loot","rose","sore";

    HashMap<String,String> h=new HashMap<String, String>();

    QuickSort q=new QuickSort();

    for(int i=0;i<Dictionary.length;i++)

        String temp =new String();

        temp= q.quickSort(Dictionary[i]);//sorted word e.g dgo for dog

        if(!h.containsKey(temp))
           h.put(temp,Dictionary[i]);
        

        else
        
           String s=h.get(temp);
           h.put(temp,s + " , "+ Dictionary[i]);
        
    

    String word=new String()"tolo";

    String sortedword = q.quickSort(word);

    if(h.containsKey(sortedword.toLowerCase())) //used lowercase to make the words case sensitive

        System.out.println("anagrams from Dictionary   :  " + h.get(sortedword.toLowerCase()));
    


【讨论】:

【参考方案10】: 计算字典中每个单词的频率计数向量,一个字母列表长度的向量。 生成字母列表长度的随机高斯向量

在这个随机方向上投影每个字典单词的计数向量并存储值(插入以便对值数组进行排序)。

给定一个新的测试词,将其投影到与字典词相同的随机方向。

进行二分搜索以查找映射到相同值的单词列表。 验证如上获得的每个单词是否确实是一个真正的字谜。如果没有,请将其从列表中删除。 返回列表的剩余元素。

PS:上述过程是对素数过程的概括,可能会导致大数(并因此导致计算精度问题)

【讨论】:

【参考方案11】:
# list of words
words = ["ROOPA","TABU","OOPAR","BUTA","BUAT" , "PAROO","Soudipta",
        "Kheyali Park", "Tollygaunge", "AROOP","Love","AOORP",
         "Protijayi","Paikpara","dipSouta","Shyambazaar",
        "jayiProti", "North Calcutta", "Sovabazaar"]

#Method 1
A = [''.join(sorted(word)) for word in words]

dict =

for indexofsamewords,samewords in enumerate(A):
    dict.setdefault(samewords, []).append(indexofsamewords)
    
print(dict)
#'AOOPR': [0, 2, 5, 9, 11], 'ABTU': [1, 3, 4], 'Sadioptu': [6, 14], ' KPaaehiklry': [7], 'Taeggllnouy': [8], 'Leov': [10], 'Paiijorty': [12, 16], 'Paaaikpr': [13], 'Saaaabhmryz': [15], ' CNaachlortttu': [17], 'Saaaaborvz': [18]

for index in dict.values(): 
    print( [words[i] for i in index ] )
    
    

输出:

['ROOPA', 'OOPAR', 'PAROO', 'AROOP', 'AOORP']
['TABU', 'BUTA', 'BUAT']
['Soudipta', 'dipSouta']
['Kheyali Park']
['Tollygaunge']
['Love']
['Protijayi', 'jayiProti']
['Paikpara']
['Shyambazaar']
['North Calcutta']
['Sovabazaar']

【讨论】:

【参考方案12】:

一种解决方案是 - 将质数映射到字母字符并乘以质数

For ex - 

    a -> 2
    b -> 3
    ......
    .......
    ......
    z -> 101

所以

'ab' -> 6
'ba' -> 6
'bab' -> 18
'abba' -> 36
'baba' -> 36

获取给定单词的 MUL_number。返回字典中与给定单词具有相同 MUL_number 的所有单词

【讨论】:

这是上面发布的方法。【参考方案13】:

首先检查字符串的长度是否相同。 然后检查两个字符串中的字符之和是否相同(即ascii代码和) 然后这些词是字谜 否则不是字谜

【讨论】:

以上是关于查找一个单词在字符串中出现的次数的几种方法的主要内容,如果未能解决你的问题,请参考以下文章

面试题总结1统计字符串中某个单词出现的次数

P1308(字符串类,处理字符串查找)

查找给定单词的字谜

vim怎么正则查询一个词出现的次数

查找并计算字符串中提到的单词(python 3)[重复]

华为python机试题目:整数与IP地址间的转换图片整理字串的连接最长路径查找提取不重复的整数字符串合并处理字符串最后一个单词的长度删除字符串中出现次数最少的字符