代码如下:
/** * 将数字拆分为指定数量的子数字数组 * @param targetNumber 需要拆分的目标数字 * @param splitCount 拆分次数 * @returns 拆分后的子数字数组 */ private numberSplit(targetNumber: number, splitCount: number): Array<number> { // 当前拆分次数 let currSplitCount = 1, // 拆分后的数字 resultNumbers: Array<number> = [], // 当前拆分的数字 currSplitNumber = targetNumber, // 当前拆分的数字 currSplitNumber 被拆分后的子数字 splitedNumbers: Array<number> = [] // 循环拆分,如果当前拆分次数小于总拆分次数 while (currSplitCount < splitCount) { // 当前拆分的数字一分为二 splitedNumbers = this.numberDichotomy(currSplitNumber) // 将子数字合并到结果中 resultNumbers = resultNumbers.concat(splitedNumbers) // 累计拆分次数 currSplitCount++ // 判断当前拆分次数是否小于总拆分次数,如果是,则继续拆分 if (currSplitCount < splitCount) { // 获取子数字中最大的数字,作为下一次被拆分的数字,等待下一次拆分 currSplitNumber = Math.max(...splitedNumbers) // 如果子数字中最大的数字为1,则停止拆分 if (currSplitNumber === 1) break // 否则,将下次待拆分的数字从结果中移除,因为它会被一分为二的子数字替换 ArrayHelper.Remove(resultNumbers, currSplitNumber) } } // 累计子数字的和,用于验证是否与目标数字相等 const totalNumber = resultNumbers.reduce((total, curr) => total += curr, 0) console.log('目标数字', targetNumber, '拆分次数', splitCount, '拆分后的数字', resultNumbers.join(','), '子数字累计值', totalNumber, `目标数字 ${targetNumber === totalNumber ? '=' : '≠'} 子数字累计值`) return resultNumbers } /** * 将数字一分为二 * @param num 目标数字 * @returns 拆分后的子数字数组 */ private numberDichotomy(targetNum: number): Array<number> { if (targetNum < 2) return [targetNum] if (targetNum === 2) return [1, 1] // 随机获取 1~目标数字减1之间的数作为子数字1 const subNum1 = this.randomNum(1, targetNum - 1), // 目标数字减子数字1作为子数字2 subNum2 = targetNum - subNum1 // 子数字合并成结果 const resultNumbers = [subNum1, subNum2] return resultNumbers } /** * 生成从 min 到 max 的随机数 * @param min 最小值 * @param max 最大值 * @returns 随机数 */ private randomNum(min: number, max: number): number { switch (arguments.length) { case 1: return parseInt((Math.random() * min + 1).toString(), 10) case 2: return parseInt((Math.random() * (max - min + 1) + min).toString(), 10) default: return 0 } }
// 使用 const answers = this.numberSplit(target, step) console.log(answers)
代码使用 TypeScript 写的,js 使用去掉类型注解即可。
嘴角上扬,记得微笑