【问题标题】:Random string in a given interval给定区间内的随机字符串
【发布时间】:2019-10-06 03:05:19
【问题描述】:

我想用这个签名创建一个函数

char *generateString(char *par1, char *par2);

结果应该是严格大于par1(与strcmp 相比)且严格小于par2 的字符串。 Par1 和 par2 的长度在 0 和 MAX 之间。

每个字符都在[INF,SUP] 间隔之间选择。 (参数是由这些字符组成的字符串)。

字符串长度是有限的,但在 0 到某个 MAX 值之间也是随机的。

似乎很难编码,有人可以帮忙吗?

【问题讨论】:

  • 当par1和par2是同一个字符串时会发生什么?
  • 可以返回空字符串
  • 如果参数无效则为空字符串?
  • 可以,可以为空
  • 我找到了解决方案,很快就会发布。我正在测试。正如你所说,看起来而且实际上非常困难!

标签: c string random


【解决方案1】:

问题要求在一个排他范围内的随机字符串。下面的解决方案给出了一个包含范围内的随机字符串。结果证明,求解一个包含范围要容易得多。如果我们想要一个独占范围,我们只需在生成的字符串落在范围的边界上时拒绝它,并生成另一个随机字符串,直到不在范围的边界上。我为此添加了函数randstrx()

为了说明我的解决方案,我们考虑十进制数字字符串,即其字符在C = [0 9] 范围内。例如任意长度的0012766501231等。考虑给定长度的所有字符串,例如4。显然,这些字符串上存在顺序。例如,对于我们的十进制数字字符串,长度为4 的字符串按如下顺序排列:000000010002、...、9999

给定任何给定长度的字符串,很容易计算在字符串顺序中紧随其后或紧随其前的相同长度的字符串(我们忽略没有紧随其后或紧随其后的两种边界情况,因为我们将不需要它们)。对于我们的十进制数字字符串,我们只需添加或减去1。加法和减法在任何基数中都有很好的定义,数字可以由任何符号组成,它们不必是十进制数字。因此,这定义了如何将1(或一个单位)添加或减去给定长度的任何字符串。我们将在下面使用它。

S1S2 分别是字符串范围的下限和上限。我们有S1 <= S2;订单由strcmp() 定义。 L1S1 的长度,L2S2 的长度。我们想在[S1 S2] 范围内生成一个随机字符串SS 可以是任意长度L <= M,其中M 是给定的常数。所有字符串都包含C = [C1 C2]范围内的字符。

[步骤 1] 第一步包括为S 生成随机长度L。根据S1S2 的值,并非所有长度都是可能的。事实上,S1S2 可以以相同的字符序列开头,例如[123555 1237]S1S2 都以123 开头。假设长度为K >= 0SkS1S2 开头的相等字符序列。设S1 = Sk + T1S2 = Sk + T2 其中T1T2 分别是S1S2Sk 之后的字符序列,+ 是字符串连接运算符。令N1 >= 0N2 >= 0 分别为T1T2 的长度。我们考虑 4 种情况:

  • N1 = 0N2 = 0 在这种情况下,S1 = S2 = Sk,因此范围 [S1 S2] 包含长度为 K 的单个字符串 Sk。因此,L = KL 唯一可能的值。
  • N1 > 0N2 = 0 这种情况是不可能的,因为我们假设 S1 <= S2
  • N1 = 0N2 > 0 显然,L 必须至少是K 的公共字符序列的长度S1S2。要确定L 的上限,我们需要考虑T2。如果T2 可以递减,这意味着我们可以生成小于S2 的任意长度的字符串。例如,如果S1 = 123S2 = 123001,则12300099...9 小于S2(和> S1)。唯一不能减少T2 的情况是T2 = C1 + C1 + ... + C1。例如,如果S1 = 123S2 = 123000,则T2 不能递减。不可能生成小于S2 且长度大于L2 的字符串。所以在这种情况下,L 必须在[K L2] 范围内。
  • N1 > 0N2 > 0 考虑L 的上限。我们知道T1 < T2T1T2 的第一个字符不相等,如果它们相等,那么共同的第一个字符将在共同的起始序列Sk 中。这意味着T1 可以递增或T2 可以递减。事实上,例如,在我们的十进制数字字符串中,唯一不能递增的T199...9。如果T1 等于该值,则这也必须是T2 的值,但T1 将等于T2,并且T1T2 必须在@987654427 中@,矛盾。可以对T2 进行类似的推理。唯一不能递减的T2T2 = 00...0,因此T1 也必须是00...0,这会将T1T2 放入Sk,这是一个矛盾。因为T1 可以递增,T2 可以递减,所以我们可以生成大于T1 和小于T2 的随机字符串或任意长度。例如,如果S1 = 1231S2 = 1234,则字符串12311...1123399...9 落在[S1 S2] 范围内。考虑L 的下限。任何长度为K 的字符串都必须等于Sk,但由于N1 > 0Sk 小于S1。所以随机字符串的长度不能是K。然而,很容易证明它的长度可以是K + 1。我们知道T1的第一个字符T1[0]小于T2的第一个字符,并且可以递增。因此,字符串Sk 附加字符T1[0] + 1 是长度为K + 1 的字符串,即大于S1。它也小于或等于S2。事实上,如果T2[0] = T1[0] + 1N2 = 1,那么随机字符串等于S2。向S2 添加更多字符只会使S2 大于随机字符串。因此,L 必须大于或等于 K + 1

