【LeetCode】395. 至少有K個重複字符的最長子串

思路

分治思想
先遍歷一遍統計字符串S中每個字母出現的次數,然後再遍歷一遍找到出現次數小於k的一個字母對應的位置(partition),包含S[mid]的子串顯然不可能符合題目要求,所以原問題求S[l,r]字符串對應的答案等價於求S[l,partition-1]和S[partition+1,r];
此外,可以對一些情況進行優化,例如,當l和r所指字符已經不符合題目要求,可以跳過這些字符,以減少計算量。

代碼

未改進代碼

超時

class Solution {
public:
	int k;
	int longestSubstring(string s, int k) {
		this->k = k;
		return cnt(s,0,s.size()-1);
	}
	int cnt(string& s, int l, int r)
	{
		unordered_map<char, int> ch;
		for (int i = l; i <= r; i++)//統計每個字符出現的次數
		{
			ch[s[i]]++;
		}	
		if (r - l + 1 < k) return 0;//此時該子串size小於k,不存在
		//尋找分割位置
		//如果在l和r和範圍內遇到不滿足>=k的,即爲分割位置
		int partition = l;
		while (partition<=r&&ch[s[partition]]>=k)
		{
			partition++;
		}
		if (partition > r) return r - l+1;//分割位置不存在,說明此時的串符合要求
		//存在分割位置,則取其左右子串兩者的最大值
		return max(cnt(s, l, partition - 1), cnt(s, partition + 1, r));
	}
};

改進代碼

class Solution {
public:
	int k;
	int longestSubstring(string s, int k) {
		this->k = k;
		return cnt(s,0,s.size()-1);
	}
	int cnt(string& s, int l, int r)
	{
		unordered_map<char, int> ch;
		for (int i = l; i <= r; i++)//統計每個字符出現的次數
		{
			ch[s[i]]++;
		}	
		//從左到右和從右到左分別跳過字符串中不符合的字符,直到遇到符合的字符位置爲止
		while (l<=r&&ch[s[l]]<k)
		{
			l++;
		}
		while (l<=r&&ch[s[r]]<k)
		{
			r--;
		}
		if (r - l + 1 < k) return 0;//此時該子串size小於k,不存在
		//尋找分割位置
		//如果在l和r和範圍內遇到不滿足>=k的,即爲分割位置
		int partition = l;
		while (partition<=r&&ch[s[partition]]>=k)
		{
			partition++;
		}
		if (partition >= r) return r - l + 1;//分割位置不存在,說明此時的串符合要求
		//存在分割位置,則取其左右子串兩者的最大值
		return max(cnt(s, l, partition - 1), cnt(s, partition + 1, r));
	}
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章