算法学习:看看深度优先搜索算法

来源:互联网 发布:中介者模式 java 编辑:程序博客网 时间:2024/06/12 01:40

先看一题:给定整数a1,a2,a3…an,判断是否可以从中选出若干数,使他们的和恰好为k。
那么,现在分析一下问题的需求。只需从a1开始按顺序决定每个数加或者不加,在管不n个数都决定后在判断他们的和是否为k即可。换一个方式想,从某个状态开始不断的转移状态直到无法转移,然后然后回退到前一步的状态,继续转移到其他状态,如此不断的重复。
如何实现这种搜索,很容易想到一种搜索手段–深度优先搜索。

深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。

顺便提一句,因发明“深度优先搜索算法”,约翰·霍普克洛夫特与罗伯特·塔扬共同获得计算机领域的最高奖:图灵奖。

下面回到开始的问题。根据深度优先搜索算法的特点–不断转移状态和重复,通常情况下采用递归函数实现会比较简单。我们可以把数组和状态的转移看成二叉树,假设输入的数据是a={1,2,4,7},k=15,根据上面的分析我们应该可以画出下面的图:
这里写图片描述

既然思路分析清晰了,代码自然水到渠成。下面只是我的一种实现方式。

/**     *     * @param a 初始输入数组     * @param i 第i项     * @param sum 遍历到i项时的和     * @param k 目标结果     * @return     */    private static boolean defMethod(int[] a, int i, int sum, int k) {        //如果已到最后一项,得到和sum,则返回sum是否等于k        if (i == a.length)            return sum == k;        //不加a[i]的情况        if (defMethod(a, i + 1, sum, k))            return true;        //加a[i]的情况        if (defMethod(a, i + 1, sum + a[i], k))            return true;        //无论是否加上a[i]都不能得到k则返回k        return false;    }

思路和代码都完成,剩下的就是分析下以上算法的复杂度了。
因为状态数是

2n+1

所以,复杂度就可以得知是
O(2n)

最后,一句话总结下:深度优先搜索就是从最开始的状态出发,遍历所有可以达到的状态。由此就可以对所有的状态进行操作或者列出所有的状态的了。

1 0
原创粉丝点击