【问题标题】:Delete all the characters in string S1 that occured in string S2删除字符串 S1 中出现在字符串 S2 中的所有字符
【发布时间】:2013-03-10 10:39:47
【问题描述】:

给定两个字符串 S1 和 S2,S = S1 - S2 定义为从 S1 中取出 S2 中的所有字符后的剩余字符串。如何尽可能快地计算任何给定字符串的 S1 - S2?

例如:

输入:

他们是学生。

哎哟

输出:

你的标准。

hash map我试过了,可惜裁判说太慢了,有没有更快的解决方案?

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool occur[300]={false};
int main()
{
    char str1[10002];
    gets(str1);
    char ch;
    while((ch=getchar())!='\n')
        occur[ch]=true;
    int i;
    for(i=0;i<strlen(str1);i++)
        if(occur[str1[i]])
            continue;
        else
            putchar(str1[i]);
    putchar('\n');
    return 0;
}

【问题讨论】:

  • “我已经尝试过哈希映射”——怎么样?有多种方法可以使用哈希表来解决这个问题。请描述您当前的算法。
  • 同意 larsmans。此问题的最快解决方案必然涉及哈希映射或数组索引。
  • 另外,虽然您没有指定语言,但我相信您已经编写了一个程序。添加您当前的实现。
  • 我不认为我在某个方面,但如果你试着看看,你可以把它们拿出来 1) en.wikipedia.org/wiki/Diff#Algorithm 2) codeproject.com/Articles/13326/… 3)paulbutler.org/archives/a-simple-diff-algorithm-in-php 我认为这些可能会有所帮助,我早点见过他们
  • 我在上面添加了我的代码,你们中的任何人都可以提出更好的解决方案吗?

标签: algorithm


【解决方案1】:

我认为你应该:

  1. 创建包含 S2 中所有字符的 HashSet S
  2. 使用 List 在您遍历 S1 时附加字符,而这些字符不在 S 中
  3. 从列表中构建字符串(Python 中的"".join(list..))

我认为没有更快的方法。您可以将 S1 分成 N 个部分并并行处理 - 这是我看到的唯一优化...

至于您的代码 - 不要在循环条件下使用 strlen!见:strlen: how does it work?。只需遍历所有字符,直到您获得 '\0' 字符或计算 strlen 一次并放入您在循环条件中使用的变量...

【讨论】:

  • 实际上,如果您的字符是 8 位的,您可能应该只使用您的字符作为数组的索引:这里不需要散列函数。根据架构,一个 255 字节的数组可能非常实惠。
  • 非常感谢,我改了代码,在线评委接受了~
【解决方案2】:

如果您可以将问题限制在较小的字母表(例如仅限英文字符),您可以创建一个与您的字母表大小相同的 bool 数组。

1 数组查找将比散列或遍历二叉树快得多。

【讨论】:

    【解决方案3】:

    可能最快和最简单的方法之一就是使用正则表达式替换。请参阅下面的示例 python 代码。

    如果您不能使用正则表达式,则需要对输入字符串的每个字符进行一次循环。由于您正在处理每个字符,因此任何算法都至少是O(n)。这意味着加快实现速度的唯一方法是减少检查字符是否需要复制到输出以及实际复制到输出所花费的时间。由于我不知道您使用的是什么语言,所以我将在 python 中给出一个简短的实现。这使用 python set 类,它允许恒定时间检查值是否在集合中。示例代码如下。

    import re
    
    def remove1(string, chars):
        return re.sub("[%s]"%chars, "", string)
    
    def remove2(string, chars):
        chars = set(chars)
        res = ""
        for c in string:
            if c not in chars:
                res += c
    
        return res
    
    import unittest
    
    class TestRemove(unittest.TestCase):
        def test_removeVowels1(self):
            self.assertEqual("Thy r stdnts.", remove1("They are students.","aeiou"))
    
        def test_removeVowels1(self):
            self.assertEqual("Thy r stdnts.", remove2("They are students.","aeiou"))
    
    if __name__=="__main__":
        unittest.main()
    

    注意:如果您使用的是 C++ 之类的语言,并且您知道输入仅限于 8 位值,那么最快的方法是使用直接寻址;即使用字符值作为数组索引。

    【讨论】:

    • 我在这里显示我的代码,但在线裁判仍然告诉我“限时”
    【解决方案4】:

    从技术上讲,Hashmap 解决方案是 O(n)+O(m),n 是句子的长度,m 是禁止字符的数量。

    在我看来,这是您拥有 来决定是否保留或丢弃该字符的句子的最快速度。此外,您必须至少遍历所有禁止字符一次才能了解它们。

    但是,我可以想象有更有效的解决方案,即更少的开销。但说实话,我想不出一个。

    更新(这是最简单的,但它是 O(n*m)。但是,对于短字符串,它可能比其他方法更快):

    foreach (c in sentence) 
      if (forbiddenChars.IndexOf(c) == -1) 
        Console.Write(c);
    

    【讨论】:

    • 我添加了我的代码,我认为这是最好的解决方案,但在线法官告诉我“限时”..
    • 您的“在线评委”肯定混淆了“简单性”和“性能”。我将在我的答案中添加一个非常简单的版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2020-08-04
    相关资源
    最近更新 更多