求们帮忙解决下运算效率问题

.Net技术 码拜 8年前 (2016-05-09) 768次浏览
问题说明:有这样形式的字符串”129384/283901/123903  293120/293092/391032  232218/312398/962519………631782/239715/123987″ . 其中129384/283901/123903为1组,中间用空格隔开.一共是2万组这样的数据.每组数据分3段,用”/”隔开.现在要做的是把每组数据的每段提出1个数字,组成1个3位数,不管重复.只要组合全就行.怎么做效率才最高呢? 小弟本人写了代码,可是效率太低了.
这有部分代码 请高手帮忙!
ArrayList ay_shuju = new ArrayList();
string[] str_shuju;
string[] str_zu;
string str,str_jieguo;
string mystr = “129384/283901/123903  293120/293092/391032  232218/312398/962519………631782/239715/123987″; // 2万组 用空格隔开
str_shuju = mystr.Split(” “);
for (int j = 0; j < str_shuju.Length; j++)
{
str_zu = str_shuju[j].Split(“/”);
for (int ii = 0; ii < str_zu[0].Length; ii++)
{
for (int jj = 0; jj < str_zu[1].Length; jj++)
{
for (int kk = 0; kk < str_zu[2].Length; kk++)
{
str_jieguo = str_zu[0].Substring(ii, 1) + str_zu[1].Substring(jj, 1) + str_zu[2].Substring(kk, 1);
str = str + ” ” + str_jieguo;
if (!ay_shuju.Contains(str_jieguo))
{
ay_shuju.Add(str_jieguo);
}
}
}
}
}
解决方案

35

每一个区段都是长度固定的数字吗?都是6位数字/6位数字/6位数字这种格式吗?

129384/283901/123903

10

理论上只需要一次遍历,效率为o(n/3)  n为字符串总长度。

引用:

假如都满足,那么下面的代码应该是效率最高的

string txt = @"129384/283901/123903 293120/293092/391032 232218/312398/962519";
int spilitLength = 1;
List<string> list = new List<string>();
for (var i = 0; i < txt.Length; i += 20 + spilitLength)
{
    char[] tmp = new char[3];
    tmp[0] = txt[i];
    tmp[1] = txt[i + 7];
    tmp[2] = txt[i + 14];
    list.Add(new string(tmp));
}
list.ForEach(l => Console.WriteLine(l));
for (var i = 0; i < txt.Length; i += 20 + spilitLength)
{
    list.Add(String.Format("{0}[1}{2}",txt[i],txt[i+7],txt[i+14]));
}

这个性能差点,但是精简代码,只需要1行求们帮忙解决下运算效率问题

20

引用:

您看下本人贴出的代码,就明白本人说的了.每组用了3个循环来组合出3位数.就是效率太低了.

从算法上,你的做法(3个嵌套循环作组合)并没有问题。
但具体实现上,有几个瓶颈:

str = str + " " + str_jieguo;   // 1
if (!ay_shuju.Contains(str_jieguo))  // 2
{
      ay_shuju.Add(str_jieguo);
}

1、str要合并约4百万次,将产生4百万个垃圾字符串。改进方法就是用StringBuilder。
2、ay_shuju是ArrayList,那么Contains将遍历ArrayList(每次ArrayList.Contains可能要查百万级数据)。改进方法就是用HashSet<string>。

15

            string mystr = "129384/283901/123903 293120/293092/391032 232218/312398/962519 631782/239715/123987"; // 2万组 用空格隔开
            System.Collections.Generic.List<string> ay_shuju = new System.Collections.Generic.List<string>(1000);
            int groupCount = (mystr.Length + 1) / (3 * 6 + 2 + 1);
            byte[] isNumber = new byte[1000];
            string str = new string(" ", groupCount * (6 * 6 * 6 * 4));
            fixed (byte* isNumberFixed = isNumber)
            fixed (char* mystrFixed = mystr, strFixed = str)
            {
                for (char* group = mystrFixed, end = mystrFixed + groupCount * (3 * 6 + 2 + 1), strWrite = strFixed + 1; group != end; group += (3 * 6 + 2 + 1))
                {
                    char* ii = group, iiEnd = group + 6;
                    do
                    {
                        int iiNumber = (*ii - "0") * 100;
                        char* jj = group + 7, jjEnd = jj + 6;
                        do
                        {
                            int jjNumber = iiNumber + (*jj - "0") * 10;
                            char* kk = group + (7 * 2), kkEnd = kk + 6;
                            do
                            {
                                int number = jjNumber + (*kk - "0");
                                *strWrite = *ii;
                                *(strWrite + 1) = *jj;
                                *(strWrite + 2) = *kk;
                                if (isNumberFixed[number] == 0)
                                {
                                    ay_shuju.Add(new string(strWrite, 0, 3));
                                    isNumberFixed[number] = 1;
                                }
                                strWrite += 4;
                            }
                            while (++kk != kkEnd);
                        }
                        while (++jj != jjEnd);
                    }
                    while (++ii != iiEnd);
                }
            }

