遇到一个随机数面试题,目测无最优解

小湿哥 2021-05-25 03:15:17
偶然看到群里别人发的一条面试题


生成随机数 (由0~9的阿拉伯数字组成的,长度是6~15个字符)
要求
1. 不能出现连续3个以上相同的数字(11234,2333456 是不允许的)
2. 不能出现3个连号的情况( 123456, 123457, 2567891)
3. 生成的字符串不能是等差数列
4. 要求算法高效,少占内存。


我是没什么好办法。大概三步走

第一步
生成随机数
一次生成64位的数,再做随机长度分割。

第二步
每个字符串从头到尾遍历,检查是否有三个连续数字一致,同时也检查是否有连续3个连号。
若有则该数失败。

第三步
依次遍历,判断等差数列

抛转引玉,有没有更高效的办法来解这个题?!
...全文
2450 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
我感觉这条:
2. 不能出现3个连号的情况( 123456, 123457, 2567891)
是楼主理解错了
图片中题目说的是不允许3连号(123456、123457、123458)
楼主似乎理解成了同一个号内部不允许3连数字
赵4老师 2021-05-25
  • 打赏
  • 举报
回复
随机必然有重复,所谓“不重复的随机”实际上是洗牌。洗牌算法参考下面:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}
小湿哥 2021-05-25
  • 打赏
  • 举报
回复
引用 3 楼 赵4老师 的回复:
仅供参考:
//要求1:从给出来的不同的六组数字中,从每组任意挑选一个数字,最后组成一个六个数字的数组。
//将所有的数组全部列出来。
//同时,排除全部为偶数、全部为奇数的数组。
//排除四个数字递增连续(比如8、9、10、11)的数组。
//如下:
//第一个数字从这12个数字中挑选:,1,3,2,4,5,6,7,8,9,10,11,12
//第二个数字从这17个数字中挑选:,8,7,5,9,6,4,11,10,12,13,3,14,17,2,16,15,18
//第三个数字从这21个数字中挑选:,13,10,15,16,18,11,14,12,7,19,21,17,8,22,9,20,6,23,5,24,25
//第四个数字从这20个数字中挑选:,22,23,18,20,16,17,15,21,14,26,19,24,27,25,12,13,11,10,28,29
//第五个数字从这19个数字中挑选:,26,25,27,29,30,28,23,24,20,22,19,31,21,17,18,32,13,15,16
//第六个数字从这14个数字中挑选:,32,33,30,31,29,28,27,26,25,24,23,22,18,21
//要求2:
//请输入第1个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第2个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第3个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第4个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第5个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第6个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//然后回车,输出结果到cp.txt
//要求3:
//保证同一组数据的数都不相同。
//比如,第一个数为6时,第二个数或其他的数都不能再为6;第二个数为10时,第三个数或其他的数都不能再为10,以此类推……
//要求4:
//增加一个条件:在产生的每个数组A1A2A3A4A5A6中,要求A1<A2<A3<A4<A5<A6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int v[6];
int n[6]={12,17,21,20,19,14};
int d[6][30]={
      {1,3,2,4,5,6,7,8,9,10,11,12},
      {8,7,5,9,6,4,11,10,12,13,3,14,17,2,16,15,18},
      {13,10,15,16,18,11,14,12,7,19,21,17,8,22,9,20,6,23,5,24,25},
      {22,23,18,20,16,17,15,21,14,26,19,24,27,25,12,13,11,10,28,29},
      {26,25,27,29,30,28,23,24,20,22,19,31,21,17,18,32,13,15,16},
      {32,33,30,31,29,28,27,26,25,24,23,22,18,21},
};
int i,j,i0,i1,i2,i3,i4,i5,s;
char ln[100],*t;
FILE *f;
int main() {
    for (i=0;i<6;i++) {
        printf("请输入第%d个数字的选择范围:",i+1);
        fgets(ln,100,stdin);
        j=0;
        t=strtok(ln," ");
        while (1) {
            if (NULL==t) break;
            if (0==t[0]) continue;//跳过多个空格间隔时取出的空串
            d[i][j]=atoi(t);
            j++;
            if (j>=30) break;
            t=strtok(NULL," ");
        }
        n[i]=j;
    }
    f=fopen("cp.txt","w");
    if (NULL==f) {
        printf("无法生成cp.txt!\n");
        return 1;
    }
    printf("正在生成cp.txt...");
    for (i0=0;i0<n[0];i0++) {
    for (i1=0;i1<n[1];i1++) {
    for (i2=0;i2<n[2];i2++) {
    for (i3=0;i3<n[3];i3++) {
    for (i4=0;i4<n[4];i4++) {
    for (i5=0;i5<n[5];i5++) {
        v[0]=d[0][i0];
        v[1]=d[1][i1];
        v[2]=d[2][i2];
        v[3]=d[3][i3];
        v[4]=d[4][i4];
        v[5]=d[5][i5];
        if (0==(v[0]%2)
         && 0==(v[1]%2)
         && 0==(v[2]%2)
         && 0==(v[3]%2)
         && 0==(v[4]%2)
         && 0==(v[5]%2)) continue;//排除全部为偶数
        if (1==(v[0]%2)
         && 1==(v[1]%2)
         && 1==(v[2]%2)
         && 1==(v[3]%2)
         && 1==(v[4]%2)
         && 1==(v[5]%2)) continue;//排除全部为奇数
        for (i=0;i<5;i++) {
            for (j=i+1;j<6;j++) {
                if (v[i]==v[j]) goto NEXT;//保证同一组数据的数都不相同
            }
        }
    NEXT:
        if (i>=5) {
            for (i=0;i<5;i++) for (j=i+1;j<6;j++) if (v[i]>v[j]) {s=v[i];v[i]=v[j];v[j]=s;}//从小到大排序
            if ((v[0]+1==v[1]
              && v[1]+1==v[2]
              && v[2]+1==v[3])
             || (v[1]+1==v[2]
              && v[2]+1==v[3]
              && v[3]+1==v[4])
             || (v[2]+1==v[3]
              && v[3]+1==v[4]
              && v[4]+1==v[5])) continue;//排除四个数字递增连续
            fprintf(f,"%2d,%2d,%2d,%2d,%2d,%2d\n",v[0],v[1],v[2],v[3],v[4],v[5]);
        }
    }}}}}}
    fclose(f);
    printf("\n生成cp.txt完毕\n");
    return 0;
}
//如果文件in.txt的内容为
//1 3 2 4 5 6 7 8 9 10 11 12
//8 7 5 9 6 4 11 10 12 13 3 14 17 2 16 15 18
//13 10 15 16 18 11 14 12 7 19 21 17 8 22 9 20 6 23 5 24 25
//22 23 18 20 16 17 15 21 14 26 19 24 27 25 12 13 11 10 28 29
//26 25 27 29 30 28 23 24 20 22 19 31 21 17 18 32 13 15 16
//32 33 30 31 29 28 27 26 25 24 23 22 18 21
//可以在cmd窗口里面输入命令
//cp <in.txt
//得到要求1对应的结果
//BTW:中了一定要分我六成啊!嘿嘿!(^=^)
赵老师一如既往地犀利, 数十年如一日, 想当初10年前我刚进CSDN的时候,赵老师就犹如指路明灯,照耀着我一路从菜鸟变成了老鸟。
小湿哥 2021-05-25
  • 打赏
  • 举报
