3. 最长无重复字符的子串(滑动窗口)
1、使用滑动窗口法,首先尾指针加1,表示加入一个元素,然后更新最长子串长度。
2、判断增加元素后原窗口是否有重复元素,找到第一个重复元素,更改首指针到该元素后。
int lengthOfLongestSubstring(string s) {
int start = 0, end = 0, length = 0, num = 0;
while (end < s.size()){
end++;length++;
num = max(num, length);
for(int n=start;n<end;n++)
if (s[n] == s[end]){
start = n + 1;
length = end - start;
break;
}
}
return num;
}
5. 最长回文子串(双重遍历+二维动规)
1、二维dp数组保存该区间是否是回文子串
2、长度l从0开始,长度为1,则dp为1,长度为2,判断i,j是否相等;长度大于2,判断是否相等且i+1,j-1是否为1
3、用string实时记录最长子串,并实时更新
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
string sub;
//用vector,定义二维数组,存动态规划状态量,小括号内为初始化
vector<vector<int>> dp(n, vector<int>(n));
for (int l = 0; l < n; l++) {
//注意加上边界判断!官方代码运行会报错
for (int i = 0; i+l < n; i++) {
int j = i + l;
if (l == 0)
dp[i][i] = 1;
else if (l == 1 && s[i] == s[j])
dp[i][j] = 1;
//动规判断比i,j小的,向较短方向转移,而非较长转移,注意顺序
else if (dp[i+1][j-1]==1 && s[i] == s[j])
dp[i][j] = 1;
//大于当前最大子串长度
if (dp[i][j] == 1 && l + 1 > sub.size())
//注意substr第二项,并非序号,应为从i往后第l+1个
sub = s.substr(i, l+1);
}
}
return sub;
}
};
76. 最小覆盖子串(滑动窗口)
1、用滑动窗口控制一个字符串范围,如果不能覆盖,一直移动右窗口,如果可以覆盖,往右收缩左窗口
2、用map记录当前子串是否可以覆盖,由于给定字符串可能重复,所以要记录个数
class Solution {
public:
unordered_map <char, int> ori, cnt;
bool check() {
for (const auto &p: ori)
if (cnt[p.first] < p.second)
return false;
return true;
}
string minWindow(string s, string t) {
for (const auto &c: t)
++ori[c];
int l = 0, r = -1,len = INT_MAX, ansL = -1, ansR = -1;
while (r < int(s.size())) {
if (ori.find(s[++r]) != ori.end())
++cnt[s[r]];
while (check() && l <= r) {
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
}
if (ori.find(s[l]) != ori.end())
--cnt[s[l]];
++l;
}
}
return ansL == -1 ? string() : s.substr(ansL, len);
}
};
718. 最长重复子数组(双重遍历+二维动规)、NC127 最长公共子串
1、与最长公共子序列不同,子串要求必须连续,如果不相等dp等于0
2、用二维数组dp记录当前两个数组下标的已有最长子串,从头开始遍历
3、如果相等,则等于之前子串加1,dp[i+1][j+1]=dp[i][j]+1;如果不等,则dp[i+1][j+1]=0
int findLength(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size(),m=nums2.size(),max=0;
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(nums1[i]==nums2[j])
dp[i+1][j+1]=dp[i][j]+1;
else
dp[i+1][j+1]=0;
if(dp[i+1][j+1]>max)
max=dp[i+1][j+1];
}
return max;
}
14. 最长公共前缀(排序+比较)
1、正常方法是所有字符从第一个字符开始从前往后挨个判断
2、取巧方法对字符串数组排序,直接比较第一个和最后一个即可,因为第一个和最后一个一定相差最大
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty()) return string();
sort(strs.begin(), strs.end());
string st = strs.front(), en = strs.back();
int i, num = min(st.size(), en.size());
for(i = 0; i < num && st[i] == en[i]; i ++);
return string(st, 0, i);
}
53. 最大子序和(一次遍历+一维动规)
1、动态规划,用数组num当dp数组,nums[i]表示以i结尾最大子序和
2、如果num[i-1]大于0,则加上,小于0,不加,用ans记录dp中当前最大值
int maxSubArray(vector<int>& nums) {
int ans=nums[0];
for(long i=1;i<nums.size();i++){
if(nums[i-1]>0)
nums[i]+=nums[i-1];
ans=max(ans,nums[i]);
}
return ans;
}
128. 最长连续序列(哈希表)
1、这个连续不是指在原数组中连续,而是指数字大小连续,所以可以使用哈希表来去重和顺序查找
2、为了减少复杂度,查找前先判断n-1存不存在,不存在说明该点是一个序列的起点,可以查找
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> num_set;
for (const int& num : nums)
num_set.insert(num);
int longestStreak = 0;
for (const int& num : num_set) {
if (!num_set.count(num - 1)) {
int currentNum = num;
int currentStreak = 1;
while (num_set.count(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}
longestStreak = max(longestStreak, currentStreak);
}
}
return longestStreak;
}
};
300. 最长递增子序列(两层遍历+一维动规)
1、由于是子序列问题,不是子数组,所以可以分开,所以不能连续一遍动规,必须两层动规扫描
2、在每个点的时候都从头再扫一遍,到这个的最长子序列,保存最大值
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = (int)nums.size();
if (n == 0)
return 0;
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i])
dp[i] = max(dp[i], dp[j] + 1);
}
}
return *max_element(dp.begin(), dp.end());
}
};
674. 最长连续递增序列(贪心)
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int ans = 0;
int n = nums.size();
int start = 0;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] <= nums[i - 1]) {
start = i;
}
ans = max(ans, i - start + 1);
}
return ans;
}
};
1143. 最长公共子序列(一次遍历+二维动规)
1、与最长公共子串不同,子序列不要求连续,如果不相等则dp等于之前较大的一个
2、用二维数组dp记录当前两个数组下标的已有最长子序列,从头开始遍历
3、如果相等,则等于之前子串加1,dp[i+1][j+1]=dp[i][j]+1;如果不等,则dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1])
int longestCommonSubsequence(string text1, string text2) {
int m=text1.size(),n=text2.size(),ans=0;
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(text1[i]==text2[j])
dp[i+1][j+1]=dp[i][j]+1;
else
dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1]);
ans=max(ans,dp[i+1][j+1]);
}
return ans;
}