classSolution { public: stringshortestPalindrome(conststring &s){ if (s.empty()) return s; stringr(rbegin(s), rend(s)); long M = INT_MAX, B = 256; int n = size(s); vector<long> p(n, 1); for (int i = 1; i < n; ++i) { p[i] = (p[i - 1] * B) % M; } long sh = 0, rh = 0; for (int i = 0; i < n; ++i) { sh = (sh * B + s[i]) % M; rh = (rh * B + r[i]) % M; } if (sh == rh && s.compare(0, n, r, 0, n) == 0) return s; for (int i = 1; i < n; ++i) { sh = (sh + M - s[n - i] * p[i - 1] % M) % M; rh = (rh + M - r[i - 1] * p[n - i] % M) % M; if (sh == rh * p[i] % M && s.compare(0, n - i, r, i, n - i) == 0) return r.substr(0, i) + s; } return s; } };
classSolution { public: stringshortestPalindrome(conststring &s){ if (s.empty()) return s; stringr(rbegin(s), rend(s)); long M = INT_MAX, B = 256; int n = size(s); vector<long> p(n, 1); for (int i = 1; i < n; ++i) { p[i] = (p[i - 1] * B) % M; } long sh = 0, rh = 0; for (int i = 0; i < n; ++i) { sh = (sh + s[i] * p[i]) % M; rh = (rh + r[i] * p[i]) % M; } if (sh == rh && s.compare(0, n, r, 0, n) == 0) return s; for (int i = 1; i < n; ++i) { sh = (sh + M - s[n - i] * p[n - i] % M) % M; rh = (rh + M - r[i - 1] * p[i - 1] % M) % M; if ((sh * p[i]) % M == rh && s.compare(0, n - i, r, i, n - i) == 0) return r.substr(0, i) + s; } return s; } };
classSolution { public: stringshortestPalindrome(conststring &s){ if (s.empty()) return s; stringr(rbegin(s), rend(s)); long M = INT_MAX, B = 256; int n = size(s); vector<long> p(n, 1), sh(n), rh(n); for (int i = 1; i < n; ++i) { p[i] = (p[i - 1] * B) % M; } sh[0] = s[0]; rh[0] = r[0]; for (int i = 1; i < n; ++i) { sh[i] = (sh[i - 1] + s[i] * p[i]) % M; rh[i] = (rh[i - 1] + r[i] * p[i]) % M; } if (sh[n - 1] == rh[n - 1] && s.compare(0, n, r, 0, n) == 0) return s; for (int i = 1; i < n; ++i) { auto a = (sh[n - i - 1] * p[i]) % M; auto b = (rh[n - 1] + M - rh[i - 1]) % M; if (a == b && s.compare(0, n - i, r, i, n - i) == 0) return r.substr(0, i) + s; } return s; } };
O(n2)递归版 KMP可以实现O(n) 我们使用双指针来找出字符串s的最长回文前缀的大概范围,指针i和j分别指向s串的开头和末尾,若 s[i] 和 s[j] 相等,则i自增1,j自减1,否则只有j自减1。这样遍历一遍后,最长回文前缀就在范围 [0, i) 中,但不保证这个本身就是最大回文前缀,我们只能确定后面剩余的部分肯定不属于,此时我们提取出剩下的字符,翻转一下加到最前面,而对范围 [0, i) 内的子串再次递归调用本函数,这样,在子函数最终会组成最短的回文串,从而使得整个的回文串就是最短的 Each iteration of shortestPalindrome is linear in size of substring and the maximum number of recursive calls can be n/2 times as shown in the Intuition section. Let the time complexity of the algorithm be T(n). Since, at the each step for the worst case, the string can be divide into 2 parts and we require only one part for further computation. Hence, the time complexity for the worst case can be represented as : T(n)=T(n-2)+O(n)T(n)=T(n−2)+O(n). So, T(n) = O(n) + O(n-2) + O(n-4) + … + O(1)T(n)=O(n)+O(n−2)+O(n−4)+…+O(1) which is O(n2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { public: stringshortestPalindrome(string s){ int n = s.length(); int i = 0; for (int j = n - 1; j >= 0;--j) { if (s[i] == s[j]) { ++i; } } if (i == n) return s; string prefix = s.substr(i); reverse(prefix.begin(), prefix.end()); string mid = shortestPalindrome(s.substr(0, i)); return prefix + mid + s.substr(i); } };
iterative O(n2) time
1 2 3 4 5 6 7 8 9 10 11
classSolution { public: stringshortestPalindrome(conststring &s){ int n = size(s); stringr(rbegin(s), rend(s)); for (int i = 0; i < n; ++i) { if (s.compare(0, n - i, r, i, n - i) == 0) return r.substr(0, i) + s; // 避免copy } return s; } };
TLE O(n2) time
1 2 3 4 5 6 7 8 9 10 11
classSolution { public: stringshortestPalindrome(conststring &s){ int n = size(s); stringr(rbegin(s), rend(s)); for (int i = 0; i < n; ++i) { if (s.substr(0, n - i) == r.substr(i)) return r.substr(0, i) + s; } return s; } };
错误dp版本O(n2) time O(n2) space 题目要求只能在前面加,这个版本是可以在任何位置加
Posted onEdited onInLeetCodeDisqus: Symbols count in article: 599Reading time ≈1 mins.
O(logn) time O(1) space
1 2 3 4 5 6 7 8 9 10 11 12
classSolution { public: intfindSpecialInteger(vector<int>& arr){ int n = size(arr); for (auto p : {.25, .5, .75}) { // 分别测试每个quartile位置的数,超过25%的数一定能被capture int i = n * p; auto [b, e] = equal_range(begin(arr), end(arr), arr[i]); if (e - b > n / 4) return arr[i]; } return-1; } };
O(n) time O(1) space
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { public: intfindSpecialInteger(vector<int>& arr){ int n = arr.size(), mx = n * .25; for (int i = 0; i < n;) { int j = i; while (arr[j] == arr[i]) { if (++j - i > mx) return arr[i]; // 一旦找到则提前返回 } i = j; } return-1; } };
boolisValid(conststring &s, bool isv4){ if (isv4) { if (s.empty() || s.length() > 3) returnfalse; // 判断长度 int x = 0; for (char c : s) { if (!isdigit(c)) returnfalse; // 判断是否有非法字符比如abcd x = x * 10 + c - '0'; } return (s == "0") || (0 < x && x < 256 && s[0] != '0'); // 不能出现leading zeros } else { if (s.empty() || s.length() > 4) returnfalse; for (char c : s) { c = tolower(c); if (!('0' <= c && c <= '9') && !('a' <= c && c <= 'f')) returnfalse; } returntrue; } } };
Posted onEdited onInLeetCodeDisqus: Symbols count in article: 670Reading time ≈1 mins.
hashmap O(n) 这个方法比简单统计字母频要快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution { public: intfirstUniqChar(string s){ int f[26] = {0}; for (constauto &c : s) { ++f[c - 'a']; } int n = s.length(); for (int i = 0; i < n; ++i) { if (f[s[i] - 'a'] == 1) { return i; } } return-1; } };
把重复的字母的下标全部记成n,不重复的则记成i,然后遍历找出最小的i
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { public: intfirstUniqChar(string s){ vector<int> m(26, INT_MAX); int n = s.length(); for (int i = 0; i < n; ++i) { int k = s[i] - 'a'; if (m[k] == INT_MAX) { m[k] = i; } elseif (m[k] < n) { m[k] = n; } } int res = *min_element(m.begin(), m.end()); return res < n ? res : -1; } };
classSolution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k){ deque<int> q; vector<int> res; int n = nums.size(); for (int i = 0; i < n; ++i) { while (!q.empty() && nums[q.back()] < nums[i]) { q.pop_back(); } q.push_back(i); if (i - q.front() >= k) { q.pop_front(); } if (i >= k - 1) { res.push_back(nums[q.front()]); } } return res; } };