【问题标题】:C# /Linq Yet another Brain TeaserC# /Linq 又一个脑筋急转弯
【发布时间】:2012-05-02 21:17:33
【问题描述】:

朋友们,还有另一种情况需要解决。我正在解决没有应用Linq的问题。但是如果您在Linq中分享您的代码,我希望这是一个学习Linq的好机会。

它被称为火焰

F - 朋友

L - 情人

A - 仰慕者

M - 结婚(丈夫)

E - 敌人

S - 姐姐

问题描述:

将给出两个名字(男性,女性)。我们必须删除两个名字中的共同字母。然后我们必须在从两个名称中删除共同字符后计算剩余字母的数量。最后,我们必须迭代字符串 FLAMES 并删除 FLAMES 中的字母,直到我们到达剩下的单个字符。剩下的单个字符显示了关系。我将在下面的示例中更详细地解释该过程。(忽略大小写和空格)。

例子:

第 1 步

Male    : Albert

Female : Hebarna

字母“a”、“e”、“b”在这两个名称中都很常见。

(从两个字符串中删除这些字母,即使名称“Hebarna”包含两个“a”,您也可以从两个字符串中删除单个“a”,因为名称“Albert”只有一个“a”)。

结果字符串是

Male :     $  l    $     $   r   t

Female:    H  $    $     $   r  n    a

第 2 步:

计算两个字符串中剩余的字母。

计数:7

第 3 步:

使用计数我们必须以下列方式迭代字符串“FLAMES”

F       L           A        M        E           S

1       2           3         4       5           6

7

(Here the count 7 ends at F ,so strike F)

你会得到

$       L         A         M         E         S

(如果它是最后一个字母(“S”),则再次从紧接的下一个字母(它不应该被击中)开始计数,然后如果“F”尚未被击中,则从第一个字母“F”开始。

 $              L         A          M             E             S

 (igonre)        1         2          3              4            5

 (ignore)       6         7

在数数时,不要考虑打出的字母。

$          L         $               M           E         S

                                    1           2          3      

ignore     4       ignore           5           6          7       

"s" 将被击中。

$            L         $           M          E        $

ignore       1         ignore      2           3       

             4         ignore      5           6 

             7

“L”将被击出

$           $          $            M             E           $

                      ignore        1             2          ignore

ignore     ignore     ignore        3             4          ignore

                                    5             6  

                                    7 

最后“M”将被击中。那么剩下的字母是“E” 所以阿尔伯特是赫尔巴纳的敌人。

更新: 字母“r”在这两个名字中也很常见。我忘了打出来。无论如何过程与解释相同。谢谢指出。

【问题讨论】:

  • 这不是成功关系的良好基础。
  • 谢谢。但是,我考虑过逻辑。 :)
  • 'r' 在这两个名字中也很常见
  • 糟糕,我错过了那个。感谢您指出。我赞成您的评论。

标签: c# linq


【解决方案1】:

第一步和第二步

var firstLookup = firstName.ToLookup(c => c.ToLower());
var secondLookup = secondName.ToLookup(c => c.ToLower());
var allChars = firstLookup.Keys.Union(secondLookup.Keys);
int count =
(
  from c in allChars
  let firstCount = firstLookup[c].Count()
  let secondCount = secondLookup[c].Count()
  select
    firstCount < secondCount ? secondCount - firstCount :
    firstCount - secondCount
).Sum()

Step3(未测试)

List<char> word = "FLAMES".ToList();

while (word.Count > 1)
{
  int wordCount = word.Count;
  int remove = (count-1) % wordCount;
  word =
    word.Select( (c, i) => new {c, i =
      i == remove ? 0 :
      i < remove ? i + wordCount + 1 : 
      i})
    .OrderBy(x => x.i)
    .Select(x => x.c)
    .Skip(1)
    .ToList();
}

char result = word.Single();

【讨论】:

  • 谢谢大卫,我怀疑第三步是关键部分,不是吗?
【解决方案2】:
var count = male.Length + female.Length - male.Intersect( female ).Count();

while (flames.Length > 1)
{
     flames = string.Join( '', flames.Where( (c,i) => i != (count % flames.Length) -1 ).ToArray() );
}

【讨论】:

  • 这既不会编译,也不会在尝试使用 count=1 时给我字母“E”,如示例所示。
  • 我没有尝试编译它,因为我目前只有我的 Macintosh。我怀疑差异可能是示例中从零开始的索引与从一开始的索引,尽管我认为我已经解释了这一点。等我到办公室看看。
【解决方案3】:

可以预先计算最后一个遍历火焰字母并逐个删除的计算部分。

public static Char GetChar(int diff) {
    var idx = (diff - 1) % 60;
    return "efefmeaelmaafmfaflefefeemsasamfmfallslslesmsasmmaelmlaslslfs"[idx];
}

有些事情可以在没有 linq 的情况下完成...除非我完全搞砸了。

【讨论】:

  • 你是怎么找出那个字符串的?我看不到图案
  • @CasperT - 我也花了一些时间。没有模式,它是预先计算好的——他/她运行了 60 个可能的值,这些就是结果。我寻找了一种模式,但无法简化循环。
  • 是的,这就是 60 个可能的值,它们会一遍又一遍地重复。如果您喜欢蛮力解决方案,您可能只需对前一千个结果进行预计算,并希望没有人找到两个每个 500 个字符的名称... ;)
  • 但是一个简单的循环不是比一些魔术字符串更好吗?你只需要运行一次循环然后保存模式。
  • 我运行了一次循环,这就是输出。在代码中运行一次循环意味着您需要在可以在编译之前或编译时确定的东西上消耗 cpu 资源。此外,它需要由程序的每个实例计算,总共消耗的 cpu 时间比我在本地运行循环所花费的时间要多。
猜你喜欢
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 2017-05-30
  • 2014-08-03
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
相关资源
最近更新 更多