今天遇到LEETCODE的第115题: Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of S which equals T.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Example 1:

Input: S = "rabbbit", T = "rabbit"
Output: 3
Explanation:

As shown below, there are 3 ways you can generate "rabbit" from S.
(The caret symbol ^ means the chosen letters) rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

Example 2:

Input: S = "babgbag", T = "bag"
Output: 5
Explanation:

As shown below, there are 5 ways you can generate "bag" from S.
(The caret symbol ^ means the chosen letters) babgbag
^^ ^
babgbag
^^ ^
babgbag
^ ^^
babgbag
^ ^^
babgbag
^^^

解法1:动态规划
假设已经得到了s[:i]中所有的t串f(i,t),考虑s[i]和t[-1]这2个字符,if不等:f(i+1,t)=f(i,t);else:f(i+1,t)=f(i,t)+f(i+1,t[:-1])。于是解法如下:
def dp(s,t):
  if len(s)<len(t):return 0
  if len(t)==1:return s.count(t)
  ans=dp(s[:-1],t)
  if s[-1]==t[-1]:ans+=dp(s[:-1],t[:-1])
return ans
测试中发现对比较长的S,出现了超时错误,说明时间复杂度高(O(len(s)*len(t)))。 解法2:二分法
对S进行等长分割成left,right,则结果应该=left中的数量 + right中的数量 + 跨界的数量
其中,跨界的数量 = left中的t[:1]数量*right中的t[1:]数量 + left中的t[:2]数量*right中的t[2:]数量 +...+ left中的t[:-1]数量*right中的t[-1]数量
于是解法如下:
def dp(s,t):
            print(s,t)
            if len(s)<len(t):return 0
            if len(t)==1:return s.count(t)
            n=len(s)//2
            left,right=s[:n],s[n+1:]
            ans=dp(left,t)+dp(right,t)
            for i in range(1,len(t)):
                ans+=dp(left,t[:i])*dp(right,t[i:])
            return ans
测试中发现对比较长的S,出现了超时错误,说明时间复杂度高(O(len(s)*len(t)))。同时也说明跨界的数量不能直接算出的话,最好不要用二分法。 解法3:动态规划
再回到解法1,这次用二维转移矩阵,令f(i,j)=s[:i]中t[:j]的数量,考虑s[i]和t[j]这2个字符,if不等:f(i+1,j+1)=f(i,j);else:f(i+1,j+1)=f(i,j)+f(i+1,j)。于是解法如下:
def dp(s,t): res = [[0] * (len(s) + 1) for _ in range(len(t) + 1)]
res[0] = [1] * (len(s) + 1) for i, cht in enumerate(t):
for j, chs in enumerate(s):
if cht == chs:
res[i + 1][j + 1] = res[i][j] + res[i + 1][j]
else:
res[i + 1][j + 1] = res[i + 1][j] return res[-1][-1]
进一步优化为:

def dp(s,t):
   li=[0]*len(t)
   d={}
   for i in range(len(t)):
      d[t[i]]=d.get(t[i],[])+[i]
   for i in range(len(s)):
      print(i,li,end=' ')
      if s[i] in t:
         for j in reversed(d[s[i]]):
            if j == 0:
               li[0] += 1
            else:
               li[j] += li[j - 1]
      print(li)
   return li[-1]

