字符串
1、string数组的最长公共前缀
https://leetcode-cn.com/problems/longest-common-prefix/comments/
class Solution { public: string longestCommonPrefix(vector<string>& strs) { string res = strs[0]; for(int i=1; i<strs.size(); i++) { for(int j=0; j<res.size();j++) { if(res[j] != strs[i][j]) { res = res.substr(0,j); break; } } } return res; } };
2、求字符串中不含重复字符的最长字串
https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/
class Solution { public: int lengthOfLongestSubstring(string s) { if(s.length()<=1) return s.length(); int res = -1, right = 0; unordered_set<char> store; for(int left=0; left<s.length();left++) { while(right < s.length() && !store.count(s[right])) { store.insert(s[right]); right++; } res = max(res,right - left); store.erase(s[left]); if(right>=s.length()) break; } return res; } };
3、完美子串的个数
参考:https://blog.csdn.net/qq_44745063/article/details/114627854
vector<string> GetPerfectStr(string& s) { int len = s.size();//记录字符串长度 vector<string> res;//用来储存结果 vector<vector<string>> dp(len + 1, vector<string>(len + 1));//实现动归的数组 map<char,int> mp;//用map的去重来统计包含字符 for (auto str : s) { mp[str]++; } string countstr = ""; for (auto c : mp) { countstr+=c.first; }//到此,统计字符结束 //初始化 for (int i = 0; i < len + 1; i++) { for (int j = 0; j <= i; j++) { dp[i][j] = countstr; } } for (int i = 0; i < len + 1; i++) { for (int j = 1; j < len + 1; j++) { int pos = dp[i][j - 1].find(s[i]); if (pos != string::npos) { dp[i][j] = dp[i][j - 1].erase(pos, 1); } else dp[i][j] = dp[i][j - 1]; if (dp[i][j] == "") { res.push_back(s.substr(i, j)); } } } return res; }
4、删除s1中所有S2中的字符
#include<iostream> #include<set> #include<string.h> using namespace std; void re_str_delete(string& a, string& b) { set<char> temp; for (auto s : b) { temp.insert(s); } int i = 0; while (a[i]!= '\0') { while(temp.find(a[i]) != temp.end()) { a.erase(a.begin()+i); } i++; } } int main() { string a = "abcdefghdijabklcmn"; string b = "abcdef"; re_str_delete(a, b); for (int i = 0; i < a.size(); ++i) { cout << a[i]; } cout << endl; system("pause"); return 0; }
5、最长回文子串
动态规划
class Solution { public: int getLongestPalindrome(string A, int n) { // write code here if(n < 2 ) return n; vector<vector<bool>> dp(n,vector<bool>(n)); int maxLen = 0; for(int i=0; i<n; i++) { dp[i][i] = 1; } for(int L=2; L<=n; L++) { for(int i=0; i<n; i++) { int j = L + i - 1; if(j >=n) break; if(A[i] != A[j]) dp[i][j] = false; else{ if(j - i < 3) dp[i][j] =true; else{ dp[i][j] = dp[i+1][j-1]; } } if(dp[i][j] == true && j - i + 1 > maxLen) { maxLen = j - i + 1; } } } return maxLen; } };
6、最长递增子序列
动态规划+二分
上面的动态规划算法需要向前遍历找到前一个k,导致算法复杂度为O(nn),一个牛逼的想法是使用二分查找优化,使复杂度降低为O(nlogn)。
基本点在于维护一个数组maxEnd,其元素maxEnd[k]表示长度为k+1的递增长子序列的最后一个元素,并且是字典序最小的那个。显然maxEnd是一个递增数组。
1 如果arr[i] > maxEnd.back()时,显然直接..., maxEnd.back(), arr[i]依然是一个递增子序列。
2 问题是arr[i] <= maxEnd.back()时怎么处理?
我们找到maxEnd中大于等于arr[i]的元素位置k,将maxEnd[k]替换为arr[i],这表示将长度为k+1的子序列的最后一个元素更新为更小的值。显然更合理。然后再同步更新dp[k]值的为i。
class Solution { public: /** * retrun the longest increasing subsequence * @param arr int整型vector the array * @return int整型vector */ vector<int> LIS(vector<int>& nums) { // write code here if (nums.size() <= 1) return nums; vector<int> dp(nums.size(), 0); vector<int> pos(nums.size(), 0);//pos[i]=j用来记录nums[i]在dp中的第j个位置 int len = 0; dp[len] = nums[0]; for (int i = 1; i < nums.size(); ++i) { if (nums[i] > dp[len]) { dp[++len] = nums[i]; pos[i] = len; } else { int low = 0, high = len; while (low <= high) { int mid = (low + high) >> 1; if (dp[mid] < nums[i]) low = mid + 1; else high = mid - 1; } if (low != -1) { dp[low] = nums[i]; pos[i] = low; } else { dp[0] = nums[i]; pos[i] = 0; } } } vector<int> res(len + 1, INT_MAX); for (int i = nums.size() - 1; i >= 0; i--) { if (pos[i] == len) { res[len] = min(res[len], nums[i]); len--; } } return res; } };