3. Longest Substring Without Repeating Characters(String,Hash table,Two pointers)无重复字符的最长子串
题目描述:
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:
给定 "abcabcbb"
,没有重复字符的最长子串是 "abc"
,那么长度就是3。
给定 "bbbbb"
,最长的子串就是 "b"
,长度是1。
给定 "pwwkew"
,最长子串是 "wke"
,长度是3。请注意答案必须是一个子串,"pwke"
是 子序列 而不是子串。
思路分析:
使用哈希表,动态更新两个值,开始记录值startPos和最长子串长度maxLen。每当在哈希表中找到重复元素时就比较重复元素下标加一与原startPos大小,若前者大则赋值给startPos。然后比较新的子串长度与原先最长子串长度maxLen,若大于后者,则更新。最终当整个循环结束时返回maxLen。总时间复杂度O(n)。
class Solution { public: int lengthOfLongestSubstring(string s) { int maxLen = 0; int startPos = 0; unordered_map<char,int> hmap; for(auto i = 0; i < s.size(); i++){ if(hmap.find(s[i]) != hmap.end()){ startPos = startPos > (hmap[s[i]] + 1) ? startPos : (hmap[s[i]] + 1); } maxLen = maxLen > (i - startPos + 1) ? maxLen : (i - startPos + 1); hmap[s[i]] = i; } return maxLen; } };
5. Longest Palindromic Substring(String,Dynamic Programming)最长回文子串
题目描述:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba"也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
思路分析:
1. 动态规划:
回文字符串的子串也回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。这样需要额外的空间O(N^2),算法复杂度也是O(N^2)。
首先定义状态方程和转移方程:
P[i,j]=true 表示子串[i,j]不是回文串。P[i,j]=false 表示子串[i,j]是回文串。
显然 P[i,i]=true
P[i,j] =P[i+1,j-1], if(s[i]==s[j])
P[i,j] =false, if(s[i]!=s[j])
string longestPalindrome(string s) { //动态规划,时间复杂度O(N^2),空间复杂度O(N^2)。运行时间120ms int start = 0, maxLen = 1;//考虑到单字符的字符串 bool P[1000][1000] = {false}; for(int i = 0; i < s.size(); ++i){//初始化准备 P[i][i] = true; if(i < s.size() - 1 && s[i] == s[i + 1]){ P[i][i+1] = true; start = i; maxLen = 2; } } for(int len = 3; len <= s.size(); ++len){//子串长度 for(int i = 0; i <= s.size() - len; ++i){//子串起始地址 int j = i + len - 1;//子串结束地址 if(P[i+1][j-1] && s[i] == s[j]){ P[i][j] = true; start = i; maxLen = len; } } } return s.substr(start,maxLen); }2. 中心扩展+剪枝 高效算法
中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。中心扩展算法复杂度为O(N^2),但剪枝后效率极大提高,在LeetCode上测试,所耗时间接近Manacher算法。
string longestPalindrome(string s) { int len = s.size(); int left = 0, right = 0; int maxLen = 0, start = 0; for(int i = 0; i < len; ++i){ left = i, right = i; //剪枝,很重要 while(right < len - 1 && s[right + 1] == s[right]) ++right; i = right; while(left > 0 && right < len - 1 && s[left - 1] == s[right + 1]) {--left; ++right;} if(maxLen < right - left + 1) {maxLen = right - left + 1; start = left;} } return s.substr(start, maxLen); }
3. Manacher算法,时间复杂度O(N),空间复杂度O(1)。
Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是需要在里面添加特殊字符。头部添加"$#",中间添加“#”,尾部添加“#%”,使abba变为$#a#b#b#a#%。这个算法就是利用已有回文串的对称性来计算的,算法时间复杂度为O(N)。详细思路我参考的这个链接 https://segmentfault.com/a/1190000008484167
class Solution { public: string longestPalindrome(string s) { //Manacher算法,时间复杂度O(N),空间复杂度O(1)。 //添加特殊字符$,#,% string myStr; myStr += "$"; for(int i = 0; i < s.size(); ++i){//为了能够处理偶回文,在所有字符中间添加特殊字符#,如baad变为#b#a#a#d# myStr += "#";//每隔一个字符添加一个# myStr += s[i]; } myStr += "#%"; //初始化变量 int len = myStr.size();//len表示添加特殊字符“ $,#,% ”后字符串的长度 vector<int> rad(len);//rad(i)表示以i为中心的回文串的半径, rad(i)-1恰好是原字符串中回文串的长度 int id = 0; int mx = 0;//表示以id为中心、回文串的右边界 int max_id = 0;//最长回文串中心 int maxRad = 0;//最长回文串半径 //确定最长回文串中心和半径 for(int i = 1; i < len - 1; ++i){//这里i = 0 和 i = len - 1不考虑,原因它们代表特殊字符“ $ , %” if(i < mx) rad[i] = min(rad[2 * id - i], mx - i + 1); else rad[i] = 1; while(myStr[i - rad[i]] == myStr[i + rad[i]])// 不需边界判断,因为左有'$',右有'%' ++rad[i]; if(mx < i + rad[i] - 1){ mx = i + rad[i] - 1; id = i; } if(maxRad < rad[i]){ maxRad = rad[i]; max_id = i; } } return s.substr((max_id - maxRad)/2, maxRad - 1); } };
6. ZigZag Conversion(String)Z字形变换
题目描述:
将字符串 "PAYPALISHIRING"
以Z字形排列成给定的行数:
P A H N A P L S I I G Y I R
之后从左往右,逐行读取字符:"PAHNAPLSIIGYIR"
实现一个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "PAYPALISHIRING", numRows = 3 输出: "PAHNAPLSIIGYIR"
示例 2:
输入: s = "PAYPALISHIRING", numRows = 4 输出: "PINALSIGYAHRPI" 解释: P I N A L S I G Y A H R P I
思路分析:
声明一个字符串向量,这样每个元素都是一个字符串。 之后,需要两个循环,一个是对所给行数的正向循环,两外一个是去掉行首和行尾的逆向循环,记住要始终保证不越界。
class Solution { public: string convert(string s, int numRows){ //better solustion , time complexity O(n), space complexity 0(n) vector<string> strVec(numRows); int len = s.size(), i = 0; while(i < len){ for(int j = 0; j < numRows && i < len; ++i, ++j) strVec[j].push_back(s[i]); for(int j = numRows -2; j > 0 && i < len; ++i, --j) strVec[j].push_back(s[i]); } string res; for(int k = 0; k < strVec.size(); ++k){ res += strVec[k]; } /*vector<string>::iterator it; for(it = strVec.begin(); it != strVec.end(); ++it) res += *it;*/ return res; } };
8. String to Integer (atoi) (String)字符串转整数
题目描述:
实现 atoi
,将字符串转为整数。
在找到第一个非空字符之前,需要移除掉字符串中的空格字符。如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即为整数的值。如果第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
字符串可以在形成整数的字符后面包括多余的字符,这些字符可以被忽略,它们对于函数没有影响。
当字符串中的第一个非空字符序列不是个有效的整数;或字符串为空;或字符串仅包含空白字符时,则不进行转换。
若函数不能执行有效的转换,返回 0。
说明:
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。如果数值超过可表示的范围,则返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: "42" 输出: 42
示例 2:
输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
思路分析:
此题题目叙述很长,但却完整地给出了编程需要考虑的情况,只要不遗漏还是很容易AC。可分为如下几步:1. 判空;2. 空格;3. 符号; 4. 计算真值(注意边界)
class Solution { public: int myAtoi(string str) { //1. empty string if(str.empty()) return 0; //2.whitespaces,trim auto offset = 0; while (str[offset] == ' ') ++offset; //3. +/- sign auto sign = 1; if(str[offset] == '+'){ sign = 1; ++offset; } else if(str[offset] == '-'){ sign = -1; ++offset; } //4.calculate real value auto ret = 0; while(offset < str.length()){ auto c = str[offset]; auto val = 0; if(c >= '0' && c <= '9') val = c - '0'; else break; //5.handle min & max if(ret > INT_MAX/10 || (ret == INT_MAX/10 && val > 7)) return sign > 0 ? INT_MAX : INT_MIN; ret *= 10; ret += val; ++offset; } return sign*ret; } };
12. Integer to Roman(String, Math)整数转罗马数字
题目描述:
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例 1:
输入: 3 输出: "III"
示例 2:
输入: 4 输出: "IV"
示例 3:
输入: 9 输出: "IX"
示例 4:
输入: 58 输出: "LVIII" 解释: C = 100, L = 50, XXX = 30, III = 3.
示例 5:
输入: 1994 输出: "MCMXCIV" 解释: M = 1000, CM = 900, XC = 90, IV = 4.
思路分析:
由于罗马数字组合个数不多,因此可枚举。把罗马数字的组合提前存入字符串数组中,然后使用取整取余计算调用即可。
/*static 声明的局部变量为静态局部变量,该变量的内存只被分配一次,因此,其值在下次调用的时候仍然维持原始值*/ /*static 声明的全局变量为静态全局变量,该变量可以被模块内的所有函数访问,但是不能被模块外的其他函数访问。*/ static const string ones[9] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; static const string tens[9] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; static const string hundreds[9] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; static const string thousands[3] = {"M", "MM", "MMM"}; class Solution { public: string intToRoman(int num) { if(num == 0) return ""; string numeral = ""; int times = 0; times = num / 1000; num %= 1000; if(times > 0) numeral.append(thousands[times - 1]); times = num / 100; num %= 100; if(times > 0) numeral.append(hundreds[times - 1]); times = num / 10; num %= 10; if(times > 0) numeral.append(tens[times - 1]); if(num > 0) numeral.append(ones[num - 1]); return numeral; } };
13. Roman to Integer(String, Math)罗马数字转整数
题目描述:
罗马数字包含以下七种字符:I
, V
, X
, L
,C
,D
和 M
。
字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
思路分析:
定义一个额外的函数来转换每个字母所对应的数字,然后在循环中注意特殊字母组合"IV","IX","XL","XC","CD","CM"
class Solution { public: int charToNum(char c){ switch(c){ case 'M': return 1000; case 'D': return 500; case 'C': return 100; case 'L': return 50; case 'X': return 10; case 'V': return 5; case 'I': return 1; default: return 0; } return 0; } int romanToInt(string s) { int tmp1, tmp2; tmp1 = charToNum(s[0]); int sum = tmp1; for(int i = 1; i < s.size(); ++i){ tmp2 = charToNum(s[i]); if(tmp2 > tmp1) sum += tmp2 - 2 * tmp1; else sum += tmp2; tmp1 = tmp2; } return sum; } };
14. Longest Common Prefix(String)最长公共前缀
题目描述:
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入: ["flower","flow","flight"] 输出: "fl"
示例 2:
输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z
。
思路分析:
1. 特殊情况处理,[],[""],["element"] 2.获取向量strs中最短的字符串 3.将最短字符串赋值给myStr,并删除原向量中最短字符串 4.求最长公共前缀
class Solution { public: string longestCommonPrefix(vector<string>& strs) { string myStr, res = ""; int minLen = INT_MAX;//初始化最短的字符串长度 int min_index;//最短的字符串长度所在位置 //特殊情况处理,[],[""],["element"] if(strs.size() == 0) return res; else if(strs.size() == 1) return strs[0]; //获取向量strs中最短的字符串 for(int i = 0; i < strs.size(); ++i){ if(minLen > strs[i].size()){ minLen = strs[i].size(); min_index = i; } } //将最短字符串赋值给myStr,并删除原向量中最短字符串 myStr = strs[min_index]; strs.erase(strs.begin() + min_index); //求最长公共前缀 for(int j = 0; j < myStr.size(); ++j){ for(int i = 0; i < strs.size(); ++i){ if(myStr[j] != strs[i][j]) return res; } res += myStr[j]; } return res; //若全部通过,别忘了最后返回 } };
17. Letter Combinations of a Phone Number(String, Backtracking)电话号码的字母组合
题目描述:
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
思路分析:
1. 递归回溯思路求解(DFS)
class Solution { public: //先做一个索引表,将0-9的数字与其代表的字母对应起来 vector<string> index = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; vector<string> letterCombinations(string digits) { //递归方法(DFS) vector<string> ans; if(digits.size() > 0){ vector<string> tmp = letterCombinations(digits.substr(1, digits.size() - 1)); if(tmp.size() == 0) tmp.push_back(""); for(int i = 0; i < index[digits[0] - '0'].size(); ++i) for(int j = 0; j < tmp.size(); ++j) ans.push_back(index[digits[0] - '0'][i] + tmp[j]); } return ans; } };
2. 非递归的方法(BFS)
class Solution { public: //先做一个索引表,将0-9的数字与其代表的字母对应起来 vector<string> index = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; vector<string> letterCombinations(string digits) { //非递归方法(BFS) vector<string> ans; if(digits.size() > 0){ ans = {""}; for(int i = 0; i < digits.size(); ++i){ vector<string> tmp; for(int j = 0; j < ans.size(); ++j){ for(int k = 0; k < index[digits[i] - '0'].size(); ++k){ tmp.push_back(ans[j] + index[digits[i] - '0'][k]); } } ans = tmp; } } return ans; } };
20. Valid Parentheses(String, Stack)有效的括号
题目描述:
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()" 输出: true
示例 2:
输入: "()[]{}" 输出: true
示例 3:
输入: "(]" 输出: false
示例 4:
输入: "([)]" 输出: false
示例 5:
输入: "{[]}" 输出: true
思路分析:
首先看一下原c++栈的基本用法:
push(): 向栈内压入一个成员;
pop(): 从栈顶弹出一个成员;
empty(): 如果栈为空返回true,否则返回false;
top(): 返回栈顶,但不删除成员;
size(): 返回栈内元素的大小;
接下来,要编写三个子函数,分别确定是否为左括号、是否为右括号和是否左右匹配。在主函数中要注意判空,另外判断栈顶元素与输入元素适合匹配时可以使用top()函数,它的作用取出栈顶元素。最终不要忘了判断栈中是否为空,若
class Solution { public: bool isLeft(char x){ switch(x){ case '(': //return true; case '[': //return true; case '{': return true; default: return false; } } bool isRight(char x){ switch(x){ case ')': //return true; case ']': //return true; case '}': return true; default: return false; } } bool match(char left, char right){ switch(left){ case '(': return (right == ')'); case '[': return (right == ']'); case '{': return (right == '}'); default: return false; } } bool isValid(string s) { if(s.empty()) return true; stack<char> stk;//声明一个栈 for(int i = 0; i < s.length(); ++i){ if(isLeft(s[i])) stk.push(s[i]); else if(isRight(s[i])){ if(stk.empty()) return false; if(!match(stk.top(), s[i])) return false; stk.pop(); } } if(!stk.empty()) return false; return true; } };
22. Generate Parentheses(String, Backtracking)括号生成
题目描述:
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
思路分析:
递归实现,如果左括号还有剩余,则可以放置左括号;如果右括号剩余数大于左括号剩余数,则可以放置右括号。
class Solution { public: //递归实现,如果左括号还有剩余,则可以放置左括号;如果右括号剩余数大于左括号剩余数,则可以放置右括号 void generate(int left, int right, string str, vector<string>& ret){ if(left == 0 && right == 0){ ret.push_back(str); return; } if(left > 0) generate(left - 1, right, str + '(', ret); if(right > left) generate(left, right - 1, str + ')', ret); } vector<string> generateParenthesis(int n){ vector<string> ret; generate(n, n, "", ret); return ret; } };
28. Implement strStr() (String, Two Pointers) 实现strStr()
题目描述:
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll" 输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "bba" 输出: -1
说明:
当 needle
是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle
是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
思路分析:
首先需要判断字符串是否为空,为空的话返回0。接下来考虑剪枝思想,去掉needle的长度。接下来判断即可。
class Solution { public: int strStr(string haystack, string needle) { if(needle == "") return 0; int len = haystack.size() - needle.size();//trim if(len < 0) return -1; for(int i = 0; i <= len; ++i){ for(int j = 0; j < needle.size(); ++j){ if(haystack[i + j] != needle[j]) break; if(j == needle.size() - 1) return i; } } return -1; } };
38. Count and Say(String)报数
题目描述:
报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1. 1 2. 11 3. 21 4. 1211 5. 111221
1
被读作 "one 1"
("一个一"
) , 即 11
。11
被读作 "two 1s"
("两个一"
), 即 21
。21
被读作 "one 2"
, "one 1"
("一个二"
, "一个一"
) , 即 1211
。
给定一个正整数 n ,输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1 输出: "1"
示例 2:
输入: 4 输出: "1211"
思路分析:
首先要处理边界情况,当n=1时直接返回“1”;当n=2时直接返回“11”。当n不小于3时,需要计数,并且要数字转数字字符。
class Solution { public: string countAndSay(int n) { //better solution if(n <= 1) return "1"; if(n == 2) return "11"; string str = "11"; for(int i = 3; i <= n; ++i){ string tmp = ""; str += "$";//为了与真实的最后一个元素判断 int len = str.size(), count = 1; for(int j = 1; j < len; ++j){ if(str[j] != str[j - 1]){ tmp += count + '0';//trick,数字转数字字符 tmp += str[j - 1]; count = 1; }else{ ++count; } } str = tmp; } return str; } };
43. Multiply Strings(String, Math)字符串相乘
题目描述:
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3" 输出: "6"
示例 2:
输入: num1 = "123", num2 = "456" 输出: "56088"
说明:
num1
和num2
的长度小于110。num1
和num2
只包含数字0-9
。num1
和num2
均不以零开头,除非是数字 0 本身。- 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
思路分析:
这道题的要求是计算 大数乘法!!!!
1. 假设两个整数的长度分别为了l1和l2,则其最后结果长度为l1+l2(最后有进位)或者l1+l2-1(最后没有有进位)。2. 因此,可以先用长度为l1+l2的数组记录结果,最后再转成字符串。3. 进行乘法的时候,先把各个位的相乘结果对应累加起来,即第1个整数的第i位(低位到高位)和第2个整数的第j位(低位到高位)相乘的结果应该存放在数组的i+j位。4. 然后再统一处理进位。 5. 最后将数组转成字符串前,需要跳过前面的零。如果结果只有0,则只返回0。
时间复杂度:O(l1*l2)(l1和l2分别为两个整数长度)
空间复杂度:O(l1+l2)
class Solution { public: string multiply(string num1, string num2) { vector<int> ret(num1.size() + num2.size(), 0);//用长度为l1+l2的数组记录结果 for(int i = 0; i < num1.size(); ++i){//乘法,把各位的相乘结果对应累加起来 for(int j = 0; j < num2.size(); ++j){ ret[i + j] += (num1[num1.size() - 1 - i] - '0') * (num2[num2.size() - 1 - j] - '0');//数字字符 - ‘0’可以转化为对应数字 } } //统一处理进位 int tmp = 0;//临时进位量 for(int i = 0; i < ret.size(); ++i){ int num = ret[i] + tmp; ret[i] = num % 10; tmp = num / 10; } //跳过前面的零 int count = ret.size() - 1; while(count >= 0 && ret[count] == 0) --count; //数字转字符串 string str = ""; if(count < 0) str = "0"; else{ for( ; count >= 0; --count) str += ret[count] + '0'; } return str; } };
49. Group Anagrams(String, Hash Table)组合字母异位词
题目描述:
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
,
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:
- 所有输入均为小写字母。
- 不考虑答案输出的顺序。
思路分析:
该题目要求是将给定的一组字符串数组,按照字母异位词(相同字母组成的单词)分类,每组单词按照字典排序。这道题考察的主要是哈希的思想,这样才能保证时间在要求的范围内。
class Solution { public: vector<vector<string>> groupAnagrams(vector<string>& strs) { vector<vector<string>> ret; //将字符串按照字典顺序排序 sort(strs.begin(), strs.end()); //利用哈希思想构建hmap,将排序后相等的字符串存在相应的vector中 unordered_map<string, vector<string>> hmap; for(int i = 0; i < strs.size(); ++i){ string str = strs[i]; sort(str.begin(), str.end());//对字符串str按照字典序内部排序 hmap[str].push_back(strs[i]); } for(auto iter = hmap.begin(); iter != hmap.end(); ++iter){ ret.push_back(iter -> second); }//sort(ret.begin(), ret.end()); //为了保证输出的顺序,可省略 return ret; } };