Leetcode 115 Distinct Subsequences

在这里插入图片描述
思路一: 不容易啊,自己做出backtracking(dfs)的hard题。哈哈其实我是事先知道了这题要用dfs来做所以才直接往这方向靠的,不然的话也不一定我就能想到dfs。其实朝着dfs方向去想还是很容找到规律的。准确的说这边是使用了recursion and memorization,光用recursion会acception denied,因为time limit exceeded。下面简单说一下自己的思路吧:base case有两个,一个是当s长度小于t长度,返回0;另一个是当t的长度为1,只需简单计算此时s中有几个t就行,返回这个数字。为什么t长度会为1,因为在整个recursion过程中s,t的长度是一直在缩短的。说完了base case,我们来说normal case。我们遍历s,找到所有与t的第一个字符相等的字符,如果找到了,就执行numDistinc(s.substring(i+1),t.substring(1))。这样做的原因是:你想,我们已经在s的i位置找到了与t第一个字符相等的字符,那我们接下来要做什么呢?此时t的第一个字符已经匹配成功,那么我们是不是只要在(s从i之后的字符串)里找有多少个与(t从1之后的字符串)相等的字符串就行了,对吗。你看,这样recursion不就出现了吗,这就是为什么我们要计算numDistinc(s.substring(i+1),t.substring(1))的原因了。最后还有一个要注意的就是,每次recursion的结果我们都存进hashmap中,减少重复计算。思路还是很简单的,下面直接上代码:

class Solution {    
    private Map<String,Integer> mappings;
   
    private int res(String s, String t){

		// 这行代码其实并没有给mappings初始化,传入到numDistinc()的时候mappings = null
		// 这行代码可以删除,并不影响结果
        mappings = new HashMap<String,Integer>();
        
        return this.numDistinct(s,t);
    }
    
    public int numDistinct(String s, String t) {
        String key = s + " " + t;
        
		// 这行判断代码必须要有,因为一开始map是空的,map == null
		// 这时候containskey会报空指针的错
		// 我们只需要重新实例化一下就好
        if(mappings == null){mappings = new HashMap<String,Integer>();}
        
        if(mappings.containsKey(key)){return mappings.get(key);}
        if(s.length() < t.length()) {return 0;}
        int res = 0;
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == t.charAt(0)){
                if(t.length() == 1){
                    for(int j = 0; j < s.length(); j++){
                        if(s.charAt(j) == t.charAt(0)){
                            res++;
                        }
                    }
                    return res;
                }else{
                    String s1 = s.substring(i+1);
                    String t1 = t.substring(1);
                    res += numDistinct(s1,t1);
                }
            }
        }
        mappings.put(key,res);
        return res;
    }
}

思路二: 可以去lc的解答一看思路,虽然写的文章很长,但是耐心看下去真的很详细,解释的特别好,很有水平。他也是用recursion+memorization来实现的,只是在recursion上的想法和我不同。代码也很有水平,这边我直接上代码了:

class Solution {
    
    // Dictionary that we will use for memoization
    private HashMap<Pair<Integer, Integer>, Integer> memo;
    
    private int recurse(String s, String t, int i, int j) {
        
        int M = s.length();
        int N = t.length();
        
        // Base case
        if (i == M || j == N || M - i < N - j) {
            return j == t.length() ? 1 : 0;
        }
        
        Pair<Integer, Integer> key = new Pair<Integer, Integer>(i, j);
        
        // Check to see if the result for this recursive
        // call is already cached
        if (this.memo.containsKey(key)) {
            return this.memo.get(key);
        }
        
        // Always calculate this result since it's
        // required for both the cases
        int ans = this.recurse(s, t, i + 1, j);
        
        // If the characters match, then we make another
        // recursion call and add the result to "ans"
        if (s.charAt(i) == t.charAt(j)) {
            ans += this.recurse(s, t, i + 1, j + 1);
        }
        
        // Cache the result
        this.memo.put(key, ans);
        return ans;
    }
    
    public int numDistinct(String s, String t) {
        
        this.memo = new HashMap<Pair<Integer, Integer>, Integer>();        
        return this.recurse(s, t, 0, 0);
    }
}
非常清晰的思路以及代码,非常值得学习!

总结:

  1. 注意我自己方法里面的那个注释。报空指针的错原因是map = null。这边刚开始的时候map里面什么都没有,是空的,就是null,所以需要初始化一下。这边我还是有疑惑的,我觉得我已经在res()里面初始化过了,为什么map还是等于null呢。希望看完这篇文章有答案的同学能给我解答一下疑惑。Thanks in advance!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值