算法5:分治(归并)

分治的思想为将大问题分解为子问题,子问题再分解为更小的子问题,直到不能再拆分,然后再合并子问题的结果,通常需要用到递归。关键是要找对如何拆解问题。

5.1 不同的二叉搜索树

LeetCode No.95

问题描述:给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 。

思路:根据二叉搜索树的特点,左子树的所有节点值均小于根节点,右子树的所有节点值均大于根节点,同时对于每一个子树也要满足以上条件。1...n有序序列,假设对于每一个值i作为根节点,可以先求的[1,i - 1]构成的二叉搜索左子树,[i + 1, n]构成的二叉搜索右子树,然后从左右子树中各选一个作为当前根节点的左右子树。

示例代码:

func generateTrees(n int) []*TreeNode {
    return _generateTrees(1, n)
}

func _generateTrees(start, end int) []*TreeNode {
    if start > end {
        return []*TreeNode{nil}
    }
    res := []*TreeNode{}
    for i := start; i <= end; i++ {
        left := _generateTrees(start, i - 1)
        right := _generateTrees(i + 1, end)
        for _, l := range left {
            for _, r := range right {
                tmp := &TreeNode{
                    Val: i,
                    Left: l,
                    Right: r,
                }
                res = append(res, tmp)
            }
        }
    }
    return res
}

5.2 为运算表达式设计优先级

LeetCode No.241

题目描述:给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。

思路:对于每个预算式形如x op y,其左右表达式也可以看做一个形如x op y的运算式,对左右两边的运算式的所有结果进行计算,就可以得到最终的结果。

示例代码:

func diffWaysToCompute(expression string) []int {
    num, err := strconv.Atoi(expression)
    // 如果为纯数字,直接返回数字
    if err == nil {
        return []int{num}
    }
    res := []int{}
    for i, ch := range expression {
        // 跳过非运算符
        if ch != '+' && ch != '-' && ch != '*' {
            continue
        }
        // 计算运算符左右两边子表达式的结果
        left := diffWaysToCompute(expression[ : i])
        right := diffWaysToCompute(expression[i + 1 : ])
        for _, l := range left {
            for _, r := range right {
                var tmp int
                switch ch {
                case '+': tmp = l + r
                case '-': tmp = l - r
                case '*': tmp = l * r
                }
                res = append(res, tmp)
            }
        }
    }
    return res
}

你可能感兴趣的:(算法5:分治(归并))