LeetCode String 数据结构-字符串(题号3,5,6,8,12,13,14,17,20,28,38,43,49)

3Longest 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;
    }    
};
5Longest Palindromic Substring(String,Dynamic Programming)最长回文子串

题目描述:

给定一个字符串 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);
        

  } 
};
6ZigZag 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;
    }    
};
8String 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;
    }
};
12Integer to Roman(String, Math)整数转罗马数字

题目描述:

罗马数字包含以下七种字符: I, V, X, LCD 和 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;
    }
    
};
13Roman to Integer(String, Math)罗马数字转整数

题目描述:

罗马数字包含以下七种字符:I, V, X, LCD 和 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;
    }
};
14Longest 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; //若全部通过,别忘了最后返回
    }
};
17Letter 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;        
    }  
    
};
20Valid Parentheses(String, Stack)有效的括号

题目描述:

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。

示例 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;     
         
    }
    
};
22Generate Parentheses(String, Backtracking)括号生成

题目描述:

给出 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;
    }    
};
28Implement 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;
        
    }
};
38Count 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;
    }
};
43Multiply Strings(String, Math)字符串相乘

题目描述:

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

说明:

  1. num1 和 num2 的长度小于110。
  2. num1 和 num2 只包含数字 0-9
  3. num1 和 num2 均不以零开头,除非是数字 0 本身。
  4. 不能使用任何标准库的大数类型(比如 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;        
      
    }
};
49Group 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;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值