NumUtils.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. export class NumUtils {
  2. /**
  3. * 计算两点间的直线距离
  4. * @param point1
  5. * @param point2
  6. * @returns
  7. */
  8. private calculateDistance(point1, point2) {
  9. let dx = point2.x - point1.x;
  10. let dy = point2.y - point1.y;
  11. return Math.sqrt(dx * dx + dy * dy);
  12. }
  13. /**
  14. * 把一个数字随机拆分成n个数字
  15. * @param total 要拆分的数字
  16. * @param parts 拆分个数
  17. * @returns
  18. */
  19. public static splitNumberIntoRandomParts(total: number, parts: number): number[] {
  20. if (parts <= 0 || total <= 0) {
  21. throw new Error("Invalid input: parts must be greater than 0 and total must be greater than 0.");
  22. }
  23. if (parts === 1) {
  24. return [total];
  25. }
  26. // Generate N-1 random points that will divide the total into parts
  27. let points: number[] = [];
  28. let remainingTotal = total;
  29. let result: number[] = [];
  30. for (let i = 0; i < parts - 1; i++) {
  31. // Generate a random number between 0 and the remaining total
  32. const max = remainingTotal - (parts - i - 1); // Ensure we can still distribute the remaining total
  33. const randomPoint = Math.floor(Math.random() * max) + 1;
  34. points.push(randomPoint);
  35. result.push(randomPoint);
  36. remainingTotal -= randomPoint;
  37. }
  38. // Add the last part which is the remaining total
  39. result.push(remainingTotal);
  40. // Shuffle the result array to ensure randomness in order
  41. for (let i = result.length - 1; i > 0; i--) {
  42. const j = Math.floor(Math.random() * (i + 1));
  43. [result[i], result[j]] = [result[j], result[i]];
  44. }
  45. return result;
  46. }
  47. /**
  48. * 返回随机不相等的数字数组
  49. * @param min
  50. * @param max
  51. * @param count
  52. * @returns
  53. */
  54. public static getRandomUniqueNumbers(min: number, max: number, count: number): number[] {
  55. if (max - min + 1 < count) {
  56. throw new Error("Range is too small to get the required number of unique numbers.");
  57. }
  58. const result: number[] = [];
  59. const usedNumbers: Set<number> = new Set();
  60. while (result.length < count) {
  61. const randomNum = Math.floor(Math.random() * (max - min + 1)) + min;
  62. if (!usedNumbers.has(randomNum)) {
  63. result.push(randomNum);
  64. usedNumbers.add(randomNum);
  65. }
  66. }
  67. return result;
  68. }
  69. /**
  70. * 返回随机的数字数组
  71. * @param min
  72. * @param max
  73. * @param count
  74. * @returns
  75. */
  76. public static getRandomNumbers(min: number, max: number, count: number): number[] {
  77. const result: number[] = [];
  78. // const usedNumbers: Set<number> = new Set();
  79. while (result.length < count) {
  80. const randomNum = Math.floor(Math.random() * (max - min + 1)) + min;
  81. // if (!usedNumbers.has(randomNum)) {
  82. result.push(randomNum);
  83. // usedNumbers.add(randomNum);
  84. // }
  85. }
  86. return result;
  87. }
  88. /**
  89. * 把一个数字随机拆分成n个数字,数字之间大小不超过x
  90. * @param total 总数
  91. * @param n 拆分等数
  92. * @param x 相差的数
  93. * @returns
  94. */
  95. public static splitNumberRandomly(total: number, n: number, x: number): number[] {
  96. if (n <= 0 || total <= 0) {
  97. throw new Error("Invalid input: n and total must be positive.");
  98. }
  99. // 先尽量均匀分配
  100. const avg = Math.floor(total / n);
  101. const remainder = total % n;
  102. // 初始化结果数组
  103. let result: number[] = new Array(n).fill(avg);
  104. // 处理余数,将其随机分配到结果数组中
  105. for (let i = 0; i < remainder; i++) {
  106. result[Math.floor(Math.random() * n)]++;
  107. }
  108. // 检查并调整结果数组,确保相邻数字之间相差不超过 3
  109. for (let i = 1; i < n; i++) {
  110. while (Math.abs(result[i] - result[i - 1]) > x) {
  111. // 如果相差超过 3,则尝试调整
  112. if (result[i] > result[i - 1] + x) {
  113. // 从 result[i] 中减去一个单位,并尝试加到 result[i-1]、result[i+1] 或其他合适的位置
  114. result[i]--;
  115. // 为了简化,这里只尝试加到前一个或后一个元素(如果存在)
  116. if (i > 0 && Math.abs(result[i] - result[i - 1]) <= 2) {
  117. result[i - 1]++;
  118. } else if (i < n - 1 && Math.abs(result[i + 1] - (result[i] - 1)) <= 2) {
  119. result[i + 1]++;
  120. } else {
  121. // 如果无法直接调整,则随机选择一个其他位置进行调整(这里为了简化,直接抛出错误)
  122. throw new Error("Unable to adjust numbers to meet the difference constraint.");
  123. }
  124. } else if (result[i - 1] > result[i] + x) {
  125. // 类似地处理 result[i-1] 大于 result[i] + 3 的情况
  126. result[i - 1]--;
  127. if (i > 0 && Math.abs(result[i - 1] - result[i - 2]) <= 2) {
  128. result[i - 2]++;
  129. } else if (i < n && Math.abs(result[i] - (result[i - 1] - 1)) <= 2) {
  130. result[i]++;
  131. } else {
  132. throw new Error("Unable to adjust numbers to meet the difference constraint.");
  133. }
  134. }
  135. }
  136. }
  137. // 由于上述调整可能不完全保证总和等于 total(尤其是在处理复杂情况时),我们需要最后校验并调整总和
  138. let currentSum = result.reduce((a, b) => a + b, 0);
  139. if (currentSum !== total) {
  140. // 如果总和不匹配,则通过微调最后一个元素来修正(这里为了简化,假设总是可以通过这种方式修正)
  141. let diff = total - currentSum;
  142. result[n - 1] += diff;
  143. }
  144. return result;
  145. }
  146. /**
  147. * 判断数字数组里面的数字是否全部相等
  148. * @param arr
  149. * @returns
  150. */
  151. public static allEqual(arr: number[]): boolean {
  152. return arr.reduce((acc, val, index, array) =>
  153. acc && (index === 0 || val === array[index - 1]), true);
  154. }
  155. }