刷leetcode遇到了 不擅长的排列组合问题 看了两道以后觉得有必要总结一下。
遇到combination问题 首先考虑recursion也就是回溯的思想
第一题是用九键打字可能的字符串序列 也就是若干个集合的 有序全排列。
eg: {a,b,c} 笛卡尔积{d,e,f}
核心函数:相当于一个DFS,深度优先遍历。
static private void combination(List<List<String>> lists,List<String> result,int depth,String cur)
{
if(depth==lists.size())
{
result.add(cur);
return;
}
for(int i=0;i<lists.get(depth).size();++i)
combination(lists,result,depth+1,cur+lists.get(depth).get(i));
}
从集合list中第一个开始,depth表示集合索引,i是集合内部元素索引。
第二题是给出n,写出所有可能的合法的n对括号序列。
eg: n=2 就是 {()(),(())} 这形状哈哈哈我邪恶了
核心函数: lal 已经添加的左括号数 ral已经添加的右括号数
private static void combination(int n, List<String> result,int lal,int ral,String str) {
if(str.length()==2*n)
{
result.add(str);
return;
}
if(lal<n){
combination(n,result,lal+1,ral,str+"(");
}
if(lal>ral)
{
combination(n,result,lal,ral+1,str+")");
}
}
recursion的逻辑有点绕 不太好正向推导,但是一旦有思路就水到渠成。这里 就是一开始在n限制内先加左括号,然后根据合法判断加入右括号,这样结果完全。我最开始在想的时候合法性判断这里很容易想到,但是纠结在怎么才能让程序自己找到所有可能,看了一眼答案恍然大悟,只要先插入左括号递归一次,接着判断是否要插入右括号,再递归,自然每种情况都会考虑到。
此外还遇到了一个问题:最初我的函数是这么写的:
if(lal<n){
str+="(";
combination(n,result,lal+1,ral,str);
}
if(lal>ral)
{
str+=")";
combination(n,result,lal,ral+1,str);
}
这样结果是错误的:例如N=3:
Output
["((()))","((()()","((()()","(()(()","(()(()"]
Expected
["((()))","(()())","(())()","()(())","()()()"]
造成这种错误的原因是,在第lal<n的if语句中修改了str,传入第一个递归中之后,str=( 这一改变也传入了下面的lal>ral的if语句。