1-45选6乐透号码与整数值双向转换算法实现(C#优先)
乐透彩票号码与整数双向互转低内存实现
这个需求的映射逻辑本质是组合数编码规则,不需要预存全量组合映射表,内存占用可忽略,单次转换时间复杂度固定为O(1)(因单注号码固定为6个,计算量恒定),完全可以替代高内存占用的全量预计算方案。
规则对齐
实现完全匹配给定的映射规则:
- 单注包含6个1~45范围内的不重复号码,按从小到大排序后参与计算
- 最小组合
01-02-03-04-05-06对应序号1 - 最大组合
40-41-42-43-44-45对应序号8145060 - 总组合数为C(45,6)=8145060,和规则定义一致
核心算法逻辑
号码转序号
- 将输入的6个号码从小到大排序,得到升序序列c₀<c₁<c₂<c₃<c₄<c₅
- 基于组合数累加计算0基偏移,最终+1得到1基序号:
序号 = C(c₀-1,1) + C(c₁-1,2) + C(c₂-1,3) + C(c₃-1,4) + C(c₄-1,5) + C(c₅-1,6) + 1
其中C(n,k)为组合数公式,代表从n个元素选k个的方案数,当n<k时C(n,k)=0
序号转号码
- 将输入的1基序号减1转为0基偏移量m
- 从最大选位k=6开始倒推,每次找到满足
C(c,k) ≤ m的最大整数c,将c+1(转1基)作为当前位的号码 - 偏移量m减去C(c,k),k值减1,重复直到6个号码全部推导完成
- 最终得到的号码自然为升序排列,无需额外排序
C# 完整实现
public static class LottoConverter { // 计算组合数C(n,k),n<k时直接返回0 private static long Comb(int n, int k) { if (n < k || k < 0) return 0; if (k == 0 || k == n) return 1; k = Math.Min(k, n - k); long result = 1; for (int i = 1; i <= k; i++) { result = result * (n - k + i) / i; } return result; } /// <summary> /// 6个乐透号码转对应1基序号 /// </summary> /// <param name="numbers">6个1-45范围的不重复整数</param> /// <returns>1-8145060范围的映射序号</returns> public static long NumbersToIndex(int[] numbers) { if (numbers.Length != 6) throw new ArgumentException("单注乐透需包含6个号码", nameof(numbers)); var sorted = numbers.OrderBy(n => n).ToArray(); for (int i = 0; i < 6; i++) { if (sorted[i] < 1 || sorted[i] > 45) throw new ArgumentOutOfRangeException(nameof(numbers), "号码取值范围必须为1-45"); if (i > 0 && sorted[i] == sorted[i-1]) throw new ArgumentException("号码不能重复", nameof(numbers)); } long index = 1; for (int i = 0; i < 6; i++) { index += Comb(sorted[i] - 1, i + 1); } return index; } /// <summary> /// 1基序号转对应乐透号码 /// </summary> /// <param name="index">1-8145060范围的映射序号</param> /// <returns>升序排列的6个乐透号码</returns> public static int[] IndexToNumbers(long index) { if (index < 1 || index > 8145060) throw new ArgumentOutOfRangeException(nameof(index), "序号取值范围必须为1-8145060"); long m = index - 1; int[] result = new int[6]; int k = 6; for (int i = 5; i >= 0; i--) { int c = k - 1; while (Comb(c + 1, k) <= m) { c++; } result[i] = c + 1; m -= Comb(c, k); k--; } return result; } }
样例验证
- 输入号码
[1,2,3,4,5,6],转换得到序号1,符合规则 - 输入号码
[1,2,3,4,5,7],转换得到序号2,符合规则 - 输入序号8145059,转换得到号码
[39,41,42,43,44,45],符合规则 - 输入序号8145060,转换得到号码
[40,41,42,43,44,45],符合规则
该实现无全局预加载数据,运行时内存占用为固定常量,单次转换仅需最多几十次整数运算,批量转换性能远高于预计算查表方案。
内容的提问来源于stack exchange,提问作者leo337
相关产品推荐
相关产品推荐

