• Leetcode 115. 不同的子序列(二维DP)


    给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。

    字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)

    题目数据保证答案符合 32 位带符号整数范围。

    简单二维DP问题。设dp[i, j]表示以i结尾的子串含有t的长度为j的前缀的数量,二重循环遍历:

    (1)s[i] == t[j]: 转移方程为(dp[i][j] += dp[i - 1][j - 1] + dp[i - 1][j]),含义是当前可以由两种情况转移过来:

    ​ (a) s[i]恰好就是t[j],s中以i - 1为结尾的子串包括t的长度为j - 1的前缀的情况数。

    ​ (b)s中以i - 1为结尾的子串已经包括整个t的长度为j的前缀的情况数。

    (2)s[i] != t[j]: 转移方程为(dp[i][j] += dp[i - 1][j]),含义同上。

    初始化需要处理所有的dp[i, 1]为当前已经出现过的t[1]的数量。(代码中其实没必要开cnt数组存储)

    注意j初始化完了以后要从2开始,同时要开long long(虽然答案说范围在int32范围内)。还有一个坑点就是输入的字符串是大小写混合的。

    #include <iostream>
    using namespace std;
    long long dp[1005][1005];//dp[i][j]表示以i结尾的子串含有t的长度为j的前缀的数量
    long long cnt[100];
    int lens, lent;
    int main() {
    	memset(cnt, 0, sizeof(cnt));
    	memset(dp, 0, sizeof(dp));
    	string s, t;
    	cin >> s >> t;
    	lens = s.size(), lent = t.size();
    	s = " " + s, t = " " + t;
    	for(int i = 1; i <= lens; i++) {
    		cnt[s[i] - 'A']++;
    		dp[i][1] += cnt[t[1] - 'A'];
    	}
    	for(int i = 1;i <= lens; i++) {
    		for(int j = 2; j <= lent; j++) {//注意j初始化完了以后要从2开始
    			if(s[i] == t[j]) {
    				dp[i][j] += dp[i - 1][j - 1] + dp[i - 1][j];
    			} else {
    				dp[i][j] += dp[i - 1][j];
    			}
    		}
    	}
    	cout << dp[lens][lent];
    	return 0;
    }
    
  • 相关阅读:
    Tomcat修改端口号
    如何修改localhost为自己指定的域名
    Tomcat启动时启动窗口中文乱码问题的解决方案
    Java Web 项目jsp页面无法加载样式
    vue 父传子(通过属性传递)
    vue 父传子 讲解
    表白小爱心
    响应式开发
    组件的重复调用
    reduce
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14550395.html
Copyright © 2020-2023  润新知