所有不同的序列串-----LCS算法的变种的更多相关文章

  1. 对LCS算法及其变种的初步研究

    LCS的全称为Longest Common Subsequence,用于查找两个字符串中的最大公共子序列,这里需要注意区分子序列与子串,所谓子序列,指的是从前到后,可以跳跃元素筛选,而字串则必须连续筛 ...

  2. LCS算法

    转自:http://hzzy-010.blog.163.com/blog/static/79692381200872024242126/  好详细~~~也十分好理解~~~ 最长公共子序列问题(非连续的 ...

  3. 最大公共字串LCS问题(阿里巴巴)

    给定两个串,均由最小字母组成.求这两个串的最大公共字串LCS(Longest Common Substring). 使用动态规划解决. #include <iostream> #inclu ...

  4. 序列最小最优化算法(SMO)-SVM的求解(续)

    在前一篇文章中,我们给出了感知器和逻辑回归的求解,还将SVM算法的求解推导到了最后一步,在这篇文章里面,我们将给出最后一步的求解.也就是我们接下来要介绍的序列最小最优化算法. 序列最小最优化算法(SM ...

  5. 【机器学习】支持向量机(SVM)的优化算法——序列最小优化算法(SMO)概述

    SMO算法是一一种启发式算法,它的基本思路是如果所有变量的解的条件都满足最优化问题的KKT条件,那么这个最优化问题的解就得到了.因为KKT条件是该优化问题的充分必要条件. 整个SMO算法包括两个部分: ...

  6. 笔试算法题(30):从已排序数组中确定数字出现的次数 & 最大公共子串和最大公共序列(LCS)

    出题:在已经排序的数组中,找出给定数字出现的次数: 分析: 解法1:由于数组已经排序,所以可以考虑使用二分查找确定给定数字A的第一个出现的位置m和最后一个出现的位置n,最后m-n+1就是A出现的次数: ...

  7. O(nlogn)LIS及LCS算法

    morestep学长出题,考验我们,第二题裸题但是数据范围令人无奈,考试失利之后,刻意去学习了下优化的算法 一.O(nlogn)的LIS(最长上升子序列) 设当前已经求出的最长上升子序列长度为len. ...

  8. LCS 算法实现

    动态规划算法 #include <iostream> #include <string.h> #include <algorithm> #include <m ...

  9. Levenshtein Distance + LCS 算法计算两个字符串的相似度

    //LD最短编辑路径算法 public static int LevenshteinDistance(string source, string target) { int cell = source ...

随机推荐

  1. VFIO PF SRIOV IOMMU UIO概念解释、关联

    1.UIO出现的原因 第一,硬件设备可以根据功能分为网络设备,块设备,字符设备,或者根据与CPU相连的方式分为PCI设备,USB设备等.它们被不同的内核子系统支持.这些标准的设备的驱动编写较为容易而且 ...

  2. easyUI combobox使用方法总结

    combobox,中文叫复合框,是把文本框和列表框的特性结合起来的一种控件,这个控件,既可以输入文字,也可以像列表框一样选择选项 Combobox用法和方法参数: 1. 需要引入class=" ...

  3. Linux下“/”和“~”的区别

    在linux中,”/“代表根目录,”~“是代表目录.Linux存储是以挂载的方式,相当于是树状的,源头就是”/“,也就是根目录. 而每个用户都有”家“目录,也就是用户的个人目录,比如root用户的”家 ...

  4. 代码生成器——实现生成pojo,sql,mapper接口

    代码生成器(记录一次兴趣代码,多多指教.转载请标明作者) 在我们开始实现代码生成器之前我们先来对代码生成器有一个简单的了解. 1.什么是代码生成器? 故名思义,也就是生成代码的一个程序.那它是一个什么 ...

  5. Java问题解决:"错误: 找不到或无法加载主类"

    参考资料:https://www.cnblogs.com/wangxiaoha/p/6293340.html 场景: 使用java命令运行.class文件时出现:“错误: 找不到或无法加载主类”: 解 ...

  6. js switch 字符串

    //字符串var day="dd";switch (day){case "dd": x="day it's dd"; break;case ...

  7. Linux(例如CentOS 7)打开TCP 22端口,基于SSH协议

    SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议.SSH 是目前较可靠,专 ...

  8. 微信、qq二次分享

    前言 我们平时做微信分享的时候,一般分享出来的页面都是一个简单的html页面,不会加入框架之类的东西.所以当我们在分享出来的页面里面再次进行分享的时候,由于我们没有配置分享的标题.描述这些东西,分享出 ...

  9. load data语句实验报告

    1.创建和选择数据库 如果管理员在设置权限时为您创建数据库,则可以开始使用它.否则,您需要自己创建它: 创建数据库不会选择它来使用; 你必须明确地这样做.要创建menagerie当前数据库,请使用以下 ...

  10. thrift之php,python使用TServerSocket并发 处理请求

    要求: 不适用nginx+fastcgi情况下,分布式系统之间如果通讯,如果不阻塞,能并发处理请求 环境: luman/laravel:5.5 php:7.2 thrift -version :Thr ...