【问题标题】:Reversal and removing of duplicates in a sentence反转和删除句子中的重复项
【发布时间】:2015-07-15 13:17:20
【问题描述】:

我正在准备一个面试问题。其中一个问题是还原一个句子。比如“今天真棒”到“今天真棒”。之后,他们问是否有重复,你能把重复的“我很好,他好吗”去掉“他很好,我好吗”这样的重复.

为了反转句子我写了以下方法

public static string reversesentence(string one)
{
    StringBuilder builder = new StringBuilder();

    string[] split = one.Split(' ');
    for (int i = split.Length-1; i >= 0; i--)
    {

        builder.Append(split[i]);
        builder.Append(" ");
    }
    return builder.ToString();

}

但是我没有关于删除重复的想法。我可以在这里获得一些帮助吗?

【问题讨论】:

  • 你可以使用字符串操作
  • 好吧,一种天真的方法可能是检查split[i] 是否在split[i+1]split[split.Length -1] 之间发生过,我猜!
  • 使用某种散列也很有帮助。使用单词作为键并将其赋值为 1。同一个单词出现多次只会将 1 赋值给现有值。我不知道如何在 C# 中做到这一点,但我一直在 Perl 中做到这一点。
  • 注意标点符号。您的代码可能不会以第二个示例显示的方式处理逗号(尽管没有删除重复项)。

标签: c#


【解决方案1】:

这行得通:

public static string reversesentence(string one)
{
    Regex reg = new Regex("\\w+");
    bool isFirst = true;
    var usedWords = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase);
    return String.Join("", one.Split(' ').Reverse().Select((w => {
        var trimmedWord = reg.Match(w).Value;
        if (trimmedWord != null) {
            var wasFirst = isFirst;
            isFirst = false;

            if (usedWords.Contains(trimmedWord)) //Is it duplicate?
                return w.Replace(trimmedWord, ""); //Remove the duplicate phrase but keep punctuation

            usedWords.Add(trimmedWord);

            if (!wasFirst) //If it's the first word, don't add a leading space
                return " " + w;
            return w;
        }
        return null;
    })));
}

基本上,我们根据没有标点符号的单词来判断它是否不同。如果它已经存在,只需返回标点符号。如果不存在,则打印出包括标点在内的整个单词。

标点符号还会删除您示例中的空格,这就是为什么我们不能只做String.Join(" ", ...)(否则结果将是good he Is , am I而不是good he Is, am I

测试:

reversesentence("I am good, Is he good").Dump();

结果:

good he Is, am I

【讨论】:

  • "(\\b)?\\w+(\\b)?" 可选的边界检查看起来很可疑。就像你根本不检查它一样。
  • @nhahtdh 词不需要定义为词的边界,但它们可以有边界。例如,A B - A 在末尾有边界,B 没有边界。 A 没有边界,`A` 开始有边界,但没有结束。它肯定会检查它,但它不需要它。
  • @nhahtdh 没关系,我今天没有直截了当地思考......你是对的 - 在所有情况下它都不需要拾取边界。我会更新代码
【解决方案2】:

对于简单的反转:

String.Join(" ", text.Split(' ').Reverse())

对于删除重复的逆转:

String.Join(" ", text.Split(' ').Reverse().Distinct())

两者都适用于仅包含空格作为分隔符的字符串。当您介绍, 时,问题变得更加困难。如此之多,以至于您需要指定应该如何处理它。例如,"I am good, Is he good" 应该变成 "good he Is am I" 还是 "good he Is , am I"?您在问题中的示例更改了 "Is" 的大小写,并将 "," 也与其分组。这对我来说似乎是错误的。

【讨论】:

  • 能保证Distinct不改顺序吗?
  • @raznagul - 是的,这是有保证的。该算法按顺序遍历可枚举对象,并且仅在第一次看到它们时才产生值。
【解决方案3】:

另一个答案指向使用抽象,但面试官通常希望看到实现。

对于反转,通常的技巧是先反转句子,然后在从左到右移动时反转每个单词。你会告诉你一个空格,你已经到了一个单词的结尾。 (有关此问题的解决方案,请参阅公开的编程面试,或者只是谷歌它。这曾经是一个非常流行的面试问题)。您的方法有效,但由于您使用了额外的空间 (O(n)),因此不受欢迎。

对于删除重复项,如果您只使用 ASCII,则可以执行以下操作:

    bool[] seenChars = new bool[128];
    var sb = new StringBuilder();

    foreach(char c in stringOne)
    {
        if(!seenChars[c]){
            seenChars[c] = true;
            sb.Append(c);
        }
    }

    return sb.ToString();

这个想法是使用 char 的值作为数组中的索引来告诉你你以前是否见过这个字符。使用这种方法,您将使用 O(1) 空间!

编辑:如果您想删除重复的单词,您可能需要使用 HashSet,如果它已经存在则跳过添加它。

【讨论】:

    【解决方案4】:

    试试这个

    string sentence = "I am good, Is he good";
    
    
            var words = sentence.Split(new char[]{' ',','}).Distinct(StringComparer.CurrentCultureIgnoreCase);
    
            var stringBuilder = new StringBuilder();
    
            foreach(var item in words)
            {
                stringBuilder.Append(item);
                stringBuilder.Append(" ");
            }
            Console.Write(stringBuilder);
            Console.ReadLine();
    

    【讨论】:

    • 1) string.Join 是你的朋友。 2) 产生一个尾随空格 3) 它不会反转。
    猜你喜欢
    • 2021-07-26
    • 1970-01-01
    • 2020-12-30
    • 2017-05-19
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    相关资源
    最近更新 更多