【C++】字符串子串的系列问题

一、解题背景:

  字符串的子串应该是常见的一类有关字符串的算法题目,这里我将leetcode的相关几道题汇总了一下,写了一些具体的思路和多种的求解方法。

二、问题求解:

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
/***********************************************************************/
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

class Solution {
public:
	// 方法1:
    int lengthOfLongestSubstring1(string s) {
	    unordered_map<char,int> mp; // 记录的是索引位置
	    int ans = 0, i = 0;
	    for (int j=0; j<s.size(); j++) {
	    	if (mp.find(s[j])!=mp.end()) {
				i = max(mp[s[j]], i);
			}
			ans = max(ans, j-i+1);
			mp[s[j]] = j+1; // 保存对应字符后边的位置索引,可能作为下一次无重复字符串起点
		}
		return ans;
	}
	// 方法2:
	int lengthOfLongestSubstring1(string s) {
		unordered_map<char,int> mp; // 记录的是字符出现的次数
		int ans = 0;
		for (int i=0, j=0; j<s.size(); j++) {
			mp[s[j]]++;
			while (mp[s[j]]>1) { // 同样这个步骤也是为了找到相同字符的后一个位置
				mp[s[i++]]--;
			}
			ans = max(ans, j-i+1);
		}
		return ans;
	}
};
159. 至多包含两个不同字符的最长子串

给定字符串 s,判断最长的只含有一个或者两个字符的子串的长度。
input_str = “kkkk”
answer = 4
解释:最长子串是 kkkk。
/***********************************************************************/
input_str = “abdyd”
answer = 3
解释:满足条件的最长子串是 dyd。

class Solution {
public:
	bool cmp(const pair<char, int> left,const pair<char, int> right) {
		return left.second<right.second;
	}
    int lengthOfLongest2DisSubstring(string s) {
  		int ans = 1;
  		unordered_map<char, int> mp;
  		for (int j=0, i=0; j<s.size();j++) {
			mp[s[j]] = j;
			
			if(mp.size()==3) {
				auto iter = min_element(mp.begin(), mp.end(), cmp); // 找到最小的value的键值对
				i = iter->second+1;
				mp.erase(iter);
			}
			ans = max(ans, j-i+1);
		}
		return ans;
	}  
};
395. 至少有 K 个重复字符的最长子串

给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
实例1:
输入:s = “aaabb”, k = 3
输出:3
解释:最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。
实例2:
输入:s = “ababbc”, k = 2
输出:5
解释:最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。

class Solution {
public:
	// 这里主要采用了分治的策略,从而使得问题拆分小,这里的核心是将整个字符串中次数未超过k次的作为分隔符来进行计算出现次数至少k次的最长子串。
	int dfs(string &s, int l, int r, int k, int res=0) {
		if (l>r) return 0;
		unordered_map<char,int> mp;
		for (int i=l; i<=r; i++)
			mp[s[i]]++;
		vector<int> pos;
		pos.push_back(l-1);
		for (int i=l; i<=r; i++)
			if (mp[s[i]]<k) pos.push_back(i);
		pos.push_back(r+1);
		if (pos.size()==2) return r-l+1;
		for (int i=0; i<pos.size()-1; i++) {
			res = max(res, dfs(s, pos[i]+1, pos[i+1]-1, k, res));
		}
		return res;
	}
	int longestSubstring(string s, int k) {
	    if (s.size()==0 || s.size()<k) return 0;
	    if (k<=1) return s.size();
	    return dfs(s,0,s.size()-1,k,0);
	}
};

参考的思路:来源leetcode题解

//分治:对于一个字符串来说,如果要求子串最少出现k次,那么如果某些字母出现的次数小于k,
//这些字母一定不会出现在最长的子串中,并且这些字母将整个字符子串分割成小段,这些小段有可能是最长的
//但是由于被分割了,还是要检查这一小段,如果某些字母出现的次数小于k,会将小段继续分割下去,
//比如字符串"aacbbbdc",要求最少出现2次,我们记录左右闭区间,,
//第一轮[0,7],处理"aacbbbdc",d只出现了一次不满足,于是递归解决区间[0,5]、[7,7]
//第二轮[0,5],处理"aacbbb",  c只出现了一次不满足,于是递归解决区间[0,1]、[3,4] 
//第二轮[7,7],处理"c",       c只出现了一次不满足,不继续递归
//第三轮[0,1],处理"aa",      满足出现次数>=2,res=2
//第三轮[3,4],处理"bbb",     满足出现次数>=2 res=3;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郝同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值