总而言之,我们有:

  • 对于N1 = 0N2 = 0L = K
  • 对于N1 > 0N2 > 0L > K
  • 对于N1 = 0N2 > 0,如果T2 = 00...0,则L = [K L2],否则L >= K

鉴于上述情况,我们为S 生成一个随机值L

[步骤 2] 我们计算长度为L 的最小字符串S1L 大于或等于S1。如果L >= L1,则S1LS1 附加了足够的C1 字符以使其长度等于L。例如,如果S123906 并且L8S1L = 23906000。另一方面,如果L < L1,我们将S1截断为长度L并添加1,如上所述。例如,如果S123906L3S1L = 240

[步骤 3] 我们计算长度为L 的最大字符串S2L,它小于或等于S2。如果L > L2,则S2LS2 减去1(如上所述)附加足够的C2 字符以使其长度等于L。例如,如果S223906 并且L8S2L = 23905999。另一方面,如果L < L2,我们将S2截断为长度L。例如,如果S223906L3S2L = 239

[步骤 4] 现在我们已经有了长度为 L 的最小和最大字符串,它们都在 [S1 S2] 范围内,很容易生成长度为 @987654527 的随机字符串@在同一范围内。对于从0L – 1 的每个i,我们只需将S[i] 设置为[S1L[i] S2L[i]] 范围内的随机字符值。

这是实现该解决方案的 C 代码。

#include "stdlib.h"
#include "string.h"
#include "assert.h"
#include "time.h"

/* Generate a random string in inclusive range [S1 S2] of maximum length M. */
/* S1, S2, and the returned random string have their characters in the range [C1 C2]. */
/* Returns NULL if no string of maximum length M exists in [S1 S2]. */
char * randstr(char * S1, char * S2, int M, int C1, int C2)
{
    /* Validate inputs. */
    if (S1 == NULL || S2 == NULL || *S1 == 0 || *S2 == 0) return NULL;
    if (strcmp(S1, S2) > 0) return NULL;
    if (C1 > C2) return NULL;

    /* Lengths of input strings. */
    int L1 = strlen(S1);
    int L2 = strlen(S2);

    /* Length of longest common starting sequence of S1 and S2. */
    int K = 0;
    for (; K < L1 && K < L2 && S1[K] == S2[K]; K++);

    /* Generate length of random string S. */
    int L;

    int N1 = L1 - K;
    int N2 = L2 - K;

    if (N1 == 0 && N2 == 0)
    {
        /* L = K */
        if (M < K) return NULL;
        L = K;
    }
    else if (N1 > 0 && N2 > 0)
    {
        /* L = [K + 1 M] */
        if (M < K + 1) return NULL;
        L = (rand() % (M - (K + 1) + 1)) + K + 1;
    }
    else if (N1 == 0 && N2 > 0)
    {
        char * T2 = S2 + K;
        while (*T2 > 0 && *T2 == C1)
            T2++;

        if (*T2 == 0) /* T2 = C1 + C1 + ... + C1 */
        {
            /* L = [K L2] */
            if (M < K) return NULL;
            if (M < L2)
                L = (rand() % (M - K + 1)) + K;
            else
                L = (rand() % (L2 - K + 1)) + K;
        }
        else
        {
            /* L >= K */
            if (M < K) return NULL;
            L = (rand() % (M - K + 1)) + K;
        }
    }

    /* Compute smallest string S1L of length L that is greater than S1. */
    char * S1L = (char*)malloc(sizeof(char) * (L + 1));
    S1L[L] = 0;
    if (L >= L1)
    {
        for (int i = 0; i < L1; S1L[i] = S1[i++]);   /* Copy S1 into S1L. */
        for (int i = L1; i < L; S1L[i++] = C1);      /* Append C1 characters. */
    }
    else /* L < L1 */
    {
        for (int i = 0; i < L; S1L[i] = S1[i++]);    /* Set S1L to S1 truncated to length L. */
        for (int i = L - 1; i >= 0; i--)             /* Increment S1L. */
        {
            if (S1L[i] < C2)
            {
                S1L[i]++;
                break;
            }
            else
                S1L[i] = C1;
        }
    }

    /* Compute largest string S2L of length L that is less than S2. */
    char * S2L = (char*)malloc(sizeof(char) * (L + 1));
    S2L[L] = 0;
    if (L > L2)
    {
        for (int i = 0; i < L2; S2L[i] = S2[i++]);    /* Copy S2 into S2L. */
        for (int i = L2; i < L; S2L[i++] = C2);       /* Append C2 characters. */
        for (int i = L2 - 1; i >= 0; i--)             /* Decrement copy of S2. */
        {
            if (S2L[i] > C1)
            {
                S2L[i]--;
                break;
            }
            else
                S2L[i] = C2;
        }
    }
    else /* L < L2 */
    {
        for (int i = 0; i < L; S2L[i] = S2[i++]);     /* Set S2L to S2 truncated to length L. */
    }

    /* Generate random string S of length L in range [S1L S2L]. */
    char * S = (char*)malloc(sizeof(char) * (L + 1));
    S[L] = 0;
    for(int i = 0; i < L; i++)
        S[i] = (rand() % (S2L[i] - S1L[i] + 1)) + S1L[i];

    free(S1L);
    free(S2L);

    return S;
}

