前言

这道题的实现方法有很多,包括dp,贪心算法,二分搜索,普通实现等等。

题目

Given a string s and a string t, check if s is subsequence of t.

You may assume that there is only lower case English letters in both s and t. t is potentially a very long (length ~= 500,000) string, and s is a short string (<=100).

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:

s = "abc", t = "ahbgdc"

Return true.

Example 2:

s = "axc", t = "ahbgdc"

Return false.

Follow up:

If there are lots of incoming S, say S1, S2, ... , Sk where k >= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?

题意说的是,判断字符串s是否是字符串t的字串(要求按照s中字符的顺序!)

实现

//
// Is Subsequence.cpp
// LeetCodeCppPro
//
// Created by George on 17/3/2.
// Copyright © 2017年 George. All rights reserved.
// #include <stdio.h>
#include "PreLoad.h" class Solution {
public:
/**
* 两个节点,贪心算法的思想
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence(string s, string t) {
if (s == t || (s == "" && t.length() > s.length())) {
return true;
}
else if (s.length() > t.length()) {
return false;
}
int idx = 0;
for (int i = 0; i < s.length(); i++,idx++) {
while (idx < t.length() && t[idx] != s[i]) {
idx++;
} if (idx >= t.length()) {
return false;
}
} return true;
} /**
* two point
* 失败,没调试好
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence2(string s, string t) {
if (s == t || (s == "" && t.length() > s.length())) {
return true;
}
else if (s.length() > t.length() || (s.length() == t.length() && s != t)) {
return false;
} int s_left = 0, s_right = s.length()-1;
int t_left = 0, t_right = t.length()-1; while (t_left < t_right) {
while (s[s_left] != t[t_left] && t_left < t_right) {
t_left++;
}
while (s[s_right] != t[t_right] && t_left < t_right) {
t_right--;
} if (t_left == t_right) {
if (s[s_left] == t[t_left]) {
return true;
}
else {
return false;
}
} if (s[s_left] == t[t_left]) {
s_left++;
t_left++;
}
else {
t_left++;
} if (s[s_right] == t[s_right]) {
s_right--;
t_right--;
}
else {
t_right--;
} if (t_left == t_right) {
if (s[s_left] == t[t_left]) {
return true;
}
else {
return false;
}
}
} if (t_left >= t_right) {
return false;
}
else {
return true;
}
} /**
* 使用hash,取idx递增顺序
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence3(string s, string t) {
vector<vector<int>> sequence(26); // 纪录下每个单词出现的下标
for (int i = 0; i < t.length(); i++) {
int idx = t[i] - 'a';
sequence[idx].push_back(i);
} // 根据s的单词顺序
int preIndex = -1;
for (int i = 0; i < s.length(); i++) {
int idx = s[i] - 'a';
auto nums = sequence[idx]; //取得字符的下标集合
if (nums.empty()) {
return false;
} auto itr2 = nums.begin();
while (itr2 != nums.end() && *itr2 <= preIndex) {
itr2++;
} if (itr2 == nums.end()) {
return false;
}
else {
preIndex = *itr2;
}
} return true;
} /**
* 和上面的思想类似,
* 不同的是使用了一个数组index记录下同一个单词的次数,读取更加方便
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence4(string s, string t) {
vector<vector<int>> posMap(26); // 题目已经假设是小写字母 // 纪录目标字符串t中字符的出现次数
for (int i = 0; i < t.length(); i++) {
posMap[t[i] - 'a'].push_back(i);
} int pre = -1;
int index[26]; //纪录s中每个单词出现的个数,为后面取该字符的下标做准备,避免从头开始遍历
memset(index, -1, sizeof(index));
for (int i = 0; i < s.length(); i++) {
int j = s[i] - 'a';
index[j]++; // posMap[j][index[j]] 为取某个字符的下标
while (index[j] < posMap[j].size()) {
if (posMap[j][index[j]] > pre) { //直到取得比上一个字符的下标大的下标值
break;
}
++index[j];
} if (index[j] > posMap[j].size()) {
return false;
} pre = posMap[j][index[j]]; //更新为当前字符的下标
} return true;
} /**
* 思路和前面的一样,都使用了之前的下标
* 不同的是做法更佳简洁,因为使用了upper_bound函数
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence5(string s, string t) {
vector<vector<int>> record(26); for (int i = 0; i < t.size(); i++) {
record[t[i] - 'a'].push_back(i);
} int index = -1;
for (int i = 0; i < s.size(); i++) {
int idx = s[i] - 'a';
auto itr = upper_bound(record[idx].begin(), record[idx].end(), index);
if (itr == record[idx].end()) {
return false;
}
index = *itr;
} return true;
} /**
* 和第一种思想类似
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence6(string s, string t) {
if (s.length() == 0) {
return true;
}
queue<int> queue; //使用队列可以保证字符的处理顺序是正确的
for (char c : s) queue.push(c);
for (int i = 0; !queue.empty() && i < t.length(); i++) {
if (t[i] == queue.front()) {
queue.pop();
}
}
return queue.empty();
} /**
* dp实现
* 不同点在于,只使用了两行数据,节省空间
* 使用了之后到的数据覆盖之前的数据
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence7(string s, string t) {
if (s.length() == 0) {
return true;
}
else if (t.length() != 0) {
return false;
} int m = t.length(), n = s.length();
vector<vector<bool>> dp(2, vector<bool>(n+1, false)); // 设置第一行,因为只需要看s的数据
for (int i = 0; i <= n; i++) {
dp[0][i] = true;
} for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (t[i] == s[j]) {
dp[1][j+1] = dp[0][j];
}
else {
dp[1][j+1] = dp[1][j];
}
} // 进行覆盖,将第1行数据覆盖到第0层数据上,循环使用
for (int j = 0; j < n; j++) {
dp[0][j] = dp[1][j];
}
} return dp[1][n];
} /**
* 正儿八经的使用dp
*
* @param s <#s description#>
* @param t <#t description#>
*
* @return <#return value description#>
*/
bool isSubsequence8(string s, string t) {
if (s.length() == 0) {
return true;
}
else if (t.length() != 0) {
return false;
} int m = t.length(), n = s.length();
vector<vector<bool>> dp(m, vector<bool>(n, false)); if (s[0] == t[0]) {
dp[0][0] = true;
} // 将第一列的数据置为false,因为不需要
for (int i = 1; i < m; i++) {
dp[i][0] = false;
} // 第一行数据
for (int i = 1; i < n; i++) {
dp[0][i] = dp[0][i-1] || s[i] == t[0];
} for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (t[i] == s[j]) {
dp[i][j] = dp[i-1][j-1] || dp[i][j-1];
// 将该行上的数据都置为true
if (dp[i][j]) {
for (int k = j+1; k < n; k++) {
dp[i][k] = true;
}
continue;
}
}
}
} return dp[m-1][n-1];
} void test() {
string s = "aaaabc", t = "llallllbllllc"; if (isSubsequence3(s, t)) {
cout << "true" << endl;
}
else {
cout << "false" << endl;
}
}
};

