拆数,给定两个正整数m,n(m >= n),将m拆成n个数相加...(游戏)
1. 问题
(网上看到的题目)
昨天去面试人家出了这样一道题,觉得挺简单的,但就是编不出来,只好麻烦各位高手了。
给定两个正整数m,n(m >= n),将m拆成n个数相加:m =a(1)+a(2)+...+a(n),使之满足:a(1)<a(2)<...<a(n);
列出所有的拆法。
例如:若m=7,n=3则只有一种拆法:7=1+2+4。
2. 解决代码
package com.clzhang.game; /** * 问题: * 昨天去面试人家出了这样一道题,觉得挺简单的,但就是编不出来,只好麻烦各位高手了。 * 给定两个正整数m,n(m >= n),将m拆成n个数相加:m =a(1)+a(2)+...+a(n),使之满足:a(1)<a(2)<...<a(n); * 列出所有的拆法。 * 例如:若m=7,n=3则只有一种拆法:7=1+2+4。 * @version 1.0 * @author acer */ import java.util.*; public class SplitInt { // 返回所有拆法中各最大数集合中的最大数 private int getMax(int m, int n, int lastNum) { int total = 0; for (int i = 1; i < n; i++) { total += i; } if ((m - total) >= lastNum) return lastNum - 1; else return m - total; } // 返回当前数是否可能组成一种拆法 private boolean isValidNum(int m, int n, int num) { int total = 0; if (num < n) return false; for (int i = 0; i < n; i++) { total += num--; } return total >= m; } /* * 计算拆分结果,递归调用 * @param m - 被拆数 * @param n - 拆分个数 * @param lastNum - 上一次拆分数值 */ public LinkedList<String> calu(int m, int n, int lastNum) { LinkedList<String> result = new LinkedList<String>(); if (n == 1) { result.add(String.valueOf(m)); return result; } int num = getMax(m, n, lastNum); while (isValidNum(m, n, num)) { LinkedList<String> lkl = calu(m - num, n - 1, num); for (int i = 0; i < lkl.size(); i++) { result.add(String.valueOf(num) + "+" + lkl.get(i)); } num--; } return result; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入m值:"); int m = scanner.nextInt(); System.out.println("请输入n值:"); int n = scanner.nextInt(); scanner.close(); AbstractList<String> list = new SplitInt().calu(m, n, m); if (list.size() == 0) System.out.println("没有解!"); else { for (int i = 0; i < list.size(); i++) System.out.println("第 " + (i + 1) + " 种拆法:" + list.get(i)); } } }
3. 输出
请输入m值:
10
请输入n值:
3
第 1 种拆法:7+2+1
第 2 种拆法:6+3+1
第 3 种拆法:5+4+1
第 4 种拆法:5+3+2