回复
引用 6 楼 早打大打打核战争 的回复:
还要保证生成50万个不同的随机数
确实 50万个,得用hash 或者 树 或者 跳表 的数据结构来保存 已有的随机数, 每次生成了一堆随机数,还得先做查重。
小湿哥 2021-05-25
  • 打赏
  • 举报
回复
引用 4 楼 NorZ 的回复:
等差数列只是一种例举的规律...是不是还有其他的规律?
问题简化,就只考虑等差吧。
  • 打赏
  • 举报
回复
还要保证生成50万个不同的随机数
NorZ 2021-05-25
  • 打赏
  • 举报
回复
等差数列只是一种例举的规律...是不是还有其他的规律?
赵4老师 2021-05-25
  • 打赏
  • 举报
回复
仅供参考:
//要求1:从给出来的不同的六组数字中,从每组任意挑选一个数字,最后组成一个六个数字的数组。
//将所有的数组全部列出来。
//同时,排除全部为偶数、全部为奇数的数组。
//排除四个数字递增连续(比如8、9、10、11)的数组。
//如下:
//第一个数字从这12个数字中挑选:,1,3,2,4,5,6,7,8,9,10,11,12
//第二个数字从这17个数字中挑选:,8,7,5,9,6,4,11,10,12,13,3,14,17,2,16,15,18
//第三个数字从这21个数字中挑选:,13,10,15,16,18,11,14,12,7,19,21,17,8,22,9,20,6,23,5,24,25
//第四个数字从这20个数字中挑选:,22,23,18,20,16,17,15,21,14,26,19,24,27,25,12,13,11,10,28,29
//第五个数字从这19个数字中挑选:,26,25,27,29,30,28,23,24,20,22,19,31,21,17,18,32,13,15,16
//第六个数字从这14个数字中挑选:,32,33,30,31,29,28,27,26,25,24,23,22,18,21
//要求2:
//请输入第1个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第2个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第3个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第4个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第5个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//请输入第6个数字的选择范围:(可以手动输入任意几个空格间隔的数字,最多30个)
//然后回车,输出结果到cp.txt
//要求3:
//保证同一组数据的数都不相同。
//比如,第一个数为6时,第二个数或其他的数都不能再为6;第二个数为10时,第三个数或其他的数都不能再为10,以此类推……
//要求4:
//增加一个条件:在产生的每个数组A1A2A3A4A5A6中,要求A1<A2<A3<A4<A5<A6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int v[6];
int n[6]={12,17,21,20,19,14};
int d[6][30]={
      {1,3,2,4,5,6,7,8,9,10,11,12},
      {8,7,5,9,6,4,11,10,12,13,3,14,17,2,16,15,18},
      {13,10,15,16,18,11,14,12,7,19,21,17,8,22,9,20,6,23,5,24,25},
      {22,23,18,20,16,17,15,21,14,26,19,24,27,25,12,13,11,10,28,29},
      {26,25,27,29,30,28,23,24,20,22,19,31,21,17,18,32,13,15,16},
      {32,33,30,31,29,28,27,26,25,24,23,22,18,21},
};
int i,j,i0,i1,i2,i3,i4,i5,s;
char ln[100],*t;
FILE *f;
int main() {
    for (i=0;i<6;i++) {
        printf("请输入第%d个数字的选择范围:",i+1);
        fgets(ln,100,stdin);
        j=0;
        t=strtok(ln," ");
        while (1) {
            if (NULL==t) break;
            if (0==t[0]) continue;//跳过多个空格间隔时取出的空串
            d[i][j]=atoi(t);
            j++;
            if (j>=30) break;
            t=strtok(NULL," ");
        }
        n[i]=j;
    }
    f=fopen("cp.txt","w");
    if (NULL==f) {
        printf("无法生成cp.txt!\n");
        return 1;
    }
    printf("正在生成cp.txt...");
    for (i0=0;i0<n[0];i0++) {
    for (i1=0;i1<n[1];i1++) {
    for (i2=0;i2<n[2];i2++) {
    for (i3=0;i3<n[3];i3++) {
    for (i4=0;i4<n[4];i4++) {
    for (i5=0;i5<n[5];i5++) {
        v[0]=d[0][i0];
        v[1]=d[1][i1];
        v[2]=d[2][i2];
        v[3]=d[3][i3];
        v[4]=d[4][i4];
        v[5]=d[5][i5];
        if (0==(v[0]%2)
         && 0==(v[1]%2)
         && 0==(v[2]%2)
         && 0==(v[3]%2)
         && 0==(v[4]%2)
         && 0==(v[5]%2)) continue;//排除全部为偶数
        if (1==(v[0]%2)
         && 1==(v[1]%2)
         && 1==(v[2]%2)
         && 1==(v[3]%2)
         && 1==(v[4]%2)
         && 1==(v[5]%2)) continue;//排除全部为奇数
        for (i=0;i<5;i++) {
            for (j=i+1;j<6;j++) {
                if (v[i]==v[j]) goto NEXT;//保证同一组数据的数都不相同
            }
        }
    NEXT:
        if (i>=5) {
            for (i=0;i<5;i++) for (j=i+1;j<6;j++) if (v[i]>v[j]) {s=v[i];v[i]=v[j];v[j]=s;}//从小到大排序
            if ((v[0]+1==v[1]
              && v[1]+1==v[2]
              && v[2]+1==v[3])
             || (v[1]+1==v[2]
              && v[2]+1==v[3]
              && v[3]+1==v[4])
             || (v[2]+1==v[3]
              && v[3]+1==v[4]
              && v[4]+1==v[5])) continue;//排除四个数字递增连续
            fprintf(f,"%2d,%2d,%2d,%2d,%2d,%2d\n",v[0],v[1],v[2],v[3],v[4],v[5]);
        }
    }}}}}}
    fclose(f);
    printf("\n生成cp.txt完毕\n");
    return 0;
}
//如果文件in.txt的内容为
//1 3 2 4 5 6 7 8 9 10 11 12
//8 7 5 9 6 4 11 10 12 13 3 14 17 2 16 15 18
//13 10 15 16 18 11 14 12 7 19 21 17 8 22 9 20 6 23 5 24 25
//22 23 18 20 16 17 15 21 14 26 19 24 27 25 12 13 11 10 28 29
//26 25 27 29 30 28 23 24 20 22 19 31 21 17 18 32 13 15 16
//32 33 30 31 29 28 27 26 25 24 23 22 18 21
//可以在cmd窗口里面输入命令
//cp <in.txt
//得到要求1对应的结果
//BTW:中了一定要分我六成啊!嘿嘿!(^=^)
lin5161678 2021-05-25
  • 打赏
  • 举报
回复
分段随机就可以了 先随机6-15 作为位数 然后每次随机1位数作为组成部分 每次随机检查会不会重复前面的数字 会不会和前面的数字连号 就可以了
lin5161678 2021-05-25
  • 打赏
  • 举报
回复
第二步 每个字符串从头到尾遍历,检查是否有三个连续数字一致,同时也检查是否有连续3个连号。 若有则该数失败。 别失败呀 签名那么多步骤 别浪费了 你交换一下不就不会失败了么 比如 111234 交换一下变成 121314 不就完事了

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