来自字符串的不同数字算法

时间:2013-02-21 17:08:37

标签: c# algorithm

我正在制作一个简单的游戏,我需要一个单词或短语,例如“hello world”并将其转换为一系列数字。

标准是:

  1. 数字需要与众不同
  2. 需要配置最大数字序列的能力。 IE 10总数。
  3. 需要能够按顺序为每个数字配置最大范围。
  4. 必须是确定性的,即我们应该每次为同一个输入短语获得相同的序列。
  5. 我试过这样解决问题:

    1. 将字符转换为ASCII数字代码:“hello world”= 104 101 108 108 111 32 119 111 114 108 100
    2. 删除所有其他号码,直到我们满足总数(在这种情况下为10)
    3. 如果数字的Foreach号码&gt; max number然后除以2,直到数字<= max number
    4. 如果任何数字重复增加或减少第一次出现直到满意为止。 (这可能会导致问题,因为您可以通过解决另一个副本来创建副本)
    5. 有没有更好的方法可以做到这一点,还是我走在正确的轨道上?如上所述,我想我可能会遇到消除区别的问题。

4 个答案:

答案 0 :(得分:1)

如果您想限制输出系列的大小 - 那么这是不可能的

<强>证明:
假设您的输出是一系列大小k,对于某些预定义的r <= M,每个范围M,然后最多k*M个可能的输出。

但是,有无数个输入,特别是有k*M+1个不同的输入。

pigeonhole principle(输入是鸽子,输出是鸽笼) - 在一个鸽笼(输出)中有2只鸽子(输入) - 因此无法达到要求。


原始回答,提供了解决方法,但不限制输出系列的大小:

您可以使用素数,让p1,p2,...成为素数系列。
然后,使用number[i] = ascii(char[i]) * p_i将字符串转换为一系列数字
每个角色的范围显然是[0,255 * p_i]

因为每个i,ji != j - &gt; p_i * x != p_j * y(对于每个x,y) - 您将获得唯一性。然而,这在理论上主要是好的,因为生成的数字可能会快速增长,并且对于实际实现,您将需要一些大数字库,例如java的BigInteger(不能回想起C#等价物)

另一种可能的解决方案(没有系列限制的相同放宽)是:

number[i] = ascii(char[i]) + 256*(i-1)

此处number[i]的范围为[256*(i-1),256*i),元素仍然不同。

答案 1 :(得分:1)

从数学上讲,理论上可以做你想做的事,但是你无法用C#做到这一点:

如果要求输出不同,则在使用ASCII值对字符串进行编码后,您不会丢失任何信息。这意味着如果您将输出大小限制为 n 数字,则数字必须包含编码中的所有信息。

所以对你的例子

“Hello World” - &gt; 104 101 108 108 111 32 119 111 114 108 100

你必须保留每个数字的含义。最简单的方法是将数字填充为三位数并将它们连接成一个大数字...使得结果104101108111032119111114108100最大数字= 1。 (你可以看到问题出在哪里,对于任意长度的输入你需要非常大的数字。)所以当然可以将任意长度的字符串输入编码为 n 数字,但数字会变得非常大。

如果你用“数字”表示数字,那么你就不能有不同的输出,正如@amit在他的例子中用pidgeonhole原理解释的那样。

答案 2 :(得分:0)

让我们尽可能轻松地消除您的标准。 对于不同的,确定性的,只需使用哈希码。 (哈希实际上不保证是独特的,但很可能是):

string s = "hello world";
uint hash = Convert.ToUInt32(s.GetHashCode());

请注意,我将从GetHashCode返回的signed int转换为unsigned,以避免出现' - '的可能性。

然后,对于每个号码的最大范围,只需convert the base

这将为您留下最大的序列标准。如果不能更好地理解您的要求,我可以提出的建议是在必要时进行截断:

hash.toString().Substring(0, size)

截断会留下你不再明显的机会,但必须按照你的要求建造?正如amit在另一个答案中解释的那样,你不能拥有无限输入和非无限输出。

答案 3 :(得分:0)

好的,所以在一条评论中你说过这只是为了选择彩票号码。在这种情况下,你可以这样做:

public static List<int> GenNumbers(String input, int count, int maxNum)
{
    List<int> ret = new List<int>();
    Random r = new Random(input.GetHashCode());
    for (int i = 0; i < count; ++i)
    {
        int next = r.Next(maxNum - i);
        foreach (int picked in ret.OrderBy(x => x))
        {
            if (picked <= next)
                ++next;
            else
                break;
        }
        ret.Add(next);
    }
    return ret;
}

这个想法是使用String的哈希码为随机数生成器播种。其余的只是选择数字而无需替换。我确信它可以更有效地编写 - 另一种方法是生成所有maxNum个数字并随机播放第一个count。警告,未经测试。

我知道.Net运行时的较新版本使用随机字符串哈希码算法(因此运行之间的结果会有所不同),但我相信这是选择加入的。编写自己的哈希算法是一种选择。