递归优化小技巧:用hashmap或者数组来预存sub-result以加快速度

技巧如题,先用hashmap或者数组来保存某些已经算好的,之后可能会重复用到的子问题的答案,这样在每次递归之前先判断,如果是存在在map里的,就直接取value返回即可。可以大大提高递归的效率。
例一:LeetCode 140. Word Break II

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words.

Return all such possible sentences.

For example, given
s = “catsanddog”,
dict = [“cat”, “cats”, “and”, “sand”, “dog”].

A solution is [“cats and dog”, “cat sand dog”].

//a faster way of recursion,it use hashmap to store some pre-found string and corresponding speration, so this information could be directly used compeatedly, thus save the time for recursion. Every time we search from the end of the string, if there exist a valid word, we let rest of the string to go into recursion and get the returned list, we just need to add the valid string to every valid strings that have been found.
    HashMap<String,List<String>> map = new HashMap<String,List<String>>();
    HashSet<String> set = new HashSet<>();

    public List<String> wordBreak(String s, List<String> wordDict) {
        for (String str : wordDict) {
             set.add(str);
         }
        return helper(s);
    }
    public List<String> helper(String s) {
        List<String> res = new ArrayList<>();
        if(s.length() == 0) {
            return res;
        }
        if(map.containsKey(s)) {
            return map.get(s);
        }
        if(set.contains(s)) {
            res.add(s);
        }
        for(int i = 1 ; i < s.length() ; i++) {
            String t = s.substring(i);
            if(set.contains(t)) {
                List<String> temp = helper(s.substring(0 , i));
                if(temp.size() != 0) {
                    for(int j = 0 ; j < temp.size() ; j++) {
                        res.add(temp.get(j) + " " + t);
                    }
                }
            }
        }
        map.put(s , res);
        return res;
    }
例二:LeetCode 337. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:
     3
    / \
   2   3
    \   \ 
     3   1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:
     3
    / \
   4   5
  / \   \ 
 1   3   1
Maximum amount of money the thief can rob = 4 + 5 = 9.
代码:
public int rob(TreeNode root) {
    return robSub(root, new HashMap<>());
}

private int robSub(TreeNode root, Map<TreeNode, Integer> map) {
    if (root == null) return 0;
    if (map.containsKey(root)) return map.get(root);

    int val = 0;

    if (root.left != null) {
        val += robSub(root.left.left, map) + robSub(root.left.right, map);
    }

    if (root.right != null) {
        val += robSub(root.right.left, map) + robSub(root.right.right, map);
    }

    val = Math.max(val + root.val, robSub(root.left, map) + robSub(root.right, map));
    map.put(root, val);

    return val;
}
例三:LeetCode 312. Burst Balloons

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.

Find the maximum coins you can collect by bursting the balloons wisely.

Note:
(1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

Given [3, 1, 5, 8]

Return 167

    nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
   coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167
解法:实际上是解法一的优化,这里用了一个二维数组C[n+2][n+2]来预存答案,防止重复计算,其中存的是C[start][end],表示从start到end的数组的最大值,同时,注意,在辅助函数中的for loop是表示目前的start和end的数组求最大值,分为最后戳破第i个气球,i = start ~ end, 然后全部求完的情况,maintain一个最大值,放入C矩阵。另外,求最大值过程中的nums[s - 1] * nums[i] * nums[e + 1]表示最后戳破第i个气球,最后返回C[1][n]即为答案。
public int maxCoins(int[] nums) {
      int n = nums.length;
      int[] newnums = new int[n + 2];
      newnums[0] = 1; newnums[n + 1] = 1;
      for(int i = 0; i < n; i++){
        newnums[i + 1] = nums[i];  
      }  
      int[][] C = new int[n + 2][n + 2];
      return helper(newnums, C, 1, n);  
    }

    int helper(int[] nums, int[][] C, int s, int e){
        if(s > e) return 0;
        if(C[s][e] > 0){
          return C[s][e];  
        }
        for(int i = s; i <= e; i++){
          int v = nums[s - 1] * nums[i] * nums[e + 1] + helper(nums, C, s, i - 1) + helper(nums, C, i + 1, e);  
          C[s][e] = Math.max(C[s][e], v);  
        }
        return C[s][e];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值