文章目录
-
- 1. 业务需求描述
- 2. 方法一
- 3. 方法二
- 4. 方法比较
1. 业务需求描述
比如描述狗的品种有如下多个角度:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TUYFGcGJTYxolMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jMyIDN0YjMyIDMykDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
我们可以将其表示为一个二维数组的形式:
String[][] dogStyle = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" } ,{"聪明", "友善"}};
我们现在的需求是: 需要从各个组合角度统计狗的品种的数量,……等等,不对,这是后续的需求,现在需要知道各个角度所有可能的组合,如:
小型-家庭犬-聪明
小型-家庭犬-友善
小型-玩具犬-聪明
……
大型-牧羊犬-友善
很简单啊,一个三层循环搞定,但是问题是:可能有10个维度,那就是10层循环了,或者,我根本不知道需要几层循环,目前客户从3个维度描述了一只狗,以后他可能从N个维度描述一只狗。
好了,需求:从N个维度各抽一个元素进行组合,需要得到所有可能的组合。
感觉这个需求很简单,又不好描述,如果还未表达清楚或者对文章题目有什么好的意见的话(我非常不满意这个题目),非常欢迎下方评论。
2. 方法一
直接拷过去,执行看看效果;打断点,debug看看执行过程。
package com.fukaiit;
public class Test {
public static void main(String[] args) {
String[][] dogStyles = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" }, { "聪明", "友善" } };
recursion(0, dogStyles, "");// 0表示从第一维开始遍历
}
private static void recursion(int index, String[][] dogStyles, String dogStyleCombination) {
for (int i = 0; i < dogStyles[index].length; i++) {
String dogStyle = dogStyles[index][i];// 获取到当前遍历到的某个具体的元素
String tempDSC = dogStyleCombination + " " + dogStyle;// dogStyleCombination表示元素的组合,这里换成List也是可以的,不过注意要clone
if (index + 1 == dogStyles.length) {// 如果到了最后一维,直接输出
System.out.println(tempDSC);
} else {// 如果还没到最后一维,带着当前组合的部分进行下一维
recursion(index + 1, dogStyles, tempDSC);
}
}
}
}
执行效果:
也可以把二维数组换成HashMap啥的,如:
HashMap<String, List<String>> dogStyles=new HashMap<String, List<String>>();
数据举例:
{
size: ["小型", "中型", "大型"],
function: ["家庭犬", "玩具犬", "工作犬", "牧羊犬"],
trait: ["聪明", "友善"]
}
输出的时候也可以输出成一个
List<List<String>>
。
本文为了使代码尽量清晰点,使用了二维数组和字符串拼接这种最简洁的方式。
3. 方法二
同样,先上代码:
package com.fukaiit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
String[][] dogStyles = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" }, { "聪明", "友善" } };
List<String> result = recursion(dogStyles, Arrays.asList(dogStyles[0]), Arrays.asList(dogStyles[1]), 1);//这里为什么传1呢,因为0相当于已经是既定的了,从第二维开始遍历
for (String str : result) {
System.out.println(str);
}
}
private static List<String> recursion(String[][] dogStyles, List<String> dogStyleCombination, List<String> currentlist, int index) {//参数可以简化,我先不管了
List<String> tempList = new ArrayList<>();
for (int i = 0; i < dogStyleCombination.size(); i++) {//dogStyleCombination是已经组合好的部分
for (int k = 0; k < currentlist.size(); k++) {//currentlist是当前需要组合上去的部分
tempList.add(dogStyleCombination.get(i) + " " + currentlist.get(k));
}
}
if (index + 1 == dogStyles.length) {// 如果到了最后一维,直接返回
return tempList;
} else {// 如果还没到最后一维,带着当前组合的部分进行下一维
return recursion(dogStyles, tempList, Arrays.asList(dogStyles[index + 1]), index + 1);
}
}
}
方法2的逻辑:将第一维各元素和第二维各元素组合,组合好之后,去检查有没有下一维:如果有的话,拿着已组合好的部分(其实相当于单纯的一个维度,只是行数更多)和下一维各元素再去组合,直到最后一维,则直接返回。
4. 方法比较
简单比较一下两个方法:
-
相同点
(1)递归的思想和处理都是一样的
(2)两个方法能互相替代实现完全相同的业务需求
-
不同点
(1)方法1的递归更简洁,递归方法中只有一层for循环,方法2中有两层for循环,当二维数组.length<=1的时候稍有点问题,需要特殊处理一下。
(2)方法2的思路更清晰,代码可读性更强