您的位置:首页 > 其它

[一天一项目] 获取m个数中和等与k的n个数

2017-08-04 13:26 288 查看
今天在CSDN问答看到一个关于递归算法的求值题。觉得很有意思。现在把题目和我自己的答案写下来。

有m个数(有重复值),如果其中的n(n不固定,即可设定)个数的值为k(可设定,不固定)。那么这样的n组合有哪些?

package com.project.GetNNumCount;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class getNNumCount {
private static int NUM = 0;
private static int count = 0;

//因为项目中存在重复数据,所以没有办法用set存储,导致最后生成的list会出现重复数据
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入X个数,用逗号分割:");
String str = input.nextLine();
String[] datas = str.split(",");
System.out.println("请输入数字M:");
NUM = input.nextInt();
System.out.println("请输入数字N:");
count = input.nextInt();
if (NUM > datas.length) {
System.out.println("输入的Y必须小于等于X!");
return;
}
combine(Arrays.asList(datas));
}

private static void combine(List<String> datas) {
List<String> list = new ArrayList<String>();
String tmp;
//对初始数组进行排序,为后续结果集筛选做准备
/**
*  排序前后差别
*  排序前:比如   1,3,1,3   2个数相加 得到 4
*  有[1,3],[1,3],[3,1],[3,1],[1,3]几种可能
*  排序后:1,1,3,3 有[1,3],[1,3],[1,3],[1,3]几种可能
*  对后面的重复list判断帮助很大
*
*/
for (int i = 0; i < datas.size() - 1; i++) {
for (int j = 1; j < datas.size() - i; j++) {
int data_1 =Integer.parseInt(datas.get(j));
int data_2 =Integer.parseInt(datas.get(j-1));
if (data_2 > data_1) {
tmp = datas.get(j);
datas.set(j,datas.get(j-1));
datas.set(j-1,tmp);
}
}
}
for(String str : datas) {
list.add(str);
//查看排序后的值
//System.out.println(str);
}

ArrayList<List<String>> subset = getSubset(list);

getNumCount(subset,count);
}

public static String[] getBinaryValue(List<String> datas) {
int size = datas.size();
int m = (int) Math.pow(2, size) - 1;
String[] result = new String[m + 1];
for (int i = m; i > -1; i--) {
StringBuffer sb = new StringBuffer(Integer.toBinaryString(i));
int length = sb.length();
if (length < size) {
for (int j = 0; j < size - length; j++) {
sb.insert(0, "0");
}
}
result[i] = sb.toString();
}
return result;
}

public static ArrayList<List<String>> getSubset(List<String> datas) {
ArrayList<List<String>> result = new ArrayList<List<String>>();
String[] items = new String[datas.size()];
int i = 0;
for (String item : datas) {
items[i++] = item;
}
String[] binaryValue = getBinaryValue(datas);
for (int j = 0; j < binaryValue.length; j++) {
String value = binaryValue[j];
List<String> subset = new ArrayList<String>();
for (int k = 0; k < value.length(); k++) {
if (value.charAt(k) == '1')
subset.add(items[k]);
}
if (subset.size() == NUM)
result.add(subset);
}

return result;
}

//获取到最后的list,需要进行最后的筛选
public static void getNumCount(ArrayList<List<String>> subset, int count) {
int count_new = 0;
List<List<String>> list = new ArrayList<List<String>>();
for (List<String> ts : subset) {
count_new = 0;
for (String num : ts) {
count_new += Integer.parseInt(num);
}
//判断是否符合所要求的总和
if (count_new == count) {
//如果list长度大于0,就开始与后一个list进行比较
if(list.size() == 0){
list.add(ts);
}else{
//如果两个list内容不相同,就添加到list中
if(!list.get(list.size()-1).equals(ts)){
list.add(ts);
}
}

}

}
for(List<String> list1 : list){
System.out.println(list1);
}
System.out.println("break");
}
}


如果这题不考虑重复数据的话会简单很多,在初始值生成的时候,用set接受排除重复数据影响就行,之后的操作就很简单了。为了重复数据for到快吐了~~很难受。

查了资料这个题可以用递归算法和回溯算法(对此没有研究,所以知其然而不知其所以然)。同样难受

解题方法很多很多,如果你有更多的更好的解决方法,欢迎交流!谢谢

代码合集:https://github.com/FanceTsui/Project.git

——Fance Tsui

a6f1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 回溯算法