背景
在近期的项目中,有一个的功能设计,此功能有一个将指标修饰词进行排列组合的步骤。
一开始的觉得这里使用多重循环就可以解决,随着实践发现了一些暴力算法的局限性,有想起来之前做图计算最短路径的深度优先搜索DFS算法,在这个场景加以变化正好适用。
场景
需要对多种类型的修饰词进行组合
例:
类型A的值有: 1,2
类型B的值有: a,b,c
那么组合的结果就有:1,a; 1,b; 1,c; 2,a; 2,b; 2,c;1 ;2 ;a ;b ; c 共11种
暴力算法与其局限
使用双循环就可以达到目的,这里就不做编码示例了。
但是局限显而易见,当我不知道有多少种类型的数据要进行组合的话,多层for循环的编码就无法实现了。
DFS算法
DFS算法其实是一种图算法,此算法简单地说就是使用递归方法模拟穷举搜索的过程。在图的起点我们可以选择不同的方向去查找下一个点,然后在新的点又可以选择不同的方向去找下一个点。深度优先(deep-first)体现在每次遍历都是优先朝同一方向前进,直到遇到边界的时候返回,再去探索其他方向。如下图所示:
结合项目中的场景,需要对不同的项做排雷组合,我们可以先将数据转为二维数组,再给数组加上边界,数据就成为了一个有x,y两个方向的二维图,就可以使用DFS的方法去遍历数据并且进行排列组合了。还是以上面的数据再加一个类型C为例:
- 类型A的值有: 1,2
- 类型B的值有: a,b,c
- 类型C的值有:1,2,3,4,5,6,7
由于组合中还要考虑到一些类型不取的情况,比如类型A,C的值都取空,组合结果可以为a。
所以我们可以在每个类型后添加一个值-1表示不取值。
- 类型A: 1,2,-1
- 类型B: a,b,c,-1
- 类型C:1,2,3,4,5,6,7,-1
这时比如遍历结果为-1,a,1 其实就是a,1这个结果。
然后是数据结构选型,这里可以使用二维数据,类型的数目(x)就是第一维的长度,每个类型的最大长度+1(maxlen+1,因为要加-1这个边界值所以为maxlen+1)就是第二维度的长度。
现在可将数据放入二维数据data[x][maxlen+1],初始化后为data[3][8]:
- 类型A: 1,2,-1,-1,-1,-1,-1,-1
- 类型B: a,b,c,-1,-1,-1,-1,-1
- 类型C:1,2,3,4,5,6,7,-1
按照DFS算法的思路,从data[0][0]出发,结合实际的需求(做不同类型项的组合),在这个二维的图中应该优先向下走,再向右走,比如data[0][0]=1的下一步应当优先为data[1][0]=a。
-
当无法继续向下走的时候(也就是完成了一个组合如 1,a,1)再向右走。
-
当向右移动的时候到达新的点仍然是遵循先向下再向右的规则(比如到达data[2][1]位置时,无法向下走此时有了新组合1,a,2)。
-
每次向下走的时候,需要把第二维的角标置为0,这是和标准图算法DFS不一样的地方。比如:data[1][0]位置