5

假如需要考虑非法数据造成内存写安全问题,可以加一个判断 (uint)number < 1000 ,或直接使用isNumber[number]让它抛异常

            string mystr = "129384/283901/123903 293120/293092/391032 232218/312398/962519 631782/239715/123987"; // 2万组 用空格隔开
            System.Collections.Generic.List<string> ay_shuju = new System.Collections.Generic.List<string>(1000);
            int groupCount = (mystr.Length + 1) / (3 * 6 + 2 + 1);
            byte[] isNumber = new byte[1000];
            string str = new string(" ", groupCount * (6 * 6 * 6 * 4));
            fixed (byte* isNumberFixed = isNumber)
            fixed (char* mystrFixed = mystr, strFixed = str)
            {
                for (char* group = mystrFixed, end = mystrFixed + groupCount * (3 * 6 + 2 + 1), strWrite = strFixed + 1; group != end; group += (3 * 6 + 2 + 1))
                {
                    char* ii = group, iiEnd = group + 6;
                    do
                    {
                        int iiNumber = (*ii - "0") * 100;
                        char* jj = group + 7, jjEnd = group + (7 + 6);
                        do
                        {
                            int jjNumber = iiNumber + (*jj - "0") * 10;
                            char* kk = group + (7 * 2), kkEnd = group + (7 * 2 + 6);
                            do
                            {
                                int number = jjNumber + (*kk - "0");
                                *strWrite = *ii;
                                *(strWrite + 1) = *jj;
                                *(strWrite + 2) = *kk;
                                if ((uint)number < 1000 && isNumberFixed[number] == 0)
                                {
                                    ay_shuju.Add(new string(strWrite, 0, 3));
                                    isNumberFixed[number] = 1;
                                }
                                strWrite += 4;
                            }
                            while (++kk != kkEnd);
                        }
                        while (++jj != jjEnd);
                    }
                    while (++ii != iiEnd);
                }
            }

5

string txt = "129384/283901/123903 293120/293092/391032 232218/312398/962519";
char[] txt2 = txt.ToCharArray();

每段中摘抄字符,从 txt2 数组处理即可。
很显然,第 i 组的第 j 段字符的txt2中的下标位置是在 i*21 +1 +j*7。假如这个公式不对,请本人修改,搞懂它意思就行了。

10

不管你总体数据有多少,只要一组数据做对了,其他全部的也就都对了
他实际就是求个笛卡尔积

            var s = "129384/283901/123903";
            var a = s.Split("/");
            var q = from x in a[0].ToArray()
                    from y in a[1].ToArray()
                    from z in a[2].ToArray()
                    select (x-"0") * 100 + (y - "0") * 10 + z-"0";
            foreach (var c in q) Console.WriteLine(c);
121
122
123
129
120
123
181
182
183
189
180
183
131
132
133
139
130
133
191
192
193
199
190
193
101
102
103
109
100
103
111
112
113
119
110
113
221
222
223
229
220
223
281
282
283
289
280
283
231
232
233
239
230
233
291
292
293
299
290
293
201
202
203
209
200
203
211
212
213
219
210
213
921
922
923
929
920
923
981
982
983
989
980
983
931
932
933
939
930
933
991
992
993
999
990
993
901
902
903
909
900
903
911
912
913
919
910
913
321
322
323
329
320
323
381
382
383
389
380
383
331
332
333
339
330
333
391
392
393
399
390
393
301
302
303
309
300
303
311
312
313
319
310
313
821
822
823
829
820
823
881
882
883
889
880
883
831
832
833
839
830
833
891
892
893
899
890
893
801
802
803
809
800
803
811
812
813
819
810
813
421
422
423
429
420
423
481
482
483
489
480
483
431
432
433
439
430
433
491
492
493
499
490
493
401
402
403
409
400
403
411
412
413
419
410
413

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明求们帮忙解决下运算效率问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)