[经典] 最X(长 | 大和 | 大积)Y(子序列 | 子字符串)
Note: 子序列,可以不连续;子字符串,必须连续。
以下题目按在我看看来的难度从易到难排列:
最大和子序列(Maximum sum subsequence)
这道题纯属娱乐...应该不会有人出这种题吧。方案是贪心法,遇到正数就放入序列。
vector<int> msseq(vector<int> &num) {
vector<int> result;
for(int i : num)
if(i > )
result.push_back(i);
return result;
}
最大和子字符串(Maximum sum substring)
暴力方案TC为O(n^2)。更好的方案为,贪心法, 设i从0到n遍历,用gmax代表全局最大和,cursum代表当前子字符串的和。cursum为负,则放弃之前的子字符串;为正则继续向后加,每遇到一个正数,都更新一次gmax。TC = O(n),SC = O(1)。
double msstr(vector<double> &nums) {
double gmax = , cur = ;
for(int i : nums) {
if(cur > )
cur += i;
else
cur = i;
gmax = max(gmax, cur);
}
return gmax;
}
最长递增子字符串(Longest increasing substring)
暴力方案TC为O(n^2)。更好的方案为,与最大和子字符串一样,贪心法,设i从0到n遍历,用gmax代表全局最长长度,len代表当前递增substring的长度。遇到递增,则len++;遇到非递增,则更新gmax,并重置len为1。TC = O(n),SC = O(1)
int listr(vector<double> &nums) {
if(nums.empty())
return ;
int gmax = , cur = ;
for(int i = ; i < nums.size(); i++) {
if(nums[i] > nums[i - ]) {
cur++;
gmax = max(gmax, cur);
}
else
cur = ;
}
return gmax;
}
最大乘积子字符串(Maximum product subsequence)
基本操作与最大乘积子序列差不多,不过是需要连续。用邻点动态规划,
double mpstr(vector<double> &nums) {
double gmax, cmax, cmin, pmax, pmin;
gmax = cmax = cmin = pmax = pmin = ;
for(double i : nums) {
cmax = max(i, max(pmax * i, pmin * i));
cmin = min(i, min(pmax * i, pmin * i));
pmax = cmax;
pmin = cmin;
gmax = max(gmax, cmax);
}
return gmax;
}
最大乘积子序列(Maximum product subsequence)
这题与最大和子序列差不多吧...如果无负数,遇到大于1的数就放入序列;不过需要考虑正负号,用邻点动态规划,
double mpseq(vector<double> &nums) {
double cmax, cmin, pmax, pmin;
cmax = cmin = pmax = pmin = ;
for(double i : nums) {
cmax = max(max(i, pmax), max(pmax * i, pmin * i));
cmin = min(min(i, pmin), min(pmax * i, pmin * i));
pmax = cmax;
pmin = cmin;
}
return pmax;
}
最长递增子序列(Longest increasing subsequence)
暴力方案TC为O(2^n)。如果用贪心法,分析知道根据第i个包含的信息,无法覆盖前i个数的情况,故第i+1个数的决策没法做;更好的方案为,全局动态规划,用opt[i]记录到i为止最长的且包含 i上字符的最长递增subsequence,opt[i]初始为1,动态转移方程为opt[i] = max(opt[j] + 1, opt[i])。
vector<int> miseq(vector<int> &num) {
vector<int> result;
if(num.empty())
return num;
vector<int> opt(num.size(), ), record(num.size(), -);
for(int i = ; i < num.size(); i++) {
for(int j = ; j < i; j++) {
if(num[i] > num[j] && opt[j] + > opt[i]) {
opt[i] = opt[j] + ;
record[i] = j;
}
}
}
int last = -, gmax = ;
for(int i = ; i < num.size(); i++) {
if(opt[i] > gmax) {
gmax = opt[i];
last = i;
}
}
while(last >= ) {
result.push_back(num[last]);
last = record[last];
}
reverse(result.begin(), result.end());
return result;
}
最长匹配子字符串(Longest common substring)
暴力方案TC为O(m*n*max(m,n))。更好的方案为,邻点动态规划,用opt[i][j]记录到M的i - 1位置与N的j - 1位置为止,且包含i - 1,j - 1的最长匹配子字符串。将0位置设为岗哨,其中opt[0][j] = opt[i][0] = 0,动态转移方程为opt[i][j] = M[i] == N[j] ? opt[i - 1][j - 1] + 1 : 0。TC = O(m*n),SC = O(m * n),用滚动数组可以压缩到O(m) or O(n)。
string lcstr(string M, string N) {
//找到最长匹配子字符串的长度
int maxlen = INT_MIN, ri = -;
vector<vector<int> > opt(M.size() + , vector<int>(N.size() + , ));
for(int i = ; i <= M.size(); i++)
for(int j = ; j <= N.size(); j++) {
opt[i][j] = M[i - ] == N[j - ] ? opt[i - ][j - ] + : ;
if(opt[i][j] > maxlen) {
maxlen = opt[i][j];
ri = i;
}
}
//将最大值对应的匹配子字符串输出
string result = "";
int starti = ri - maxlen;
for(int i = starti; i < ri; i++)
result += M[i];
return result;
}
最长匹配子序列(Longest common subsequence)
更好的方案为,与最长匹配子字符串类似,邻点动态规划,用opt[i][j]记录到M的i - 1位置与N的j - 1位置为止,且包含i - 1,j - 1的最长匹配子字符串。将0位置设为岗哨,其中opt[0][j] = opt[i][0] = 0,动态转移方程为opt[i][j] = M[i] == N[j] ? opt[i - 1][j - 1] + 1 : max(opt[i - 1][j], opt[i][j - 1])。TC = O(m*n),SC = O(m*n),滚动数组同样可以压缩到O(m) or O(n)。
//只是找长度很简单...
int lenlcstr(string M, string N) {
//找到最长匹配子字符串的长度
vector<vector<int> > opt(M.size() + , vector<int>(N.size() + , ));
for(int i = ; i <= M.size(); i++)
for(int j = ; j <= N.size(); j++)
opt[i][j] = M[i - ] == N[j - ] ? opt[i - ][j - ] + : max(opt[i - ][j], opt[i][j - ]);
return opt[M.size()][N.size()];
}
//还要返回一个最长匹配字符串
string lcstr(string M, string N) {
//记录路径
vector<vector<int> > track(M.size() + , vector<int>(N.size() + , -));
//找到最长匹配子字符串的长度
vector<vector<int> > opt(M.size() + , vector<int>(N.size() + , ));
for(int i = ; i <= M.size(); i++)
for(int j = ; j <= N.size(); j++) {
if(M[i - ] == N[j - ]) {
opt[i][j] = opt[i - ][j - ] + ;
track[i][j] = ;
}
else {
if(opt[i - ][j] > opt[i][j - ]) {
track[i][j] = ;
opt[i][j] = opt[i - ][j];
}
else {
track[i][j] = ;
opt[i][j] = opt[i][j - ];
}
}
}
int i = int(M.size()), j = int(N.size());
string result = "";
while(track[i][j] > -) {
if(track[i][j] == ) {
result += M[i - ];
i--;
j--;
}
else if(track[i][j] == )
i--;
else
j--;
}
reverse(result.begin(), result.end());
return result;
}
编辑距离(Edit distance)
更好的方案,与LCS类似,邻点动态规划
int edist(string s1, string s2) {
int m = int(s1.length()), n = int(s2.length());
vector<vector<int> > opt(m + , vector<int> (n + , ));
for(int i = ; i <= m; i++)
opt[i][] = i;
for(int j = ; j <= n; j++)
opt[][j] = j;
for(int i = ; i <= m; i++)
for(int j = ; j <= n; j++) {
opt[i][j] = min(min(opt[i - ][j], opt[i][j - ]), opt[i - ][j - ]) + ;
if(s1[i - ] == s2[j - ])
opt[i][j] = min(opt[i][j], opt[i - ][j - ]);
}
return opt[m][n];
}
最长无重复子字符串(Longest substring with no duplicate characters)
用一个unordered_set<char>里存已有的char,遇到加入一个新的char,则在set里找,如果没找到,则加入set,并且count++;如果找到了,则在substring的循环弹出,更新set,并循环count--,直到弹出新加入的char的重复字符。
[经典] 最X(长 | 大和 | 大积)Y(子序列 | 子字符串)的更多相关文章
- 《剑指offer》第四十八题(最长不含重复字符的子字符串)
// 面试题48:最长不含重复字符的子字符串 // 题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子 // 字符串的长度.假设字符串中只包含从'a'到'z'的字符. #inclu ...
- 剑指offer-面试题48-最长不含重复字符的子字符串-动态规划
/* 题目: 最长不含重复字符的子字符串. */ /* 思路: f(i) = f(i-1) + 1,(未出现过当前字符,distance > f(i-1) distance,当前字符和上一次出现 ...
- 剑指 Offer 48. 最长不含重复字符的子字符串 + 动态规划 + 哈希表 + 双指针 + 滑动窗口
剑指 Offer 48. 最长不含重复字符的子字符串 Offer_48 题目详情 解法分析 解法一:动态规划+哈希表 package com.walegarrett.offer; /** * @Aut ...
- 剑指offer面试题48: 最长不含重复字符的子字符串
Given a string, find the length of the longest substring without repeating characters.(请从子字符串中找出一个最长 ...
- 【Java】 剑指offer(48) 最长不含重复字符的子字符串
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字 ...
- 【Offer】[48] 【最长不含重复字符的子字符串】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度.假设字符串中只包含'a'~'z'的字符.例如,在字符串&q ...
- 剑指offer——50最长不含重复字符和子字符串
题目: 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度.假设字符串中只包含’a~z”的字符.例如,在字符串“arabcacfr"中,最长的不含重复字符的子字符串 ...
- 每日一题 - 剑指 Offer 48. 最长不含重复字符的子字符串
题目信息 时间: 2019-07-02 题目链接:Leetcode tag: 动态规划 哈希表 难易程度:中等 题目描述: 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度 ...
- 剑指 Offer 48. 最长不含重复字符的子字符串
题目描述 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度. 示例1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 & ...
随机推荐
- 关于封装的一个小问题和TA的例子
写个小例子吧 -- 很多细节(如校验.判断等等)都略了 其实不是有意写成这样,而是很多朋友都这么写(当然里面也有点夸张的写法) 这么写其实也没什么不好,简单明了,不用动脑子,一看就很直白, 但是如果 ...
- 让ie6/7/8兼容css3的圆角阴影等特殊效果的方法 PIE1.0.0及placeholder在这些IE下生效的方法
PIE地址:http://css3pie.com/ 使用方法1: #login,#AnnouncementBox { border:3px solid #fff; -webkit-border-r ...
- [中级] 有效删除URL中的index.php
如果你刚接触CI不久又或者刚刚研读CI的使用手册的话,关于如何有效删除URL中index.php以使URL看起来更友好美观的问题,可能是你面对的第一个较为复杂的问题!本贴不是原创,而是一个各种意见的综 ...
- Node.js的长连接
之前写的js服务器脚本,在服务器上运行的挺好的.也经过了压力测试,单次接受4000次的连接不成问题.在5s里,可以应答1W多次的连接.对于这个连接次数,我们还是挺满意的,但是Boss说:客户端每2分钟 ...
- laravel4通过控制视图模板路劲来动态切换主题
通过控制视图模板路劲来动态切换主题 App::before(function($request) { $paths = Terminal::isMobile() ? array(__dir__.'/v ...
- window下配置SSH连接GitHub、GitHub配置ssh key(转)
转自:http://jingyan.baidu.com/article/a65957f4e91ccf24e77f9b11.html 此经验分两部分: 第一部分介绍:在windows下通过msysGit ...
- mysql 语句资料总结
一.UNION命令 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SE ...
- 如何让input之间无空隙
有如下两个input: <form action="http://www.example.com/index/search" method="get"&g ...
- html5 DeviceOrientation来实现手机网站上的摇一摇功能
原文地址:http://www.cootm.com/?p=706 从网上转载看到的,感觉不错,就转过来了,特此感谢 cnblogs 的 幸福2胖纸的码农生活,直接转载了,不要介意!呵呵 以下是转载内容 ...
- C语言结构体(struct)使用方法
基本定义:结构体,通俗讲就像是打包封装,把一些变量有共同特征(比如同属于某一类事物的属性)的变量封装在内部,通过一定方法访问修改内部变量. 结构体定义: 第一种:只有结构体定义 struct stuf ...