/* Generate a random string in exclusive range (S1 S2) of maximum length M. */
/* S1, S2, and the returned random string have their characters in the range [C1 C2]. */
/* Returns NULL if no string of maximum length M exists in (S1 S2). */
char * randstrx(char * S1, char * S2, int M, int C1, int C2)
{
    /* If S1 + 1 >= S2, then no random string exists in (S1 S2). */
    int L1 = strlen(S1);
    char * S = (char*)malloc(sizeof(char) * (L1 + 1));
    strcpy(S, S1);
    for (int i = L1 - 1; i >= 0; i--)
    {
        if (S[i] < C2)
        {
            S[i] += 1;
            break;
        }
    }

    if (strcmp(S, S2) >= 0)
    {
        free(S);
        return NULL;
    }

    do
    {
        free(S);
        S = randstr(S1, S2, M, C1, C2);
    }
    while (strcmp(S, S1) == 0 || strcmp(S, S2) == 0);

    return S;
}

int main()
{
    srand((unsigned int)time(NULL)); // initialisation de rand

    char * s;

    /* N1 == 0, N2 == 0, K == 1 */
    s = randstr("0", "0", 10, '0', '9');
    assert(strcmp(s, "0") == 0);

    /* N1 == 0, N2 == 0, K == 4 */
    s = randstr("1210", "1210", 10, '0', '9');
    assert(strcmp(s, "1210") == 0);

    /* N1 == 0, N2 == 1, K == 3, T2 == 0 */
    s = randstr("121", "1210", 3, '0', '9');
    assert(strcmp(s, "121") == 0);

    /* N1 == 0, N2 == 1, K == 3, T2 == 0 */
    s = randstr("121", "1210", 4, '0', '9');
    assert(strcmp(s, "121") == 0 || strcmp(s, "1210") == 0);

    /* N1 == 1, N2 == 1, K == 3, T2 != 0 */
    s = randstr("1210", "1211", 4, '0', '9');
    assert(strcmp(s, "1210") == 0 || strcmp(s, "1211") == 0);

    /* N1 == 1, N2 == 1, K == 3, T2 != 0 */
    s = randstr("1210", "1211", 5, '0', '9');
    assert(strcmp(s, "1210") >= 0 || strcmp(s, "1211") <= 0);

    /* N1 == 4, N2 == 1, K == 0, T2 != 0 */
    s = randstr("0004", "1", 25, '0', '9');
    assert(strcmp(s, "0004") >= 0 || strcmp(s, "1") <= 0);

    return 0;
}

【讨论】:

  • 你确实意识到这不是一个赏金问题,对吧?这是很多内容。
猜你喜欢
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 1970-01-01
  • 2010-09-26
相关资源
最近更新 更多