【LeetCode】字符串 string(共112题)
【3】Longest Substring Without Repeating Characters (2019年1月22日,复习)
【5】Longest Palindromic Substring (2019年1月22日,复习)
【6】ZigZag Conversion (2019年1月22日,复习)
【8】String to Integer (atoi) (2019年1月22日,复习)
【10】Regular Expression Matching (2019年1月22日,复习)
【12】Integer to Roman (2019年1月22日,复习)
【13】Roman to Integer (2019年1月22日,复习)
罗马数字转换成整数。
题解:用一个map来存储映射关系。
1 class Solution { 2 public: 3 int romanToInt(string s) { 4 const int n = s.size(); 5 initMap(); 6 int idx = 0; 7 int ret = 0; 8 while (idx < n) { 9 if (idx + 1 == n) { 10 string temp = string(1, s[idx]); 11 ret += mp[temp]; 12 idx++; 13 continue; 14 } 15 string str = s.substr(idx, 2); 16 if (mp.find(str) != mp.end()) { 17 ret += mp[str]; 18 idx += 2; 19 } else { 20 string temp = string(1, s[idx]); 21 ret += mp[temp]; 22 idx++; 23 } 24 } 25 return ret; 26 } 27 unordered_map<string, int> mp; 28 void initMap() { 29 mp["IV"] = 4, mp["IX"] = 9; 30 mp["XL"] = 40, mp["XC"] = 90; 31 mp["CD"] = 400, mp["CM"] = 900; 32 mp["I"] = 1, mp["V"] = 5, mp["X"] = 10, 33 mp["L"] = 50, mp["C"] = 100, mp["D"] = 500, 34 mp["M"] = 1000; 35 } 36 };
【14】Longest Common Prefix (2019年1月22日,复习)
给了一组单词,由小写字母构成,找他们的公共前缀,返回这个字符串。
题解:可以暴力解,可以trie树。
1 class Solution { 2 public: 3 string longestCommonPrefix(vector<string>& strs) { 4 if(strs.empty()) return ""; 5 for(int i=0; i<strs[0].size(); ++i){ 6 for(int j=1; j<strs.size(); ++j){ 7 if(strs[0][i] != strs[j][i]){ 8 return strs[0].substr(0,i); 9 } 10 } 11 } 12 return strs[0]; 13 } 14 };
1 class Solution { 2 public: 3 struct TrieNode { 4 char c; 5 vector<TrieNode*> children; 6 bool isEndingChar = false; 7 int cntChildrenNotNull = 0; 8 TrieNode(char t): c(t) { 9 children = vector<TrieNode*>(26, nullptr); 10 } 11 }; 12 class Trie { 13 public: 14 void insert(string s) { 15 TrieNode * node = root; 16 for (int i = 0; i < s.size(); ++i) { 17 char c = s[i]; 18 if (node->children[c-'a'] == nullptr) { 19 node->children[c-'a'] = new TrieNode(c); 20 node->cntChildrenNotNull++; 21 } 22 node = node->children[c-'a']; 23 } 24 node->isEndingChar = true; 25 return; 26 } 27 string getCommonPrefix() { 28 TrieNode* node = root; 29 string ret = ""; 30 while (node->cntChildrenNotNull == 1 && node->isEndingChar == false) { 31 for (int i = 0; i < 26; ++i) { 32 if (node->children[i]) { 33 node = node->children[i]; 34 break; 35 } 36 } 37 ret += string(1, node->c); 38 } 39 return ret; 40 } 41 TrieNode* root = new TrieNode('/'); 42 }; 43 string longestCommonPrefix(vector<string>& strs) { 44 const int n = strs.size(); 45 Trie trie; 46 for (auto s : strs) { 47 if (s.empty()) { 48 return s; 49 } 50 trie.insert(s); 51 } 52 return trie.getCommonPrefix(); 53 } 54 };
【17】Letter Combinations of a Phone Number (2019年1月22日,复习)
给了一个座机电话, 给了一个数字的字符串 digits,返回所有的数字对应的字母排列。
题解:map + dfs
1 class Solution { 2 public: 3 vector<string> letterCombinations(string digits) { 4 n = digits.size(); 5 if (n == 0) { return vector<string>{}; } 6 initMap(); 7 string s = ""; 8 dfs(digits, 0, s); 9 return ret; 10 } 11 int n; 12 unordered_map<int, vector<string>> mp; 13 vector<string> ret; 14 void dfs(string digits, int cur, string& s) { 15 if (cur == n) { 16 ret.push_back(s); 17 return; 18 } 19 int num = digits[cur] - '0'; 20 for (auto ele : mp[num]) { 21 string ori = s; 22 s += ele; 23 dfs(digits, cur + 1, s); 24 s = ori; 25 } 26 return; 27 } 28 void initMap() { 29 mp[2] = {"a", "b", "c"}; 30 mp[3] = {"d", "e", "f"}; 31 mp[4] = {"g", "h", "i"}; 32 mp[5] = {"j", "k", "l"}; 33 mp[6] = {"m", "n", "o"}; 34 mp[7] = {"p", "q", "r", "s"}; 35 mp[8] = {"t", "u", "v"}; 36 mp[9] = {"w", "x", "y", "z"}; 37 } 38 };
【20】Valid Parentheses (2019年1月22日,复习)
Given a string containing just the characters '('
, ')'
, '{'
, '}'
, '['
and ']'
, determine if the input string is valid. 判断一个字符串中的括号是不是合法的。
题解:用栈做。
代码不贴了。
【22】Generate Parentheses (2019年1月22日,复习)
【28】Implement strStr() (算法群,2018年11月4日,练习kmp)
实现在字符串 s 中找到 模式串 p, (kmp)
题解:暴力O(N*M) 可以解, kmp O(N+M) 也可以解 ,kmp务必再深入理解一下 next 数组的求法。不然面试不给笔记看就凉凉了。(还有一个注意点是 p 为空串的时候要特判)
1 class Solution { 2 public: 3 int strStr(string haystack, string needle) { 4 return kmp(haystack, needle); 5 } 6 int kmp(string& s, string& p) { 7 const int n = s.size(), m = p.size(); 8 if (m == 0) {return 0;} //p empty 9 vector<int> next = getNext(p); 10 int i = 0, j = 0; 11 while (i < n && j < m) { 12 if (j == -1 || s[i] == p[j]) { 13 ++i, ++j; 14 } else { 15 j = next[j]; 16 } 17 } 18 if (j == m) { 19 return i - j; 20 } 21 return -1; 22 } 23 vector<int> getNext(string& p) { 24 const int n = p.size(); 25 vector<int> next(n, 0); 26 next[0] = -1; 27 int j = 0, k = -1; 28 while (j < n - 1) { 29 if (k == -1 || p[j] == p[k]) { 30 ++k, ++j; 31 next[j] = p[j] == p[k] ? next[k] : k; 32 } else { 33 k = next[k]; 34 } 35 } 36 return next; 37 } 38 };
1 //暴力解法 O(N*M) 2 class Solution { 3 public: 4 int strStr(string haystack, string needle) { 5 const int n = haystack.size(), m = needle.size(); 6 if (m == 0) {return 0;} 7 for (int i = 0; i + m <= n; ) { // 判断条件要不要取等号,然后下面做了++i, ++j, for循环里面就别做了,尴尬,这都能错 8 int j; int oldi = i; 9 for (j = 0; j < m;) { 10 if (haystack[i] == needle[j]) { 11 ++i, ++j; 12 } else { 13 break; 14 } 15 } 16 if (j == m) { 17 return i - j; 18 } else { 19 i = oldi + 1; 20 } 21 } 22 return -1; 23 } 24 };
【30】Substring with Concatenation of All Words
【32】Longest Valid Parentheses
【38】Count and Say
【43】Multiply Strings (2018年11月27日,高精度乘法) (2019年3月5日更新)
给了两个string类型的数字,num1 和 num2, 用string的形式返回 num1 * num2。(num1, num2 的长度都小于等于110)
题解:我们可以不做翻转的操作,从 num1 和 num2 的末尾开始计算,num1[i], num2[j] 的乘积要放在 nums[i+j+1] 的位置,进位放在 nums[i+j] 的位置。返回结果的字符串的长度肯定是 nums1.size() + nums2.size() 的长度。
1 class Solution { 2 public: 3 string multiply(string num1, string num2) { 4 const int size1 = num1.size(), size2 = num2.size(); 5 vector<int> nums(size1 + size2, 0); 6 for (int i = size1 - 1; i >= 0; --i) { 7 for (int j = size2 - 1; j >= 0; --j) { 8 int temp = (num1[i] - '0') * (num2[j] - '0') + (nums[i+j+1]); 9 nums[i+j+1] = temp % 10; 10 nums[i+j] += temp / 10 ; 11 } 12 } 13 string res = ""; 14 for (auto num : nums) { 15 if (num == 0 && res.empty()) { 16 continue; 17 } 18 res += num + '0'; 19 } 20 if (res.empty()) { res = "0"; } 21 return res; 22 } 23 };
【44】Wildcard Matching
【49】Group Anagrams (2019年1月23日,谷歌tag复习)
给了一个单词列表,给所有的异构词分组。
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
题解:我的解法,hashmap + sort。不是最优秀的解法。还有什么用 26个素数代替法,这个更快吧。
代码不贴了。
【58】Length of Last Word
【65】Valid Number
【67】Add Binary
【68】Text Justification
【71】Simplify Path
【72】Edit Distance
【76】Minimum Window Substring
【87】Scramble String
【91】Decode Ways
【93】Restore IP Addresses
【97】Interleaving String
【115】Distinct Subsequences
【125】Valid Palindrome
【126】Word Ladder II
【151】Reverse Words in a String (2018年11月8日, 原地翻转字符串)
Input: "the sky is blue
",
Output: "blue is sky the
".
题解:用stringstream能做。
1 class Solution { 2 public: 3 void reverseWords(string &s) { 4 stringstream iss(s); 5 string temp; 6 iss >> s; 7 while (iss >> temp) { 8 s = temp + " " + s; 9 } 10 if (isspace(s[0])) {s = "";} 11 return; 12 } 13 };
【157】Read N Characters Given Read4
【158】Read N Characters Given Read4 II - Call multiple times
【159】Longest Substring with At Most Two Distinct Characters (2019年1月29日,谷歌tag复习)
给定一个字符串 s,返回它最长的子串的长度,子串要求只能有两个distinct characters。
题解:sliding window。(time complexity is O(N))
1 class Solution { 2 public: 3 int lengthOfLongestSubstringTwoDistinct(string s) { 4 const int n = s.size(); 5 int ans = 0; 6 int begin = 0, end = 0, cnt = 0; 7 unordered_map<char, int> mp; 8 while (end < n) { 9 mp[s[end]]++; 10 if (mp[s[end]] == 1) { 11 ++cnt; 12 } 13 if (cnt <= 2) { 14 ans = max(ans, end - begin + 1); 15 } 16 while (cnt > 2) { 17 mp[s[begin]]--; 18 if (mp[s[begin]] == 0) { 19 --cnt; 20 } 21 ++begin; 22 } 23 end++; 24 } 25 return ans; 26 } 27 };
【161】One Edit Distance (2018年11月24日,刷题数)
给了两个字符串 s 和 t,问 s 能不能通过 增加一个字符, 删除一个字符,替换一个字符 这三种操作里面的任意一个变成 t。能的话返回 true, 不能的话返回 false。
题解:感觉是基础版的编辑距离。直接通过模拟来做。beats 36%。时间复杂度是 O(N).
1 class Solution { 2 public: 3 bool isOneEditDistance(string s, string t) { 4 if (s == t) {return false;} 5 const int ssize = s.size(), tsize = t.size(); 6 int cnt = 0; 7 if (ssize == tsize) { //check replace; 8 int idx = findfirstidx(s, t); 9 if (idx == ssize || s.substr(idx+1) == t.substr(idx+1)) { 10 return true; 11 } 12 } else if (ssize == tsize - 1) { //check insert 13 int idx = findfirstidx(s, t); 14 if (idx == tsize || s.substr(idx) == t.substr(idx+1)) { 15 return true; 16 } 17 18 } else if (ssize == tsize + 1){ //check delete 19 int idx = findfirstidx(s, t); 20 if (idx == ssize || s.substr(idx+1) == t.substr(idx)) { 21 return true; 22 } 23 } 24 return false; 25 } 26 inline int findfirstidx (string s, string t) { 27 const int ssize = s.size(), tsize = t.size(); 28 int tot = min(ssize, tsize); 29 for (int i = 0; i < tot; ++i) { 30 if (s[i] != t[i]) { 31 return i; 32 } 33 } 34 return max(ssize, tsize); 35 } 36 };
【165】Compare Version Numbers (2019年5月5日, 字符处理类型的题目)
比较两个字符串版本号的大小。input 是 version1 和 version2。
比较规则是: ‘.’ 作为分隔符,如果同一层级的 version1 的number 小于 version2 的 number,返回 -1, 反之,如果大于,返回 1. 如果相等的话,继续比较下一个层级。
题解:直接模拟法做。时间复杂度是O(N).
1 class Solution { 2 public: 3 int compareVersion(string version1, string version2) { 4 int size1 = version1.size(), size2 = version2.size(); 5 int p1 = 0, p2 = 0; 6 int num1 = 0, num2 = 0; 7 while (p1 < size1 || p2 < size2) { 8 if (p1 < size1 && version1[p1] == '.') {++p1;} 9 if (p2 < size2 && version2[p2] == '.') {++p2;} 10 while (p1 < size1 && isdigit(version1[p1])) { 11 num1 = num1 * 10 + (version1[p1] - '0'); 12 ++p1; 13 } 14 while (p2 < size2 && isdigit(version2[p2])) { 15 num2 = num2 * 10 + (version2[p2] - '0'); 16 ++p2; 17 } 18 if (num1 < num2) {return -1;} 19 if (num1 > num2) {return 1;} 20 num1 = 0, num2 = 0; 21 } 22 return 0; 23 } 24 };
【186】Reverse Words in a String II (2018年11月8日, 原地翻转字符串)
Given an input string , reverse the string word by word.
Example: Input: ["t","h","e"," ","s","k","y"," ","i","s"," ","b","l","u","e"] Output: ["b","l","u","e"," ","i","s"," ","s","k","y"," ","t","h","e"] Note: A word is defined as a sequence of non-space characters. The input string does not contain leading or trailing spaces. The words are always separated by a single space.
题解:无。
1 class Solution { 2 public: 3 void reverseWords(vector<char>& str) { 4 reverse(str.begin(), str.end()); 5 const int n = str.size(); 6 int p1 = 0, p2 = 0; 7 while (p2 < n) { 8 while (p1 < n && str[p1] == ' ') {p1++;} 9 p2 = p1; 10 while (p2 < n && str[p2] != ' ') {p2++;} 11 reverse(str.begin() + p1, str.begin() + p2); 12 p1 = p2; 13 } 14 return; 15 } 16 };
【214】Shortest Palindrome (2018年11月2日,周五,算法群)
给了一个字符串 S,为了使得 S 变成回文串可以在前面增加字符,在增加最少的字符的前提下返回新的回文 S。
题解:我的做法跟昨天的题一样(366)就是找从第一个字符开始最长的回文串,然后把后面的那小段翻转一下,拼到前面。时间复杂度是O(N^2)
1 //类似的题目可以见 336 Palindrome Pairs 2 class Solution { 3 public: 4 string shortestPalindrome(string s) { 5 const int n = s.size(); 6 string ans = ""; 7 for (int j = n; j >= 0; --j) { 8 if (isPalindrome(s, 0, j-1)) { 9 string str = s.substr(j); 10 reverse(str.begin(), str.end()); 11 ans = str + s; 12 break; 13 } 14 } 15 return ans; 16 } 17 bool isPalindrome(const string& s, int start, int end) { //[start, end] 18 while (start < end) { 19 if (s[start] != s[end]) {return false;} 20 start++, end--; 21 } 22 return true; 23 } 24 };
应该还有更好的解法:(学习学习学习)。
【227】Basic Calculator II (2019年3月18日)
给了一个字符串,包含数字,+,-,*,/,和空格,求字符串表达式的值。
Example 1:
Input: "3+2*2" Output: 7
Example 2:
Input: " 3/2 " Output: 1
Example 3:
Input: " 3+5 / 2 " Output: 5
题解:本题大爷他们说用状态机的方法来做。状态机的方法就是遍历字符串,如果碰到 digit 应该怎么做,如果碰到 + - * / 应该怎么做,如果碰到 空格 应该怎么做。
用一个 vector<int> 做为 cache 缓存前面的只用 +,- 的值。
1 class Solution { 2 public: 3 int calculate(string s) { 4 const int n = s.size(); 5 int num = 0; 6 char sign = '+'; 7 vector<int> cache; 8 for (int i = 0; i < n; ++i) { 9 if (isdigit(s[i])) { 10 num = num * 10 + (s[i] - '0'); 11 } 12 if (i == n-1 || !isdigit(s[i]) && s[i] != ' '){ 13 if (sign == '+') {cache.push_back(num);} 14 if (sign == '-') {cache.push_back(-num);} 15 if (sign == '*' || sign == '/') { 16 int last = cache.back(); 17 cache.pop_back(); 18 if (sign == '*') {cache.push_back(last * num);} 19 else if (sign == '/') {cache.push_back(last / num);} 20 } 21 num = 0; 22 if (!isdigit(s[i])) { sign = s[i]; } 23 } 24 } 25 int res = 0; 26 for (auto& e : cache) { 27 res += e; 28 } 29 return res; 30 } 31 };
【249】Group Shifted Strings
【271】Encode and Decode Strings
【273】Integer to English Words
【293】Flip Game
【336】Palindrome Pairs (2018年11月1日,周四,算法群)
给了一组字符串words,找出所有的pair (i,j),使得 words[i] + words[j] 这个新的字符串是回文串。
题解:这题WA出了天际。因为map似乎一旦访问了某个不存在的key,这个key就变的存在了。。一开始我想暴力,暴力超时,暴力时间的时间复杂度是O(N^2*K)。后来认真思考了一下一个字符串是怎么变成回文的。如果一个字符串word,他的长度是n,如果它的前半段 word[0..j] 是个回文串,那么我们需要匹配它后面那段 word[j+1..n-1], 我们把后半段reverse一下, 查找字符串集合(map)里面有没有对应的这段。同理,如果它的后半段 word[j+1..n-1] 是个回文串,那么我们把前半段 reverse一下,在 map 里面查找有没有前半段就可以了。特别注意这个前半段和后半段都可以包含空串,所以 j 的范围是[0, n]。
1 class Solution { 2 public: 3 vector<vector<int>> palindromePairs(vector<string>& words) { 4 const int n = words.size(); 5 unordered_map<string, int> mp; 6 for (int i = 0; i < n; ++i) { 7 mp[words[i]] = i; 8 } 9 vector<vector<int>> ans; 10 set<vector<int>> st; 11 for (int i = 0; i < n; ++i) { 12 string word = words[i]; 13 int size = word.size(); 14 for (int j = 0; j <= size; ++j) { 15 if (isPalindrome(word, 0, j-1)) { 16 string str = word.substr(j); 17 reverse(str.begin(), str.end()); 18 //vector<int> candidate = vector<int>{mp[str], i}; 这个不能放在外面,不然mp[str]可能不存在 19 if (mp.find(str) != mp.end() && mp[str] != i) { 20 vector<int> candidate = vector<int>{mp[str], i}; 21 if (st.find(candidate) == st.end()) { 22 ans.push_back(candidate); 23 st.insert(candidate); 24 } 25 } 26 } 27 if (isPalindrome(word, j, size-1)) { 28 string str = word.substr(0, j); 29 reverse(str.begin(), str.end()); 30 //vector<int> candidate = vector<int>{i, mp[str]}; 31 if (mp.find(str) != mp.end() && mp[str] != i) { 32 vector<int> candidate = vector<int>{i, mp[str]}; 33 if (st.find(candidate) == st.end()) { 34 ans.push_back(candidate); 35 st.insert(candidate); 36 } 37 } 38 } 39 } 40 } 41 return ans; 42 } 43 bool isPalindrome(const string& word, int start, int end) { // [start, end] 44 while (start < end) { 45 if (word[start++] != word[end--]) { return false; } 46 } 47 return true; 48 } 49 };
听说这题还能用 trie 解,有空要看答案啊。
【340】Longest Substring with At Most K Distinct Characters (2019年1月29日,谷歌tag复习)
类似题:159. Longest Substring with At Most 2 Distinct Characters, sliding window 一模一样的。时间复杂度是O(N)
1 class Solution { 2 public: 3 int lengthOfLongestSubstringKDistinct(string s, int k) { 4 const int n = s.size(); 5 if (n <= k) {return n;} 6 int begin = 0, end = 0, cnt = 0; 7 unordered_map<char, int> mp; 8 int ans = 0; 9 while (end < n) { 10 mp[s[end]]++; 11 if (mp[s[end]] == 1) { 12 ++cnt; 13 } 14 if (cnt <= k) { 15 ans = max(ans, end - begin + 1); 16 } 17 while (cnt > k) { 18 mp[s[begin]]--; 19 if (mp[s[begin]] == 0) { 20 --cnt; 21 } 22 ++begin; 23 } 24 ++end; 25 } 26 return ans; 27 } 28 };
【344】Reverse String (2018年12月3日,第一次review,ko)
逆序一个字符串。
题解:直接reverse,或者 2 pointers
1 class Solution { 2 public: 3 string reverseString(string s) { 4 int start = 0, end = s.size() - 1; 5 while (start < end) { 6 swap(s[start++], s[end--]); 7 } 8 return s; 9 } 10 };
【345】Reverse Vowels of a String (2018年12月4日,第一次review,ko)
逆序一个字符串的元音字母。
题解:2 pointers
1 class Solution { 2 public: 3 string reverseVowels(string s) { 4 set<char> setVowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}; 5 int left = 0, right = s.size()-1; 6 while (left < right) { 7 while (setVowels.find(s[left]) == setVowels.end()) {++left;} 8 while (setVowels.find(s[right]) == setVowels.end()) {--right;} 9 if (left < right) { //这里需要再次判断 10 swap(s[left++], s[right--]); 11 } 12 } 13 return s; 14 } 15 };
【383】Ransom Note
【385】Mini Parser
【387】First Unique Character in a String
【408】Valid Word Abbreviation
【434】Number of Segments in a String
【443】String Compression (2019年2月12日)
压缩一个字符数组,"aaa" -> "a3", "bb" -> "b2", "c" -> "c"。要求 in-place。space复杂度为O(1).
题解:用指针做。用一个index指针记录当前新字符串的末尾的位置。
1 class Solution { 2 public: 3 int compress(vector<char>& chars) { 4 const int n = chars.size(); 5 int idx = 0; 6 int begin = 0, end = 0, cnt = 0; 7 while (end < n) { 8 if (chars[begin] == chars[end]) { 9 ++cnt; ++end; 10 } 11 if (end == n || (end < n && chars[begin] != chars[end])) { 12 chars[idx++] = chars[begin]; 13 if (cnt > 1) { 14 string s = to_string(cnt); 15 for (auto c : s) { chars[idx++] = c; } 16 } 17 begin = end; 18 cnt = 0; 19 } 20 } 21 return idx; 22 } 23 };
【459】Repeated Substring Pattern
【468】Validate IP Address (2018年12月7日)
判断一个字符串是不是有效的 IP 地址,区分 IPv4 和 IPv6, 都不是的话返回 Neither。IPv4 的判断很简单,就是用 ‘.’ 隔开的四段数字,然后每段数字都在0~255中间,数字没有前导 0。 IPv6 的判断比较麻烦,是八段用 ‘:’ 隔开是数字,每段数字都是四位十六进制数。四位数字如果有前置 0 的话,可以省略,以及大小写都可以忽略不同。
题解:比较复杂的模拟题。我用 getline 分割字符串,注意如果 它已经有 7 个 ‘:’ 分割八段十六进制数之后,如果在尾部还有一个 ‘:’ ,那么这个要特判。
1 #define NEITHER "Neither" 2 #define IPV4 "IPv4" 3 #define IPV6 "IPv6" 4 5 class Solution { 6 public: 7 string validIPAddress(string IP) { 8 if (IP.find(':') != string::npos) { 9 return checkIPV6(IP); 10 } 11 return checkIPV4(IP); 12 } 13 string checkIPV4(string IP) { 14 int cnt = 0; 15 string word; 16 stringstream ss; 17 ss << IP; 18 if (IP.front() == '.' || IP.back() == '.') {return NEITHER;} 19 while (getline(ss, word, '.')) { 20 cnt++; 21 if (word.size() > 3 || word.empty()) {return NEITHER;} 22 for (int i = 0; i < word.size(); ++i) { 23 if (i == 0 && word[i] == '0' && word.size() > 1 || !isdigit(word[i])) { 24 return NEITHER; 25 } 26 } 27 int num = stoi(word); 28 if (num < 0 || num > 255) {return NEITHER;} 29 } 30 if (cnt != 4) { 31 return NEITHER; 32 } 33 return IPV4; 34 } 35 string checkIPV6(string IP) { 36 int cnt = 0; 37 string word; 38 stringstream ss; 39 ss << IP; 40 if (IP.front() == ':' || IP.back() == ':') {return NEITHER;} 41 while (getline(ss, word, ':')) { 42 cnt++; 43 printf("word = %s \n", word.c_str()); 44 if (word.size() > 4 || word.empty()) {return NEITHER;} 45 for (int i = 0; i < word.size(); ++i) { 46 char c = word[i]; 47 if (!isalnum(c) || c > 'f' && c <= 'z' || c > 'F' && c <= 'Z') { 48 return NEITHER; 49 } 50 } 51 } 52 if (cnt != 8) { 53 return NEITHER; 54 } 55 return IPV6; 56 } 57 };
【520】Detect Capital
【521】Longest Uncommon Subsequence I
【522】Longest Uncommon Subsequence II
【527】Word Abbreviation
【536】Construct Binary Tree from String
【537】Complex Number Multiplication (2018年11月27日)
给了两个字符串,代表两个 complex, 返回这两个complex 的乘积(用字符串表示)。
题解:见math分类:https://www.cnblogs.com/zhangwanying/p/9790007.html
【539】Minimum Time Difference (2019年2月11日)
给了一个字符串list,代表时间,返回最小的时间差(分钟为单位)。
Input: ["23:59","00:00"] Output: 1
题解:先排序,然后两两相邻的相减。还有第一个和最后一个相减。
1 class Solution { 2 public: 3 int findMinDifference(vector<string>& timePoints) { 4 sort(timePoints.begin(), timePoints.end()); 5 int ret = calDiff(timePoints[0], timePoints.back()); 6 for (int i = 0; i < timePoints.size() - 1; ++i) { 7 ret = min(ret, calDiff(timePoints[i], timePoints[i+1])); 8 } 9 return ret; 10 } 11 int calDiff(string s1, string s2) { 12 int num1 = trans(s1), num2 = trans(s2); 13 if (num1 < num2) { swap(num1, num2); } 14 return min(num1 - num2, num2 + 1440 - num1); 15 } 16 int trans(string s) { 17 int hour = stoi(s.substr(0, 2)); 18 int min = stoi(s.substr(3)); 19 return hour * 60 + min; 20 } 21 };
【541】Reverse String II
【544】Output Contest Matches
【551】Student Attendance Record I
【553】Optimal Division
【555】Split Concatenated Strings
【556】Next Greater Element III
【557】Reverse Words in a String III
【564】Find the Closest Palindrome (2019年3月3日,H)
给定一个字符串 N, 求距离 N 最近的回文数。
- The input n is a positive integer represented by string, whose length will not exceed 18.
- If there is a tie, return the smaller one as answer.
Input: "123" Output: "121"
题解:唔,这个题看了awice的思路。就是说,我们先把这个数分成前面一半和后面一半,比如“23456”,一半就是“234”,用前面一半分别 +{-1, 0 ,1}, 然后生成对应的回文(注意原数字长度的奇偶性)。这样能生成3个candidate。
但是其实还有两个数字,就是比给定数字长度少一位的最大回文,9999...999,和比给定数字长度多一位的最小回文,10...01。一共五个candidate。
如果candidate中有N本身,就忽略掉。从candidate中选出距离最近的那个。
1 class Solution { 2 public: 3 string nearestPalindromic(string n) { 4 const int size = n.size(); 5 string strHalf = n.substr(0, (size + 1)/ 2); 6 long long half = stoll(strHalf); 7 set<string> st; 8 long long biggest = pow(10LL, size) + 1, smallest = pow(10LL, size - 1) - 1; 9 st.insert(to_string(smallest)); 10 st.insert(to_string(biggest)); 11 for (int i = -1; i <= 1; ++i) { 12 string p = to_string(half + i); 13 string pp = p; 14 if (size & 1) { 15 pp += string(p.rbegin() + 1, p.rend()); 16 } else { 17 pp += string(p.rbegin(), p.rend()); 18 } 19 st.insert(pp); 20 } 21 st.erase(n); 22 string res = ""; 23 long long absMinDiff = LLONG_MAX; 24 for (auto& s : st) { 25 long long num = stoll(s), target = stoll(n); 26 if (abs(num - target) < absMinDiff) { 27 res = s; 28 absMinDiff = abs(num - target); 29 } else if (abs(num - target) == absMinDiff && num < target) { 30 res = s; 31 } 32 } 33 return res; 34 } 35 };
【583】Delete Operation for Two Strings
【591】Tag Validator
【606】Construct String from Binary Tree
2018年11月14日,树的分类里面做了:https://www.cnblogs.com/zhangwanying/p/6753328.html
【609】Find Duplicate File in System
【616】Add Bold Tag in String
【632】Smallest Range
【635】Design Log Storage System
【647】Palindromic Substrings
【657】Robot Return to Origin
【678】Valid Parenthesis String
【680】Valid Palindrome II (2019年2月12日)
输入是一个字符串,问字符串最多删除一个字符,看能不能变成回文字符串。
题解:2 pointers 先遍历,找到第一个失配的地方,然后分别从左右去查找跳过这个字符,剩下的字符串是不是能成回文。
1 class Solution { 2 public: 3 bool validPalindrome(string s) { 4 int begin = 0, end = s.size() - 1; 5 while (begin < end) { 6 if (s[begin] != s[end]) { 7 if (isValid(s, begin+1, end) || isValid(s, begin, end-1)) { 8 return true; 9 } 10 return false; 11 } 12 ++begin, --end; 13 } 14 return true; 15 } 16 bool isValid(string s, int begin, int end) { 17 while (begin < end) { 18 if (s[begin++] != s[end--]) {return false;} 19 } 20 return true; 21 } 22 };
【681】Next Closest Time (2019年1月29日,谷歌tag复习)
给了一个字符串,代表时间,HH:MM,返回用当前数字组成的合法的下一个时间。There is no limit on how many times a digit can be reused.
Input: "19:34" Output: "19:39" Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later. It is not 19:33, because this occurs 23 hours and 59 minutes later.
Input: "23:59" Output: "22:22" Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. It may be assumed that the returned time is next day's time since it is smaller than the input time numerically.
题解:思路就是先把所有的四个数字存下来,从最小的(分针)开始往前找,如果找到了比当前位置更大的一个数的话,就用这个更大的数字去代替当前的数字。(前提是这个更大的数字代替完了之后这个时间得合法。)如果找到最大的位置都没有找到的话,那就用最小的数字生成一个第二天的时间来作为新的数字。
1 class Solution { 2 public: 3 string nextClosestTime(string time) { 4 set<int> st; 5 int minn = 10; 6 for (int i = 0; i < 5; ++i) { 7 if (isdigit(time[i])) { 8 int t = time[i] - '0'; 9 minn = min(t, minn); 10 st.insert(t); 11 } 12 } 13 if (st.size() == 1) {return time;} //invalid 14 string ret = time; 15 for (int i = 4; i >= 0; --i) { 16 char c = ret[i]; 17 int t = c - '0'; 18 auto iter = upper_bound(st.begin(), st.end(), t); 19 if (iter == st.end()) {continue;} 20 if (i == 0 && *iter > 2) { 21 continue; 22 } 23 if (i == 1 && *iter > 4 && ret[0] == '2') { 24 continue; 25 } 26 if (i == 3 && *iter > 5) { 27 continue; 28 } 29 ret[i] = (*iter) + '0'; 30 for (int k = i + 1; k < 5; ++k) { 31 if (isdigit(ret[k])) { 32 ret[k] = minn + '0'; 33 } 34 } 35 break; 36 } 37 if (ret == time) { 38 for (auto& c : ret) { 39 if (isdigit(c)) { 40 c = minn + '0'; 41 } 42 } 43 } 44 return ret; 45 46 } 47 };
【686】Repeated String Match
【696】Count Binary Substrings (2021年10月24日)
https://leetcode.com/problems/count-binary-substrings/
题解:思路是构造一个count 数组,来表示连续0,连续1的个数,e.g: [0,0,0,1,1,1,1,0,0] 这样的构造数组就是 [3, 4, 2]。然后结果就是 res += min(3, 4) + min(4, 2) 这样。因为肯定是要跟相邻的最小个数的元素决定有几个子串。
另一种解释:
首先,数一下,连续的0,1的个数有多少,构成一个数组。比如,“0110001111”的连续0和1的个数是[1, 2, 3, 4].
然后,我们想求得0和1的个数相等的子串,所以需要进行一个交错,找出相邻的两个个数的最小值就好了。比如“0001111”, 结果是min(3, 4) = 3, 即,("01", "0011", "000111")。
有什么道理呢?因为我们求得字符串出现的数组,它的每个位置一定是0,1交错的子字符串长度。否则相邻的0或者1会拼成更长的长度。所以我们最后求交错的最小值,就是得到了相邻字符串的0和1相等的长度。
https://blog.csdn.net/fuxuemingzhu/article/details/79183556
1 class Solution { 2 public: 3 int countBinarySubstrings(string s) { 4 const int n = s.size(); 5 vector<int> counts; 6 int curCount = 1; 7 for (int i = 1; i < n; ++i) { 8 if (s[i] != s[i-1]) { 9 counts.push_back(curCount); 10 curCount = 1; 11 } else { 12 curCount++; 13 } 14 } 15 counts.push_back(curCount); 16 17 int res = 0; 18 for (int i = 0; i+1 < counts.size(); ++i) { 19 res += min(counts[i], counts[i+1]); 20 } 21 return res; 22 } 23 };
【709】To Lower Case
【722】Remove Comments (2019年2月16日, M)
给了一个字符串的数组,每个字符串代码一行代码,里面'//', '/*', '*/' 分别代表一行和多行注释。返回去掉注释后的代码段。
题解:用两个bool变量记录,inline记录是否当前在//注释里面,inBlock记录是否当前在 /**/ 里面。然后业务逻辑比较一下。
1 class Solution { 2 public: 3 vector<string> removeComments(vector<string>& source) { 4 vector<string> res; 5 bool inBlock = false; 6 string s = ""; 7 for (auto& line : source) { 8 const int n = line.size(); 9 bool inLine = false; 10 for (int i = 0; i < n; ++i) { 11 if (i + 1 < n && line[i] == '/') { 12 if (line[i+1] == '/' && !inBlock) { 13 inLine = true; 14 } else if (line[i+1] == '*' && !inLine && !inBlock) { 15 ++i, inBlock = true; 16 } else if (!inBlock && !inLine) { 17 s += string(1, line[i]); 18 } 19 } else if (i + 1 < n && line[i] == '*' && line[i+1] == '/') { 20 if (inBlock) { 21 ++i, inBlock = false; 22 } else if (!inLine){ 23 s += string(1, line[i]); 24 } 25 } else { 26 if (inBlock || inLine) {continue;} 27 s += string(1, line[i]); 28 } 29 } 30 if (!inBlock && !s.empty()) { 31 res.push_back(s); 32 s.clear(); 33 } 34 } 35 return res; 36 } 37 };
【730】Count Different Palindromic Subsequences
【736】Parse Lisp Expression
【758】Bold Words in String
【761】Special Binary String
【767】Reorganize String
【770】Basic Calculator IV
【772】Basic Calculator III
【788】Rotated Digits
【791】Custom Sort String (2018年11月27日)
给了两个字符串 S 和 T, S中最多有 26个小写字母,给 T 重新排序,如果字母 x, y 在 S 中出现,且在 T 中出现,如果在 S 中 x 出现在 y 之前, 那么在 T 中 x 也要出现在 y 之前。没有在 S 中出现的字符就随便放哪里都可以。
题解:直接 unordered_map
1 class Solution { 2 public: 3 string customSortString(string S, string T) { 4 const int n = T.size(); 5 unordered_map<char, int> mp; 6 for (int i = 0; i < n; ++i) { 7 mp[T[i]]++; 8 } 9 string ret; 10 for (auto c : S) { 11 if (mp.find(c) == mp.end() || mp[c] == 0) {continue;} 12 ret += string(mp[c], c); 13 mp[c] = 0; 14 } 15 for (auto ele : mp) { 16 if (ele.second > 0) { 17 ret += string(ele.second, ele.first); 18 } 19 } 20 return ret; 21 } 22 };
【800】Similar RGB Color
【804】Unique Morse Code Words
【809】Expressive Words (2019年2月13日,google tag)
给了一个word S和一个word list,问word list中有多少pattern符合S。一个 pattern w 符合 S 的条件是,w extend之后可以变成 S。w 中的一个字母可以extend成三个或者三个以上相同的字母。问word list中有多少个这样的pattern。
题解:我的解法时间复杂度是O(NM),空间复杂度使用了一个map,还是比较高的。我的解法的说明如下:对于S中每一个小段重复序列,计算当前字符重复了多少次。根据不同重复的次数得到pattern中的相同字符的范围,然后去对比pattern。
1 class Solution { 2 public: 3 int expressiveWords(string S, vector<string>& words) { 4 const int n = S.size(); 5 unordered_map<string, int> mp; 6 for (auto& w : words) { mp[w] = 0; } 7 int begin = 0, end = 0, cnt = 0; 8 int res = 0; 9 while (end < n) { 10 while (end < n && S[begin] == S[end]) { 11 ++end; 12 } 13 cnt = end - begin; 14 pair<int, int> range(0, 0); 15 if (cnt <= 2) { 16 range = make_pair(cnt, cnt); 17 } else { 18 range = make_pair(1, cnt + 1 - 3); 19 } 20 res = 0; 21 for (auto& p : mp) { 22 string pattern = p.first; 23 int start = p.second, end1 = start, size = pattern.size(); 24 if (start < 0) {continue;} 25 while (end1 < size && pattern[end1] == pattern[start]) { 26 ++end1; 27 } 28 int sameSize = end1 - start; 29 if (sameSize >= range.first && sameSize <= range.second) { 30 p.second = end1; 31 ++res; 32 } else { 33 p.second = -1; 34 } 35 } 36 begin = end; 37 } 38 return res; 39 } 40 };
还有lee215的解法。写的很短,也很好理解。需要好好复习学习。
用word list中每个单词和S做一个比较,比较规则如下:
Loop through all words. check(string S, string W)
checks if W
is stretchy to S
.
In check
function, use two pointer:
- If
S[i] == W[j]
,i++, j++
- If
S[i - 2] == S[i - 1] == S[i]
orS[i - 1] == S[i] == S[i + 1]
,i++
- return false
1 class Solution { 2 public: 3 int expressiveWords(string S, vector<string>& words) { 4 int res = 0; 5 for (auto& w : words) { 6 if (check(S, w)) {++res;} 7 } 8 return res; 9 } 10 bool check(const string& s, const string& w) { 11 int n = s.size(), m = w.size(); 12 int j = 0; 13 for (int i = 0; i < n; ++i) { 14 if (j < m && s[i] == w[j]) {++j;} 15 else if (i - 2 >= 0 && s[i] == s[i-1] && s[i] == s[i-2]) {;} 16 else if (i - 1 >= 0 && i + 1 < n && s[i] == s[i-1] && s[i] == s[i+1]) {;} 17 else { return false; } 18 } 19 return j == m; 20 } 21 };
【816】Ambiguous Coordinates
【819】Most Common Word
【824】Goat Latin
【831】Masking Personal Information
【833】Find And Replace in String
【842】Split Array into Fibonacci Sequence
【848】Shifting Letters
【856】Score of Parentheses
【859】Buddy Strings
【890】Find and Replace Pattern
【893】Groups of Special-Equivalent Strings
【899】Orderly Queue