[LeetCode] Is Subsequence 题解的更多相关文章

  1. [LeetCode] Is Subsequence 是子序列

    Given a string s and a string t, check if s is subsequence of t. You may assume that there is only l ...

  2. [LeetCode] Wiggle Subsequence 摆动子序列

    A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...

  3. 「LeetCode」全部题解

    花了将近 20 多天的业余时间,把 LeetCode 上面的题目做完了,毕竟还是针对面试的题目,代码量都不是特别大,难度和 OJ 上面也差了一大截. 关于二叉树和链表方面考察变成基本功的题目特别多,其 ...

  4. LeetCode "Wiggle Subsequence" !

    Another interesting DP. Lesson learnt: how you define state is crucial.. 1. if DP[i] is defined as, ...

  5. C#版 - Leetcode 65. 有效数字 - 题解

    版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. Leetcod ...

  6. Hdoj 1159.Common Subsequence 题解

    Problem Description A subsequence of a given sequence is the given sequence with some elements (poss ...

  7. [LeetCode] Three Sum题解

    Three Sum: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? ...

  8. LeetCode——Is Subsequence

    Question Given a string s and a string t, check if s is subsequence of t. You may assume that there ...

  9. Leetcode的SQL题解:185. 部门工资前三高的员工

    题目 查询部门工资前三高的员工. 我用的数据库是oracle. 下面是数据表的信息. Employee表数据: | ID | NAME | Salary | DepartmentId | | -- | ...

随机推荐

  1. PHP的一些 有用但不常用的函数记录

    1. microtime() 当前 Unix 时间戳以及微秒数. <?php $mem = new Memcache; $mem->connect("127.0.0.1" ...

  2. C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二)

    本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (一) 上个帖子主要是讲了如何读取Excel,本帖主要是讲述读取的Excel数据是如何序列化成二进制的,考虑到现在在手游中 ...

  3. HDU-1166-敌兵布阵(线段树)

    前言: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点.       对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a, ...

  4. Beanstalkd使用

    Beanstalkd,一个高性能.轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Facebook ...

  5. 如何在NodeJS项目中优雅的使用ES6

    如何在NodeJS项目中优雅的使用ES6 NodeJs最近的版本都开始支持ES6(ES2015)的新特性了,设置已经支持了async/await这样的更高级的特性.只是在使用的时候需要在node后面加 ...

  6. 从RPC开始(二)、序列化

    在C++的世界里构建一个序列化框架:并非一件困难的事情,但也并非简单.因此,需要分成两部分来完成这项任务: 1.序列化容器. 2.序列化方式. 前者,很容易理解:但也决定着我们将要存储数据的方式:二进 ...

  7. 进阶之初探nodeJS

    一.前言 在"初探nodeJS"随笔中,我们对于node有了一个大致地了解,并在最后也通过一个示例,了解了如何快速地开启一个简单的服务器. 今儿,再次看了该篇随笔,发现该随笔理论知 ...

  8. Wireshark网络抓包(二)——过滤器

    一.捕获过滤器 选中捕获选项后,就会弹出下面这个框,在红色输入框中就可以编写过滤规则. 1)捕获单个IP地址 2)捕获IP地址范围 3)捕获广播或多播地址 4)捕获MAC地址 5)捕获所有端口号 6) ...

  9. iOS核心笔记—源代码管理工具-SVN

    源代码管理工具-SVN 一. 源代码管理工具概述 1. 源代码管理工具的作用? > 能追踪一个项目从诞生一直到定案的过程 > 记录一个项目的所有内容变化,无限制返回 > 查看特定版本 ...

  10. 微端游戏启动器launcher的制作(序篇)

    公司要做一个游戏接入腾讯QQ游戏大厅,腾讯要求制作一个launcher,公司之前并没有接入过腾讯,所以大家其实都不懂,而我又是新人,所以刚拿到这个任务的时候整个人就是一个大写的懵逼.在网上查找了不少的 ...