【问题标题】:Generate 7 million random strings that do not overlap生成 700 万个不重叠的随机字符串
【发布时间】:2020-03-05 15:00:01
【问题描述】:

我尝试生成 700 万个不重叠的随机字符串。(字符串长度必须为 2 到 4)

但是,我的代码用了 28023 毫秒来生成 700 万个不重叠的字符串。

我不知道如何高效地生成 700 万个不重叠的字符串。

我尝试使用 hashmap、list、... 因为我需要一个键值类型

    HashMap<String, Integer> map = new HashMap();
    long start = System.currentTimeMillis();

    for(int i = 0 ; i < 7000000 ; ) {
        int MAX_LENGTH = 4;
        int MIN_LENGTH = 2;

        StringBuffer temp = new StringBuffer();
        Random rnd = new Random();
        int length = rnd.nextInt(MAX_LENGTH - MIN_LENGTH + 1) + MIN_LENGTH; // 문자열 길이 랜덤(2~4자리)

        for (int j = 0; j < length; j++) {
            int rIndex = rnd.nextInt(2);
            switch (rIndex) {
                case 0:
                    // a-z(소문자)
                    temp.append((char) ((int) (rnd.nextInt(26)) + 97));
                    break;
                case 1:
                    // A-Z(대문자)
                    temp.append((char) ((int) (rnd.nextInt(26)) + 65));
                    break;
            }
        }


        String str = temp.toString();

        if(!map.containsKey(str)) {
            map.put(str, rnd.nextInt());
            i++;
        }
    }

    long end = System.currentTimeMillis();

    System.out.println("Setup Performance : " + (end - start));

我的代码用了 28023 毫秒来生成 700 万个不重叠的字符串。

【问题讨论】:

  • 一个建议是将Random rnd = new Random(); 移出循环。不过,这并不能完全解决您的问题。
  • 不到半分钟?有什么问题?
  • 还将StringBuffer 替换为StringBuilder 并将实例化移动到循环前(创建一次)并在每次迭代中使用setLength(0)。显着消除 GC。
  • 您正在使用 52 个字母:A-Za-z。将您的字符串想象为以 52 为基数的 2、3 或 4 位数字。在该范围内选择一个数字并以 52 为基数表示。有很多方法可以从一个范围内生成非重复随机数,例如格式保留加密.

标签: java string algorithm random


【解决方案1】:

因此,您希望从一组 52 个字符(A-Za-z)中生成 700 万个字符串,每个字符串包含 2 到 4 个字符。

一些简单的数学运算告诉我们,有 2,704 个可能的 2 字符字符串、140,608 个 3 字符字符串和 7,311,616 个可能的 4 字符字符串。总共有 7,454,928 个可能的字符串。

所以创建一个包含从 0 到 7,454,927 的所有数字的数组。 Shuffle it,然后从数组中选出前 700 万个。

当然,您必须编写代码将该数字转换为您的输出字符串之一。这很容易。 0 是“AA”,51 是“Az”,52 是“BA”。您基本上是在进行整数到字符串的转换。

这是基本的想法。您必须转换为 Java。

arraySize = 7454928
numbers = new array[arraySize]

// populate array
for i = 0 to arraySize-1
    numbers[i] = i

shuffle(numbers)

for i = 0 to 7000000
    code = convertNumberToString(numbers[i])
    print code


convertNumberToString(n)
    Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    outputString = ""
    while (n > 0 || outputString.length < 2)
      result = n / 52 // length of alphabet
      remainder = n % 52;
      outputString.append(Alphabet[remainder])
      n = result;
    // outputString now contains the characters,
    // but they're reversed. So reverse the string.
    return outputString.reverse()

【讨论】:

  • 你不需要在最后反转字符串。我们正在生成随机字符串,谁在乎字符串的顺序是什么?
【解决方案2】:

要生成 n 个随机字符串,我们至少需要 O(n) 步。要检查是否已经生成了新字符串,您需要一个好的搜索算法。因此,搜索可能需要 O(n^2)、O(nlogn) 或 O(logn) 等...取决于您使用的算法。如何通过为随机生成的字符串添加索引(例如 1,2,3...7,000,000)前缀来完全删除搜索步骤?如果你不喜欢十进制前缀,你可以使用十六进制前缀等... 希望这可以帮助改进它。

添加了 C# 示例程序。

using System;
using System.Collections.Generic;

namespace Test
{
    class Program
    {
        public static List<char> GeneratePrintableCharArray(int numFirstChars = 256)
        //  Go thru numFirstChars first Unicode characters and extract
        //  non-control and non-white space characters into a list.
        //  From the default first 256 unicode chars, we can have 189 characters.
        {
            List<Char> printableChars = new List<char>();
            for (int i = char.MinValue; i < numFirstChars && i <= char.MaxValue; i++)
            {
                char c = Convert.ToChar(i);
                if (!char.IsControl(c) && !char.IsWhiteSpace(c))
                {
                    printableChars.Add(c);
                }
            }
            return printableChars;
        }

        static void Main(string[] args)
        {
            //  If we want to use 2 "digits" to store the index upto 7 million,
            //  we need 2645-base number system

            //  extract the first 2645 Uniocde characters and the null character
            List<char> chars = GeneratePrintableCharArray(2713);
            chars.Insert(0, '\0');

            List<string> idxList = new List<string>();
            List<string> randomList = new List<string>();

            int maxNumStrings = 7000000;
            bool stop = false;

            //  1. Generate "2-digit" index string list and up-to 2 character string list
            for (int i = 0; i < chars.Count && !stop; i++)
            {
                for (int j = 0; j < chars.Count && !stop; j++)
                {
                    string s = "";


                    if (i > 0 && j > 0)
                    {
                        s += new string(chars[i], 1);
                        s += new string(chars[j], 1);

                        idxList.Add(s);
                    }
                    else if (i > 0)
                    {
                        s += new string(chars[i], 1);
                    }
                    else if (j > 0)
                    {
                        s += new string(chars[j], 1);
                    }

                    randomList.Add(s);

                    if (idxList.Count == maxNumStrings)
                    {
                        stop = true;
                    }
                }
            }

            //  2. Append random suffix for the index
            Random rnd = new Random();
            for (int i = 0; i < idxList.Count; i++)
            {
                idxList[i] += randomList[rnd.Next(0, randomList.Count - 1)];
            }
            //  Here, we have 7 mil random strings.

            //  3. Just for testing - to make sure we don't have multiple items with the same string
            HashSet<string> set = new HashSet<string>(); 
            for (int i = 0; i < idxList.Count; i++)
            {
                if (set.Contains(idxList[i]))
                {
                    Console.WriteLine("There is a bug. Duplicate string found: " + idxList[i]);
                }
                else
                {
                    set.Add(idxList[i]);
                }
            }

        }
    }
}

【讨论】:

  • 谢谢。但是,字符串长度必须是 2 到 4。所以,我不能添加索引 :(
猜你喜欢
  • 2014-04-07
  • 1970-01-01
  • 2017-02-14
  • 2010-12-07
  • 2017-04-05
  • 2011-07-23
  • 2017-08-01
相关资源
最近更新 更多