这道题目可使用不少种解法,包括是动态规划等等。html
s为匹配字符串,t为给定字符串假设dp[i][j]表示t从开始到第i个字符时对应s从开头到第j个字符,s所否是t的子序列。python
分析:在比较的过程当中,若是t[i]不等于s[j],则忽略掉当前的字符,取以前i-1匹配的状况,若是是相等,则取决于双方上一位的匹配的状况,这里注意的是,若是匹配字符串为空,那么结果为True。web
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if not s and not t:
return True
elif not s and t:
return True
elif not t and s:
return False
m, n = len(t), len(s)
dp = [[False for i in range(n + 1)] for j in range(m + 1)]
dp[0][0] = True
for i in range(1, m + 1):
dp[i][0] = True
for i in range(1, n + 1):
dp[0][i] = False
for i in range(1, m + 1):
for j in range(1, n + 1):
if t[i-1] == s[j-1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = dp[i - 1][j]
return dp[m][n]
但由于空间的复杂度过大致使了TLE,因此须要再进一步的进行优化,由于咱们只使用到了上一行的状态,所以咱们能够只使用两行,而后使用完的时候进行交换便可。数组
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if not s and not t:
return True
elif not s and t:
return True
elif not t and s:
return False
m, n = len(t), len(s)
dp = [[False for j in range(m + 1)] for i in range(2)]
for i in range(m + 1):
dp[0][i] = True
for i in xrange(1, n+1):
for j in xrange(1, m+1):
if s[i-1] == t[j-1]:
dp[1][j] = dp[0][j-1]
else:
dp[1][j] = dp[1][j-1]
dp[0] = dp[1][:]
return dp[1][m]
可是,依旧是TLE,咱们继续在它的基础之上进行优化,由于只有在不相等的状况的时候才会使用到上一行的状态,并且只用到了它的值,所以,咱们使用一个变量来进行维护。app
不会
一开始我看到这个方法的时候,竟然傻傻的去对字符串进行搜索😳。函数
思路:纪录给定字符串每一个字符对应的位置,维护前一个字符的位置,而后遍历匹配字符串去找到比前一个字符位置要大的位置,可是又不能超出数组长度,由于这样显然是由于前一个字符在不存在。优化
import collections
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
def binary_search(nums, x):
low, high = 0, len(nums)
while low < high:
mid = (low + high) // 2
if nums[mid] < x:
low = mid + 1
else:
high = mid
return high
if not s and not t:
return True
elif not s and t:
return True
elif not t and s:
return False
pre_idx = 0
idxs = collections.defaultdict(list)
for i,n in enumerate(t):
idxs[n].append(i)
for i in range(len(s)):
idx = binary_search(idxs[s[i]], pre_idx)
if idx != len(idxs[s[i]]):
pre_idx = idxs[s[i]][idx] + 1
else:
return False
return True
其实上面的作法也是贪心的思想,只要后者比前者大就更新,那这里就直接使用内建函数index
。ui
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if not s and not t:
return True
elif not s and t:
return True
elif not t and s:
return False
pre_idx = -1
for i in range(len(s)):
idx = t.find(s[i], pre_idx+1)
if idx != -1:
pre_idx = idx
else:
return False
return True
移动窗口本质也是贪心的思想,以前的动态规划时间复杂度为O(n^2),二分搜索优化到了O(nlogn),滑动窗口则直接优化到了O(n)。spa
思路:每当匹配字符串中的字符和给定字符串中的字符相等时,则移动匹配下标,其他均移动给定字符串下标,查看最后移动下标是否到达最后。code
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if not s and not t:
return True
elif not s and t:
return True
elif not t and s:
return False
m, n = len(s), len(t)
si, ti = 0, 0
while si < m and ti < n:
if s[si] == t[ti]:
si += 1
ti += 1
return si == m