多层for循环的优化

来源:互联网 发布:重复文件清理软件 mac 编辑:程序博客网 时间:2024/05/01 08:37

简单的描述一下问题:

有7组数字,每组选取一个数字,求7个数字和在2500到2510之间的组合。

 

由于这7组数据个数比较多,当时我弱弱的写了7层的for循环,运行的时候感觉要算几个月。看来这程序必须优化一下才能跑。单纯的枚举法太耗时间了。

 

没有优化前的程序片段。

for (int s1 = 0; s1 < juriList.size(); s1++) {    for (int s2 = 0; s2 < chineseList.size(); s2++) {for (int s3 = 0; s3 < nursList.size(); s3++) {    for (int s4 = 0; s4 < accountList.size(); s4++) {for (int s5 = 0; s5 < mathList.size(); s5++) {    for (int s6 = 0; s6 < civilList.size(); s6++) {for (int s7 = 0; s7 < englishList.size(); s7++) {    sum = s1 + s2 + s3 + s4 + s5 + s6 + s7;    if (sum <= max && sum >= min) {.......}    }}    }}    }}    }}


看着7层for,感觉好吓人。。。。

对于最后的结果,只有满足 和 在2500到2510 之间的数据才输出。

大部分的结果都是没有用的,这样如果能在每一层for循环开始时,对for循环的开始和结束做出动态的调整(注:数据存在List中,已经按大小排过序),这样就可以缩小遍历的次数。

下面的程序是改进的方案。


for (int s1 = 0; s1 < juriList.size(); s1++) {    minChine = min - juriNum.get(s1);    i1 = getIndex(minChine, lists, 1);    s2b = 0;    if (i1[0] == 1) {s2b = i1[1];    }    sum += juriNum.get(s1);    if (sum > max) {sum -= juriNum.get(s1);continue;    }    for (int s2 = s2b; s2 < chineseList.size(); s2++) {minNurs = minChine - chineseNum.get(s2);i2 = getIndex(minNurs, lists, 2);s3b = 0;if (i2[0] == 2) {    s3b = i2[1];}sum += chineseNum.get(s2);if (sum > max) {    sum -= chineseNum.get(s2);    continue;}for (int s3 = s3b; s3 < nursList.size(); s3++) {    minAcc = minNurs - nursNum.get(s3);    i3 = getIndex(minAcc, lists, 3);    s4b = 0;    if (i3[0] == 3) {s4b = i3[1];    }    sum += nursNum.get(s3);    if (sum > max) {sum -= nursNum.get(s3);continue;    }    for (int s4 = s4b; s4 < accountList.size(); s4++) {minMath = minAcc - accountNum.get(s4);i4 = getIndex(minMath, lists, 4);s5b = 0;if (i4[0] == 4) {    s5b = i4[1];}sum += accountNum.get(s4);if (sum > max) {    sum -= accountNum.get(s4);    continue;}for (int s5 = s5b; s5 < mathList.size(); s5++) {    minCivil = minMath - mathNum.get(s5);    i5 = getIndex(minCivil, lists, 5);    s6b = 0;    if (i5[0] == 5) {s6b = i5[1];    }    sum += mathNum.get(s5);    if (sum > max) {sum -= mathNum.get(s5);continue;    }    for (int s6 = s6b; s6 < civilList.size(); s6++) {minEng = minCivil - civilNum.get(s6);i6 = getIndex(minEng, lists, 6);s7b = 0;if (i6[0] == 6) {    s7b = i6[1];}sum += civilNum.get(s6);if (sum > max) {    sum -= civilNum.get(s6);    continue;}for (int s7 = s7b; s7 < englishList.size(); s7++) {    sum += englishNum.get(s7);    if (sum <= max && sum >= min) {......}    }    sum -= englishNum.get(s7);}sum -= civilNum.get(s6);    }    sum -= mathNum.get(s5);}sum -= accountNum.get(s4);    }    sum -= nursNum.get(s3);}sum -= chineseNum.get(s2);    }    sum -= juriNum.get(s1);}
    private static int[] getIndex(int minValue, List<List<Integer>> lists, int index) {// 得到 结果 最接近最小值的 元素索引int total = 0;int i = 0;int indexNow = 6;for (int j = lists.size() - 1; j >= index; j--) {    int nowNum = 0;    for (int z = 0; z < lists.get(j).size(); z++) {nowNum = lists.get(j).get(z);total += nowNum;if (total >= minValue - (7-index)) {    i = z;    indexNow = j;    break;} else {    total -= nowNum;}if (z == lists.get(j).size() - 1) {    total += lists.get(j).get(z);}    }}int[] result = { indexNow, i };return result;    }

在第一层for循环开始时,会从第一个值遍历所有值,这时我们重新计算一下最小值,即 2500-s1的值 ,

这个时候,我有一个想法

从最里层的for循环开始取最大值,这样从最里层开始都会得到最大的值,其和也最大,当结果接近 2500 - s1 这个值时,再外一层的for循环就不需要去最大值了,而是取数组中间的某一个值,我们返回数组的顺序及 下标。

 

我可能不能很好的表达清楚,下面借助字母再解释一遍:

 

我们有7个数组,分别是 s1, s2, s3, s4, s5, s6, s7

在开始循环的时候,s1取第一个元素,即s1的最小值。 

这个时候我们想让 从 s7开始都取最大值,这样可以接近 min , 而里层循环的小的值就不用遍历了。

我们假设有这种情况: min - s1[0]-s7max - s6max - s5max - s4[57] ∞7 我们返回 4 和 57 代表s7、s6、s5都取最大值 s4取第57的值。

这时第2层的for循环从第一个元素开始,第3层也是第一个,第4层从第57个开始,第5,6,7层都只取最后一个。

这样我们就把7个数加起来的和小于 min 的值尽可能都过滤掉了。

 

然后我们再优化一下 值大于max的部分。

对于这部分我的做法是把和已经大于max的continue了。

每深入一层for循环的时候,判断一下目前的和看是否超过max了,如果超过continue。在退出for循环的时候不要忘记把值减掉。

 

就这么多。。。



原创粉丝点击