使String变得漂亮或丑陋的算法

时间:2009-07-15 17:08:51

标签: algorithm language-agnostic

我很难找到以下谜题的算法 - 如果一个字符串连续有3个元音,或者连续有5个辅音,或者两者都有,则称为丑陋。如果字符串不丑,则称其为nice。给你一个字符串s,由大写字母('A' - 'Z')和问号('?')组成。 你能找到一个算法,通过用字母替换问号来判断字符串是否可以变好吗?

示例 -

  1. “EE?FFFF” - 不能做得很好。插入辅音或元音会使它变得难看。

  2. “H 22 LOWOR ??” - 可以做得很好。

  3. P.S - 不是家庭作业,而是互联网上编程难题的一部分。

8 个答案:

答案 0 :(得分:12)

请注意,唯一可能丑陋的字符串是由于给定字母或仅包含单例问号而已经丑陋的字符串。这是证明的草图:

  • 对于任何两个问号的集合,使左侧问号与左侧邻居相反,右侧问号与右侧邻居相反。例如。 V ?? C应该成为VCVC。如果它不是丑陋的话,这样的替换永远不会变成难看的字符串。
  • 对于任何三个或更多个问号的集合,设置最左边和最右边的问号,然后在V和C之间交替使用中间问号。这可能会导致引入两个连续的V或C,但从不引入三个。 / LI>

所以,我们留下了两个简单的案例。

  • 检查字符串是否已经丑陋是一个简单的正则表达式。
  • 单身人士可以将字符串变得难看的唯一情况是问号是否有一个元音到一侧,四个辅音到另一侧;但你不能只检查那些,因为替换可能会引入这样的模式(考虑EE?FFF?EE)。但是在这一点上,您可以通过从左到右进行检查,通过插入右邻居的相反方法来解决每个单例问号,除非这会使字符串变得难看并且如果存在两个元音/四个辅音模式则停止。

答案 1 :(得分:5)

Haskell中的解决方案:

import System (getArgs)

nicePart :: Int -> Int -> String -> Bool
nicePart 3 _ _  = False
nicePart _ 5 _  = False
nicePart _ _ "" = True
nicePart v c ('?':as) = nicePart (v+1) 0 as || nicePart 0 (c+1) as
nicePart v c (a:as)
   | a `elem` "AEIOU" = nicePart (v+1) 0 as
   | otherwise        = nicePart 0 (c+1) as

nice :: String -> Bool
nice as = nicePart 0 0 as

main = getArgs >>= print . nice . unwords

该函数记录到当前点已经看到多少个连续元音和辅音。如果有太多,则返回False。如果找到问号,则进行两次递归调用,一次将问号计为元音,一次作为辅音,检查这些变化是否合适。

答案 2 :(得分:3)

这是关键:从丑陋到美好的可转换性取决于一定长度的辅音或元音。因此,如果将一个块转换为nice将必然预测另一个块的丑陋,则无法完成。

对于懒得做自己的家庭作业的人来说,实施是一种练习。 : - )

答案 3 :(得分:2)

您可以做的是迭代每个问号,并测试插入元音或问号的每种可能组合。

例如(V =>元音,C =>辅音)

  1. “EE?FFFF”
    VVVCCCC
    VVCCCCC
    这两种可能性,正如你所知,它们都是丑陋的。

答案 4 :(得分:2)

有一个与丑陋相匹配的正则表达式:

[aeiouAEIOU]{3}|[a-zA-Z&&[^aeiouAEIOU]]{5}

现在,如果在元音序列中发生?,您可以将其变成辅音。如果它发生在一系列辅音内,你可以把它变成一个元音。如果问号出现在边界上,则会出现问题:

[aeiouAEIOU]{2}\?[a-zA-Z&&[^aeiouAEIOU]]{4}
[a-zA-Z&&[^aeiouAEIOU]]{4}\?[aeiouAEIOU]{2}

在每种情况下,都没有解决方案。现在,如果有两个问号,一个接一个,如果序列是:

,就会出现问题
[aeiouAEIOU]{2}\?\?[aeiouAEIOU]{2}
[a-zA-Z&&[^aeiouAEIOU]]{4}\?\?[a-zA-Z&&[^aeiouAEIOU]]{4}

这些也没有解决方案。如果有两个以上的问号,那么你可以解决它。

所以,搜索那些模式,加上“纯粹的”丑陋模式。如果它们中的任何一个发生,你就无法改变。否则,没关系。

答案 5 :(得分:0)

您是否尝试过迭代整个字母表并尝试每种组合以查看它是否“丑陋”?

尝试用字母替换每个问号然后检查有效性,这是最简单,最不理想的方式。例如:

EEF?d?

我会开始填写?这些组合:

AAA AAB AAC AAD

编辑:不,你不必遍历整个字母表,只需A和B即可。或者真的,只是任何元音和任何辅音。

答案 6 :(得分:0)

正如已经指出的那样,有一种蛮力,效率极低的方法可行。有趣的是增加效率,减少可能性。

  1. 首先,在原来的字符串之前做一个快速的“丑陋的正则表达式”匹配吗?代换。如果你得到一个匹配,那么这个字符串显然不能很好。

  2. 接下来寻找单身?机会,那些?那两边都是没有其他的?四个职位。看看这些中的任何一个是否必须固定为V或C,或者它们是否完全取消了该字符串的资格(如OP的例子1中所示)。如果它们必须固定为V或C,请执行此操作并继续。

  3. 后续策略更多参与:双倍?细分涉及左右检查?根据各自的左/右侧翼字符等的V / C要求

答案 7 :(得分:0)

这是C#中的解决方案,似乎可以从我投入的一些测试用例中解决。 [正则表达式的部分内容来自之前的回答者。]

public static bool IsWordNiceable(string word, int maxVowels, int maxConsonants)
{
    if (IsUgly(word, maxVowels, maxConsonants)) return false;

    int i = 0;
    while ((i = word.IndexOf('?', i)) != -1)
    {
        string newWord = word.Substring(0, i) + "a" + word.Substring(i+1);
        bool vowelMakesNice = IsWordNiceable(newWord, maxVowels, maxConsonants);

        newWord = word.Substring(0, i) + "b" + word.Substring(i + 1);
        bool consonantMakesNice = IsWordNiceable(newWord, maxVowels, maxConsonants);

        if (!(vowelMakesNice || consonantMakesNice)) return false;
        i++;
    }

    return true;
}


private static bool IsUgly(string word, int maxVowels, int maxConsonants)
{
    string consonants = "bcdfghjklmnpqrstvwxyz";
    string vowels = "aeiou";
    string uglyRegex = string.Format("([{0}]{{{1},{1}}})|([{2}]{{{3},{3}}})", vowels, maxVowels, consonants, maxConsonants);

    Match match = Regex.Match(word.ToLower(), uglyRegex);
    return match.Success;
}

这首先测试给定的单词是否是丑陋的(包括问号,如果有的话)。然后它循环通过单词,替换第一个“?”同时使用元音和辅音,并使用新单词调用自身。如果元音和辅音替换都不能使它变好,那么该分支返回false(丑陋)。