字符串处理问题

  1. 大小写转换

    LeetCode 709 To Lower Case

    输入一个字符串,输出相同的小写后的字符串

    举例1:

    输入:”Hello”

    输出:”hello”

    举例2:

    输入:”here”

    输出:”here”

    举例3:

    输入:”LOVELY”

    输出:”lovely”

    /*
    思路:大小写转换有多种方法,这里介绍两种。1)根据ASCII码值,小写字母的ASCII码值比大写字母大32,因此可以对大写字母进行+32操作;2)可以使用tolower()函数,对字符进行小写处理。
    */
    //第一种方法
    class Solution {
    public:
       string toLowerCase(string str) {
           string res = "";
           int len = str.length();
           for(int i = 0; i < len; ++i)
           {
               if(str[i]>='A'&&str[i]<='Z')
                   res+=(str[i]+32);
               else
                   res+=str[i];
           }
           return res;
       }
    };
    //第二种方法
    class Solution {
    public:
       string toLowerCase(string str) {
           int i;
           for(i=0;i<str.size();i++)
        {
                str[i]= (char)tolower(str[i]);
        }
           return str;
       }
    };
  2. 字符串反转

    有两种字符串反转操作:1)字符串整体反转;2)字符串中的单词反转;3)字符串中单词位置反转;4)反转给定位置的字符;5)反转元音字母位置。分别对应LeetCode 344、557、151、541、345。

    1)字符串整体反转

    输入:”A man, a plan, a canal: Panama”

    输出:”amanaP :lanac a ,nalp a ,nam A”

    /*
    思路:可以使用反向迭代器,对字符串进行输出。
    */
    class Solution {
    public:
       string reverseString(string s) {
           string result = "";
           for(auto it = s.rbegin(); it != s.rend(); ++it)
           {
               result += *it;
           }
           return result;
       }
    };

    2)反转字符串中的单词

    输入:”Let’s take LeetCode contest”

    输出:”s’teL ekat edoCteeL tsetnoc”

    /*
    思路:此题在对单词进行反转时,使用到反向迭代器。可以通过对字符串进行是否等于空格或者是否为最后一个字符的判断,如果不是,则将此字符加入到temp字符串中,否则将现有的temp反向输出,并且加上空格,然后清空temp,继续遍历。
    */
    class Solution {
    public:
       string reverseWords(string s) {
           vector<string> temp;
           string str = "";
           string result = "";
           if(s.size()==0)
               return result;
           for(int i = 0; i < s.size(); ++i)
           {
               if(s[i] != ' ')
                   str += s[i];
               if(s[i] == ' ' || i == s.size()-1)
               {
                   for(auto it = str.rbegin(); it != str.rend(); ++it)
                   {
                       result += *it;
                   }
                   if(i != s.size()-1)
                   {
                       result += " ";
                       str = "";
                   }
                   else
                       return result;
               }
    
           }
       }
    };

    3)字符串中单词位置反转

    输入:”the sky is blue”

    输出:”blue is sky the”

    /*
    思路:将字符串中的单词一次放入vector容器内,然后从容器最后一个元素开始向前遍历,两两之间加入空格,遍历到第0个字符后,不加空格。
    */
    class Solution {
    public:
       void reverseWords(string &s) {
           vector<string> temp;
    
           string tempstr = "";
    
           for(int i = 0; i < s.size(); ++i)
           {
               if(s[i] != ' ')
                   tempstr += s[i];
               if(s[i] == ' ' || i == s.size()-1)
               {
                   if(tempstr != "")
                   {
                       temp.push_back(tempstr);
                       tempstr = "";
                   }
               }
           }
    
           string res = "";
           int len = temp.size();
    
           for(int i = len-1; i >= 0; --i)
           {
               if(i != 0)
               {
                   res += temp[i];
                   res += " ";
               }
               else
               {
                   res +=temp[i];
               }
           }
           s = res;
       }
    };

    4)反转给定位置的字符

    输入:s = “abcdefg”,k = 2

    输出:”bacdfeg”

    解释:每个2k长度的子串中,反转前k个。

    /*
    思路:对字符串按照2k的长度进行划分,对前k的字符进行swap操作。
    */
    class Solution {
    public:
       string reverseStr(string s, int k) {
           for(int i = 0; i < s.size(); i = i + 2 * k)
           {
               reverseStr(s, i, i + k - 1);
           }
           return s;
       }
    
       string reverseStr(string &s, int begin, int end)
       {
           if(end > s.size()-1)
               end = s.size()-1;
    
           while(end > begin)
           {
               swap(s[begin], s[end]);
               begin++;
               end--;
           }
           return s;
       }
    };

    5)反转元音字母位置

    输入:hello

    输出:holle

    输入:leetcode

    输出:leotcede

    /*
    思路:将元音字母存在一个vector中,将其对应的下标存在另一个vector中。
    然后从下标vector的最后一个元素开始,将其对应的元素赋值为元音字母所在容器的第i个,元音字母所在容器从第一个元素开始遍历。
    */
    class Solution {
    public:
       string reverseVowels(string s) {
           vector<char> vowels;
           vector<int> index;
           int len = s.size();
    
           for(int i = 0; i < len; ++i)
           {
               if(isvowels(s[i]))
               {
                   vowels.push_back(s[i]);
                   index.push_back(i);
               }               
           }
    
           int count = vowels.size() - 1;
           for(int i = 0; i < index.size(); ++i)
           {
               s[index[i]] = vowels[count];
               count--;
           }
           return s;
       }
    
       bool isvowels(char c)
       {
           if(c == 'a' || c == 'A' || c == 'e' || c == 'E' || c == 'o' || c == 'O' || c == 'i' || c == 'I' || c == 'u' || c == 'U')
               return true;
           else
    
               return false;
       }
    };
  3. 括号的打印

    LeetCode 22 Generate Parentheses

    给定n对括号,写一个函数来产生所有合法的括号组合。

    举例:n=3,则最终的集合为

    [

    ​ “((()))”,

    ​ “(()())”,

    ​ “(())()”,

    ​ “()(())”,

    ​ “()()()”

    ]

    /*
    思路:使用两个变量来标记左括号和右括号的剩余数量,l,r,只有当r和l都为0时,此次组合结束,将本次组合加入到vector中。当l大于0时,可以一直放左括号;当r>0并且r>l时,可以放右括号。
    */
    class Solution {
    public:
       vector<string> generateParenthesis(int n) {
           vector<string> res;
           string str = "";
           result(res, str, n, n);
           return res;
    
       }
    
       void result(vector<string> &res, string str, int left, int right)
       {
           if(left == 0 && right == 0)
           {
               res.push_back(str);
               return;
           }
           if(left > 0)
               result(res, str + "(", left-1, right);
           if(right > 0 && left < right)
               result(res, str + ")", left, right-1);
       }
    };
  4. 回文子串

    LeetCode 647 Palindromic Substrings

    给定一个字符串,返回该字符串中所有回文子串数目,开始下标和结束下标不同的相同回文子串,属于不同回文子串。

    举例:

    输入:”abc”

    输出:3

    解释:”a”,”b”,”c”

    输入:”aaa”

    输出:6

    解释:”a”,”a”,”a”,”aa”,”aa”,”aaa”

    /*
    思路:回文串都有一个对称轴,奇数的对称轴为最中间的字符,偶数的对称轴是中间两个字符。当在回文串两端各加入两个相同字符的时候,形成的新字符依旧是回文串。因此,起始阶段,我们可以从一个字符串开始,或者从两个相同字符开始,运用上述规律来寻找回文串。
    */
    class Solution {
    public:
       int countSubstrings(string s) {
           for(int i = 0; i < s.size(); ++i)
           {
               helper(s, i, i);  //从中间一个字符串开始
               helper(s, i, i+1);  //从中间相同的两个字符串开始
           }
           return count;
       }
       int count = 0;
       void helper(string s, int left, int right)
       {
           while(left >= 0 && right < s.size() && s[left] == s[right])
           {
               count++;
               left--;  //分别向左右两端加入新的字符
               right++; 
           }
       }
    };
  5. 最佳除法

    LeetCode 553 Optimal Division

    给定一段连续的除法式子,我们需要给它在不同地方加括号,确保能得到最大的结果,最后以string的形式返回结果

    举例:

    输入:

    [1000, 100, 10, 2]

    输出:

    “1000/(100/10/2)”

    /*
    思路:对于连除形式,在除数部分加入括号实际上是改变了除数和被除数的值:
    在不添加任何括号的情况下:
    a / b / c / d / ... = a / (b * c * d * ...)
    在算式中添加括号会使得被除数和除数的构成发生变化
    但无论括号的位置如何,a一定是被除数的一部分,b一定是除数的一部分
    原式添加括号方案的最大值,等价于求除数的最小值
    因此最优添加括号方案为:
    a / (b / c / d / ...) = a * c * d * ... / b
    */
    class Solution {
    public:
       string optimalDivision(vector<int>& nums) {
           int len = nums.size();
           if(len == 0)
               return "0";
           if(len == 1)
               return to_string(nums[0]);
           if(len == 2)
               return to_string(nums[0]) + "/" + to_string(nums[1]);
           string res = "";
           res += to_string(nums[0]) + "/" + "(";
           for(int i = 1; i < len; ++i)
           {
               if(i != len-1)
                   res += to_string(nums[i]) + "/";
               else
                   res += to_string(nums[i]) + ")";
           }
           return res;
       }
    };
  6. 括号得分

    LeetCode 856 Score of Parentheses

    给定一个配对好的括号串,计算这个字符串的得分。

    ()为1分

    AB为A+B

    (A)为2 * A

    举例:

    输入:”()”

    输出:1

    输入:”(())”

    输出:2

    输入:”()()”

    输出:2

    输入:(()(()))

    输出:6

    /*
    思路:题目中要求只有()才能得分,而且嵌套的()会将得分加倍,所以题目可以简化为求所有()的得分,其中得分多少取决于被嵌套的层数。因此,需要有一个变量来记录嵌套的层数,每一层加倍一次,层内为加法。
    */
    class Solution {
    public:
       int scoreOfParentheses(string S) {
           int len = S.size();
    
           int temp = 0;
           int count_p = 0; //记录嵌套层数
           for(int i = 0; i < len; ++i)
           {
               if(S[i] == '(')
               {
                   if(S[i+1] == ')')
                   {
                       temp += 1 << count_p;  //加倍
                   }
                   count_p++;
               }
               else
                   count_p--;
           }
           return temp;
       }
    };
  7. 独一无二的莫斯码

    LeetCode 804 Unique Morse Code Words

    本题给出26个字母的摩斯码,然后输入一个数组,数组中的元素为字符串,求出这组字符串转换为莫斯码后,有几种摩斯码。

    举例:

    输入:

    words = ["gin", "zen", "gig", "msg"]

    输出:

    2

    解释:

    The transformation of each word is:
    "gin" -> "--...-."
    "zen" -> "--...-."
    "gig" -> "--...--."
    "msg" -> "--...--."
    
    There are 2 different transformations, "--...-." and "--...--.".
    /*
    思路:先将Morse码和26个字母匹配,存在map中。然后遍历每个字符串的每个字符,将其转换为相应的摩斯码,然后将生成的摩斯码存在map中,这样相同的摩斯码就不会重复存储,因此最终map的大小就为不同摩斯码序列的个数。
    */
    class Solution {
    public:
       int uniqueMorseRepresentations(vector<string>& words) {
           vector<string> Morse = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
           map<char,string> dict;
           char j = 'a';
           for(int i = 0; j <= 'z' && i < Morse.size(); ++j,++i)
           {
               dict[j] = Morse[i];
           }
    
           map<string, int> count;
           for(int i = 0; i < words.size(); ++i)
           {
               string temp = "";
               for(int j = 0; j < words[i].length(); ++j)
               {
                   temp += dict[words[i][j]];
               }
    
               count[temp]++;
           }
           return count.size();
       }
    };
  8. 罗马字母转换成整数

    LeetCode 13 Roman to Integer

    给定一串罗马字母,计算其代表的整数

    举例:

    输入:III

    输出:3

    输入:IV

    输出:4

    输入:LVIII

    输出:58

    /*
    思路:建立一个map来存储基本的罗马字母与其对应的整数。然后从字符串最后一个字母开始遍历,若前一个比它小,则用当前数值减前一个;若前一个比它大,则用当前数值加前一个。
    */
    class Solution {
    public:
       int romanToInt(string s) {
           map<char, int> char2int;
           char2int['I'] = 1;
           char2int['V'] = 5;
           char2int['X'] = 10;
           char2int['L'] = 50;
           char2int['C'] = 100;
           char2int['D'] = 500;
           char2int['M'] = 1000;
    
           int sum = char2int[s[s.size()-1]];
    
           for(int i = s.size()-2; i >= 0; --i)
           {
               if(char2int[s[i]] < char2int[s[i+1]])
                   sum -= char2int[s[i]];
               else
                   sum += char2int[s[i]];
           }
           return sum;
       }
    };
  9. 整数转换成罗马字母

    LeetCode 12

    给定一个整数,输出其罗马字母表示的字符串

    举例:

    输入:3

    输出:III

    输入:58

    输出:LVIII

    /*
    思路:罗马数字可以分为1、4、5、9这四种构成方式,而1-3999中,共有1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1,共计13种,依次分别对应"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I",即
    整数数字  1000 900 500 400 100 90 50 40 10 9  5 4  1
    罗马数字  M    CM  D   CD  C   XC L  XL X  IX V IV I
    */
    class Solution {
    public:
       string intToRoman(int num) {
           map<int,string> intMapRoman;
           //int num[] = {1000,900,500,400,100,90,50,40,10,9,};
           intMapRoman[1] = "I";
           intMapRoman[4] = "IV";
           intMapRoman[5] = "V";
           intMapRoman[9] = "IX";
           intMapRoman[10] = "X";
           intMapRoman[40] = "XL";
           intMapRoman[50] = "L";
           intMapRoman[90] = "XC";
           intMapRoman[100] = "C";
           intMapRoman[400] = "CD";
           intMapRoman[500] = "D";
           intMapRoman[900] = "CM";
           intMapRoman[1000] = "M";
    
           map<int,string>::reverse_iterator rit = intMapRoman.rbegin();
           string res = "";
           while(num != 0)
           {
               if(num >= (rit->first))
               {
                   num -= rit->first;
                   res += rit->second;
               }
               else
                   rit++;
           }
           return res;
       }
    };
  10. 最小时间差

    LeetCode 539

    给定一个24小时制的时间列表,寻找两个时间点的最小差值。

    举例:

    输入:[“23:59”, “00:00”]

    输出:1

    注意:给定的列表中最少有两个时间节点

    /*
    思路:如果不对输入的时间进行排序,那么需要两两之间比较,再将比较的值取最小值,这样复杂度会比较大。因此,我们考虑先将输入的时间序列进行排序,排序后相邻两个时间之间比较,最后一个时间再和第一个时间比较。在计算出两者差值后,用24*60减去此差值,在两者中取最小,就是相邻两个时间点的最小时间点,然后在所有相邻的最小时间点钟取最小,就是最终的结果。
    */
    class Solution {
    public:
       int findMinDifference(vector<string>& timePoints) {
           int len = timePoints.size();
           //int differ = 0;
           sort(timePoints.begin(), timePoints.end());
           int min_time = 1440;
    
           for(int i = 0; i < len; ++i)
           {
               int temp = abs(diff(timePoints[i], timePoints[(i-1+len)%len]));
               temp = min(temp, 1440-temp);
               min_time = min(temp, min_time);
           }
           return min_time;  
       }
       int diff(string time1, string time2)
       {
           int h1, m1, h2, m2;
           h1 = stoi(time1.substr(0,2));  //stoi函数将字符串转换成int类型
           m1 = stoi(time1.substr(3,2));
           h2 = stoi(time2.substr(0,2));
           m2 = stoi(time2.substr(3,2));
           return (h1 - h2) * 60 + (m1 - m2);
       }
    };
  11. 最长公共子串

    LeetCode 718

    给定两个序列A和B,找出最长公共子串。比如A为12112,B为12113,则最长公共子串为1211,长度为4.要求子串中的字符在原序列中是连续的。

    此题可以采用动态规划的方法来解,我们可以先列出表格来对比

    12112
    00000
    101011
    200200
    101031
    101014
    300000

    由上表可以得到迭代公式如下:

    if(A[i] == B[i])
        dp[i][j] = dp[i-1][j-1] + 1;
    else
        dp[i][j] = 0;

    最终结果为矩阵中最大元素。

    class Solution {
    public:
        int findLength(vector<int>& A, vector<int>& B) {
            int m = A.size();
            int n = B.size();
            vector<vector<int> > dp(m+1,vector<int>(n+1,0));
    
            int res = 0;
            for(int i = 1; i < m + 1; ++i)
            {
                for(int j = 1; j < n + 1; ++j)
                {
                    if(A[i-1] == B[j-1])
                        dp[i][j] = dp[i-1][j-1]+1;
                    else
                        dp[i][j] = 0;
                    res = max(res,dp[i][j]);
                }
            }
    
            return res;
        }
    };
  12. 最长公共子序列

    子序列跟子串的区别在于,子串要求连续,而子序列不要求连续。因此在进行对比时,迭代公式如下:

    if(A[i] != B[j])
        dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
    else
        dp[i][j] = dp[i-1][j-1] + 1;

    例如,A为357486782,B为13456778

    13456778
    00000000
    300111111
    500112222
    700112233
    400122233
    800122233
    600122333
    700122344
    800122344
    200122344

    因此最长公共子序列为5

  13. 两个字符串的删除操作

    LeetCode 583 Delete Operation for Two Strings

    给定两个字符串,求出最少删除多少个元素,可以使得两个字符串相同。

    举例:

    输入:”sea”,”eat”

    输出:2

    /*
        思路:本题其实是一道求最长公共子序列的题。只有求出两个字符串的最长公共子序列的长度l,然后用两个字符串长度和减去2倍的l,就是需要删除的最少元素。
    */
    class Solution {
    public:
        int minDistance(string word1, string word2) {
            int m = word1.size();
            int n = word2.size();
    
            vector<vector<int> > dp(m + 1, vector<int>(n + 1, 0));
            for(int i = 1; i <= m; ++i)
            {
                for(int j = 1; j <= n; ++j)
                {
                    if(word1[i-1] == word2[j-1])
                        dp[i][j] = dp[i-1][j-1] + 1;
                    else
                        dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                }
            }
    
            return m + n - 2 * dp[m][n];
        }
    };
  14. 最长递增子序列

    LeetCode 300

    最长递增子序列是在最长子序列的基础上,对序列的顺序大小做出了要求。如序列{1,4,3,2,6,5}的最长递增子序列长度为3。

    思路:对于序列A中的第i个元素A[i],它能够加入到已有递增序列的条件是前j个元素j<i,A[j]<A[i],并且以A[j]为结尾的子序列长度最大。设F[i]为递推矩阵,则递推公式为:
    F[1] = 1;
    F[i] = max{F[i], F[j]+1 | A[j] < A[i] && j < i}
    F1F2F3F4F5F6
    122233
    class Solution {
    public:
        int lengthOfLIS(vector<int>& nums) {
            int len = nums.size();
            if(len == 0)
                return 0;
            int result = 1;
            vector<int> dp(len,1);
            dp[0] = 1;
            for(int i = 1; i < len; ++i)
            {
                for(int j = 0; j < i; ++j)
                {
                    if(nums[j] < nums[i])
                        dp[i] = max(dp[i],dp[j] + 1);
                }
                result = max(result,dp[i]);
            }
            return result;
        }
    };
  15. 最长递增子串

    LeetCode 674 Longest Continuous Increasing Subsequence

    输入一组整数序列,找出这个序列中最长的递增连续子串。这个题和上一题的区别是,上一题要求是最大递增子序列,不要求连续。此题要求连续。

    举例:

    输入:[1,3,5,4,7]

    输出:3

    输入:[2,2,2,2,2,2]

    输出:1

    /*
        思路:和最大递增子序列的思路类似,不过这次比较时,如果A[j] >= A[i], j<i时,dp[i] = 0;否则dp[i] = dp[j] + 1
    */
    class Solution {
    public:
        int findLengthOfLCIS(vector<int>& nums) {
            int len = nums.size();
            vector<int> dp(len,0);
    
            if(len == 0)
                return 0;
    
            dp[0] = 1;
    
            int res = 1;
    
            for(int i = 1; i < len; ++i)
            {
                for(int j = 0; j < i; ++j)
                {
                    if(nums[j] < nums[i])
                        dp[i] = dp[j]+1;
                    else
                        dp[i] = 1;
                }
                res = max(res, dp[i]);
            }
            return res;
        }
    };
  16. 最长公共前缀

    LeetCode 14 Longest Common Prefix

    输入一组字符串,找出这组字符串的最长公共前缀,如果没有公共前缀,则返回空串。

    举例:

    输入:[“flower”, “flow”, “flight”]

    输出:”fl”

    注意:所有元素都是小写字母

    方法一:

    暴力解法

    /*
        思路:从第一个字符串的第一个字符开始,如果其余字符串也在相应位置有这个字符,则将flag和1与,否则和0与,这样只有当其余所有字符串都包含这个字符时,最终的flag是1,如果最终的flag是1,则将这个字符加入最终结果。如果最终flag不是1,则停止循环。
    */
    class Solution {
    public:
        string longestCommonPrefix(vector<string>& strs) {
            string res = "";
            int len = strs.size();
            if(len == 0)
                return "";
            if(len == 1)
                return strs[0];
            int flag = 1;
            for(int i = 0; i < strs[0].size(); ++i)
            {
                for(int j = 1; j < len; ++j)
                {
                    if(strs[j][i]==strs[0][i])
                        flag &= 1;
                    else
                        flag &=0;
                }
                if(flag)
                    res += strs[0][i];
                else
                    break;
            }
            return res;
        }
    };

    方法二:

    排序法

    /*
        思路:可以先将整个字符串数组中的字符串排序,最短的字符串在最前面,最长的在最后面。然后,只需比较第一个字符串和最后一个字符串的公共前缀即可。
    */
    class Solution {
    public:
        string longestCommonPrefix(vector<string>& strs) {
            int len = strs.size();
            string res = "";
            if(len == 0)
                return "";
            sort(strs.begin(), strs.end());
    
            for(int i = 0; i < strs[0].size(); ++i)
            {
                if(strs[0][i] == strs[len-1][i])
                    res +=strs[0][i];
                else
                    break;
            }
            return res;
        }
    };
  17. 最大回文序列

    给定一个字符串,该字符串由大小写字母组成,找出能够用这些字符组成的最大回文序列。

    举例:

    输入:abccccdd

    输出:7

    解释:最大回文序列为dccaccd,长度为7。

    /*
        思路:首先,对于出现次数为偶数次的字符,是一定可以全部加入回文序列中的,对于出现次数为奇数次的字符,如果其大于1,可以将其n-1个加入回文序列,如果此时回文序列长度不是奇数,则可以将剩下的1加入,否则不加入。回文序列长度为奇数,说明已经加入了长度为奇数的字符。
    */
    class Solution {
    public:
        int longestPalindrome(string s) {
            int len = s.size();
            map<char, int> charMapInt;
    
            for(int i = 0; i < len; ++i)
            {
                charMapInt[s[i]]++;
            }
    
            map<char, int>::iterator it = charMapInt.begin();
            int res = 0;
            while(it != charMapInt.end())
            {
                res += it->second / 2 * 2;
                if(it->second % 2 == 1 && res % 2 == 0) //res % 2 == 0这句话很重要,这句话可以保证出现奇数次的字符仅被使用一次
                    res++;
                it++;
            }
            return res;
        }
    };
  18. 最长Harmonious子序列

    LeetCode 594

    定义Harmonious序列是指序列中最大元素-最小元素=1。给定一个整数序列,找出最大的Harmonious子序列。

    举例:

    输入:[1,3,2,2,5,2,3,7]

    输出:5

    解释:[3,2,2,2,3]

    /*
        思路:使用map容器,对出现的所有数字进行统计,由于map是按照Key升序排序,所以,从map的第一个元素开始,如果该元素+1的元素在容器中存在,那么ans = max(anx, a+b)。
    */
    class Solution {
    public:
        int findLHS(vector<int>& nums) {
            int len = nums.size();
    
            if(len == 0)
                return 0;
            if(len == 1)
                return 0;
            map<int,int> numsMapCount;
    
            for(int i = 0; i < len; ++i)
            {
                numsMapCount[nums[i]]++;
            }
    
            map<int,int>::iterator it = numsMapCount.begin();
            if(numsMapCount.size() == 1)
                return 0;;
            int ans = 0;
    
            while(it != numsMapCount.end())
            {
                if(numsMapCount.count((it->first)+1))
                    ans = max(ans, (it->second) + numsMapCount[(it->first) + 1]);
                it++;
            }
            return ans;
        }
    };
  19. 最大连续子序列

    LeetCode 128

    这里的连续并不是指子序列中元素在原序列中位置连续,而是指子序列中元素的大小连续。找出最大连续的子序列长度。

    举例:

    输入:[100,4,200,1,3,2]

    输出:4

    解释:最长连续元素序列为[1,2,3,4],长度为4

    /*
        思路:可以先将本题输入给出的元素存在set中,这样set会按照值的大小从小到大排列,然后使用和上题一样的思路,从第一个元素开始,判断该元素+1是否在set中,若在则count加一,不在则count置为1,最终选择最大的count。
    */
    class Solution {
    public:
        int longestConsecutive(vector<int>& nums) {
            set<int> temp;
            int len = nums.size();
    
            for(int i = 0; i < len; ++i)
            {
                temp.insert(nums[i]);
            }
    
            set<int>::iterator it = temp.begin();
            //set<int>::iterator next;
            int count = 1;
            int res = 0;
            while(it != temp.end())
            {
                //next = it++;
                //it--;
                if(temp.count((*it)+1))
                {
                    count++;
                }
                else
                    count = 1;
                res = max(res, count);
                it++;
            }
            return res;
        }
    };
  20. 最大回文子序列

    LeetCode 516

    此题和第16题求最大回文序列不同的是,在给定的字符串中,回文序列的字符排列先后顺序要和原序列一致。

    举例:

    输入:bbbab

    输出:4

    解释:bbbb,长度为4

    /*
        思路:这类题目一般采用动态规划的方法,定义迭代矩阵dp[i][j]表示从第i个位置到第j个位置的最大回文子序列的长度。如果n[i] == n[j],则说明可以再去掉首尾的最大回文长度上+2,即dp[i][j] = dp[i+1][j-1] + 2;如果n[i] != n[j],则选择去掉头或者去掉尾的回文序列长度最大值,即dp[i][j] = max(dp[i+1][j], dp[i][j-1])。最后返回从0到n-1的值。
    */
    class Solution {
    public:
        int longestPalindromeSubseq(string s) {
            int len = s.size();
            vector<vector<int> > dp(len, vector<int>(len,0));
    
            for(int i = len-1; i >= 0; --i)
            {
                dp[i][i] = 1;
                for(int j = i + 1; j < len; ++j)
                {
                    if(s[i] == s[j])
                        dp[i][j] = dp[i+1][j-1] + 2;
                    else
                        dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
                }
            }
            return dp[0][len-1];
        }
    };
  21. 最大回文子串

    LeetCode 5

    与上一题不同,此题求得最大回文子串是指连续的字符,字符间不能间断。

    举例:

    输入:babad

    输出:bab

    /*
        思路:回文序列是指从某个字符开始,其左右两个元素相等,则将其加入新的回文序列。回文序列有两种情况,一种是一个元素左右两端,另一个是两个相同元素左右两端加入相同元素。
    */
    class Solution {
    public:
        string longestPalindrome(string s) {
            int len = s.size();
            if(len <= 1)
                return s;
    
            string res = "";
            int max = 0;
    
            for(int i = 0; i < len; ++i)
            {
                string temp = "";
                int l = i, r = i;
                temp = getPalindrome(s,l,r);
                if(temp.size() > max)
                {
                    max = temp.size();
                    res = temp;
                }
    
                if(i != len - 1)
                {
                    l = i;
                    r = i + 1;
                    temp = getPalindrome(s,l,r);
                    if(temp.size() > max)
                    {
                        max = temp.size();
                        res = temp;
                    }
                }
            }
            return res;
        }
        string getPalindrome(const string s, int l, int r)
        {
            while(l >= 0 && r < s.size() && s[l] == s[r])
            {
                l--;
                r++;
            }
            return s.substr(l+1,r-l-1);
        }
    };
  22. 字典中最长单词

    LeetCode 720

    给定一组string,寻找最长的一个string,使得他由words中的元素逐字母生成,如world,则它逐字母生成意味着w,wo,wor,worl均在words中。如果长度相同,输出字典序较小那个,也就是第一个不同字母字典序较小的那个。

    输入:

    words = [“w”,”wo”,”wor”,”worl”,”world”]

    输出:

    “world”

    /*
        思路:首先,我们需要对输入的字符串数组按照字符串长度大小排序,对于字符串长度一样的,按照字符串字典关系排序。然后从第一个字符串开始,判断其各个子字符串是否在原字符串数组中存在。如果使用map或者set容器,则字符串自动按照字符串字典进行排序,所以我们需要将字符串和字符串长度定义为pair,然后将pair存在vector中,对vector进行sort排序,排序方法由我们自主定义。然后从排序好的vector中,第一个开始遍历,判断其各个子串是否存在,若判断发现都存在,则停止遍历,直接输出。
    */
    class Solution {
    public:
        static bool myCompare(pair<string,int> &a, pair<string, int> &b)
        {
            if(a.second == b.second)
                return a.first < b.first;
            else
                return a.second > b.second;
        }
    
        string longestWord(vector<string>& words) {
            set<string> wordstring;
            pair<string, int> temp;
            vector<pair<string, int> > wordcount;
    
            int len = words.size();
    
            for(int i = 0; i < len; ++i)
            {
                temp.first = words[i];
                temp.second = words[i].size();
    
                wordstring.insert(words[i]);
                wordcount.push_back(temp);
            }
    
            sort(wordcount.begin(), wordcount.end(), myCompare);
            int n;
            for(int i = 0; i < wordcount.size(); ++i)
            {
                for(n = wordcount[i].second-1; n > 0; --n)
                {
                    if(!wordstring.count(wordcount[i].first.substr(0, n)))
                        break;
                }
                if(n == 0)
                    return wordcount[i].first;
            }
            return "";
        }
    };
  23. 最长合法括号子串

    LeetCode 32

    给定一个由’(‘和’)’组成的字符串,找到其中最长和合法括号子串的长度。

    举例:

    输入:”(()”

    输出:2

    输入:”)()())”

    输出:4

    注意:求的是子串,不是子序列,所以())()的输出为2

    方法一:动态规划

    /*
        思路:这道题可以使用动态规划来做。定义迭代矩阵dp[i]表示第i个字符处的最大合法子串长度。当s[i]='(',则dp[i] = 0,只有在s[i] = ')'处会更新值:
        当s[i] == ')' && s[i-1] == '(',则dp[i] = dp[i-2] + 2;
        当s[i] == ')' && s[i-1] == ')' && s[i-dp[i-dp[i-1]-1]-1] == '(',则dp[i] = dp[i-1] + dp[i-dp[i-1]-2] +2;
        最后,在dp中取最大值输出。
    */
    class Solution {
    public:
        int longestValidParentheses(string s) {
            int len = s.size();
            vector<int> dp(len, 0);
            int res = 0;
    
            for(int i = 1; i < len; ++i)
            {
                if(s[i] == ')' && s[i-1] == '(')
                    dp[i] = dp[i-2] + 2;
                if(s[i] == ')' && s[i-1] == ')' && s[i - dp[i-1] - 1] == '(')
                {
                    dp[i] = dp[i-dp[i-1] - 2] + dp[i-1] + 2;
                }
                res = max(res, dp[i]);
            }
            return res;
        }
    };

    方法二:stack

    /*
        思路:采用stack来存储下标,当输入的字符为'('时,将其下标压入栈,否则将栈顶元素出栈,此时如果栈空,则将当前下标压入,否则计算当前下标和栈顶元素的差,和上次的差取最大。未来防治第一个元素就是')',我们在遍历字符串之前,将-1压入栈。
    */
    class Solution {
    public:
        int longestValidParentheses(string s) {
            int len = s.size();
            stack<int> temp;
            temp.push(-1);
    
            int res = 0;
            for(int i = 0; i < len; ++i)
            {
                if(s[i] == '(')
                    temp.push(i);
               else
               {
                   temp.pop();
                   if(temp.empty())
                       temp.push(i);
                   else
                       res = max(res, i - temp.top());
               }
            }
            return res;
        }
    };
  24. 复数的乘法

    LeetCode 537

    输入: “1+1i”, “1+1i”

    输出:”0+2i”

    输入:”1+-1i”, “1+-1i”

    输出:”0+-2i”

    方法一:使用stringstream

    /*
        思路:将字符串输入流中,然后从流中依次得到实部和虚部,最终计算公式是a的实部*b的实部-a的虚部*b的虚部 + (a的实部*b的虚部 + b的实部 * a的虚部)i
    */
    class Solution {
    public:
        string complexNumberMultiply(string a, string b) {
            stringstream sa(a),sb(b),res;
            int ra,ia,rb,ib;
            char buff;
            sa>>ra>>buff>>ia>>buff;
            sb>>rb>>buff>>ib>>buff;
    
            res<<(ra*rb - ia*ib) << "+" <<(ra * ib + rb * ia) << "i";
            return res.str();
    
        }
    };

    方法二:stoi+substr

    /*
        思路:定义一个提取函数,返回值为pair<int,int>,将一个字符串中的实部和虚部提取出来。使用stoi和substr来实现
    */
    class Solution {
    public:
        string complexNumberMultiply(string a, string b) {
            if(a=="")
                return b;
            if(b=="")
                return a;
            auto p1=extract(a);
            auto p2=extract(b);
            int x,y;
            x=p1.first*p2.first-p1.second*p2.second;
            y=p1.second*p2.first+p1.first*p2.second;
            string s;
            s=to_string(x)+"+"+to_string(y)+"i";
            return s;
    
        }
        pair <int,int> extract(string s)
        {
            int l=s.length(),i=1,a,b;
            while(i<l&&s[i]!='+')
                i++;
            a=stoi(s.substr(0,i));
            b=stoi(s.substr(i+1));
            return make_pair(a,b);
        }
    };
  25. 大数相乘

    LeetCode 43

    给定两个字符串,计算字符串中的数字乘积,输出仍以字符串输出。

    输入:

    num1 = “2”,num2 = “3”

    输出:

    “6”

    /*
        思路:将两个字符串逆序放入vector<int>容器内,然后开始遍历第二个的每一位乘第一个的每一位,res[i + j] += rnum1[i] * rnum2[j]; 最后再对res中的数字进行进位和取余操作,最后to_string后逆序输出即可。 
    */
    class Solution {
    public:
        string multiply(string num1, string num2) {
            int len1 = num1.size();
            int len2 = num2.size();
    
            vector<int> res(len1 + len2, 0); //存放结果
            vector<int> rnum1(len1,0);
            vector<int> rnum2(len2,0);
            //逆序存储
            for(int i = len1 - 1; i >= 0; --i)
            {
                rnum1[len1 - i - 1] = num1[i] - '0';
            }
    
            for(int i = len2 - 1; i >= 0; --i)
            {
                rnum2[len2 - i - 1] = num2[i] - '0';
            }
    
            //桉顺序相乘相加
            for(int i = 0; i < len1; ++i)
            {
                for(int j = 0; j < len2; ++j)
                {
                    res[i + j] += (rnum1[i] * rnum2[j]);
                }
            } 
    
            int flag = 0;//存储进位
            int temp = 0;//存储临时进位
    
            //计算每一位数字
            for(int i = 0; i < len1 + len2; ++i)
            {
                temp = (res[i] + flag) / 10;
                res[i] = (res[i] + flag) % 10;
                flag = temp;
            }
    
    
            string output = "";
            bool zero = false; //用来控制0的输出
            //如果前几位都是0则不输出,遇到了第一个不为0的数,则其后的所有0都合法输出
            for(int i = (len1 + len2) - 1; i >= 0; --i)
            {
                if(zero)
                {
                    output += to_string(res[i]);
                }
                else if(res[i])
                {
                    zero = true;
                    output += to_string(res[i]);
                }
            }
            //特别地,对于0*0 = 0的结果,输出0
            if(output == "")
                return "0";
            return output;
        }
    };
  26. 大数相加

    LeetCode 415

    输入两个字符串表示的数字,输出这两个数字相加的和,以字符串形式输出

    /*
        思路:先得到两个字符串的长度,只要两个长度有一个>=0,或者进位标识>0,进入循环。每次循环都计算一次当前位两个字符串相加的结果,然后将其个位输出到字符串,进位保存在进位标识。最后将字符串逆序输出即可。逆序输出可以使用reverse函数
    */
    class Solution {
    public:
        string addStrings(string num1, string num2) {
            int len1 = num1.size() - 1;
            int len2 = num2.size() - 1;
    
            string res = "";
            int flag = 0;
            int temp = 0;
    
            while(len1 >= 0 || len2 >= 0 || flag)
            {
                int sum = 0;
                if(len1 >= 0)
                {
                    sum += num1[len1]-'0';
                    len1--;
                }
    
                if(len2 >= 0)
                {
                    sum += num2[len2]-'0';
                    len2--;
                }
                temp = (sum + flag) / 10;
                res += to_string((sum + flag) % 10);
                flag = temp;
            }
    
            reverse(res.begin(), res.end());
    
            if(res.size() == 0)
                return "0";
            return res;
        }
    };
  27. 二进制数相加

    输入表示二进制的两个字符串,输出这两个二进制数的和,以字符串形式输出。

    输入:a = “11”, b = “1”

    输出:”100”

    /*
        思路:从两个字符串的最高位开始遍历,将两个的对应为相加,赋给int型变量c,c=0时代表两位都是0,c=1表示两位有一位是1,c=2表示两位都是1,且没有进位,c=3表示两位都是1且之前有进位。最终c%2表示当前位的最终值,c/2表示进位值。最后逆序输出。
    */
    class Solution {
    public:
        string addBinary(string a, string b) {
            int c = 0;//存放进位和当前位的和
            int la = a.size()-1;
            int lb = b.size()-1;
    
            string temp = "";
    
    
            while(c == 1 || la >= 0 || lb >= 0)
            {
                c += la >= 0 ? (a[la--] - '0') : 0;
                c += lb >= 0 ? (b[lb--] - '0') : 0;
    
                temp += (char)(c % 2 + '0');
    
                c /=2;
            }
            string res(temp.rbegin(), temp.rend());
            return res;
        }
    };
  28. 字符串加1操作

    LeetCode 66

    给一组int类型的数组,给该数组+1后,输出新的数组。

    输入:[4,3,2,1]

    输出:[4,3,2,2]

    /*
        思路:可以采用26和27的思路,将数组中的元素放在string中,作为第一个字符串,将1作为第二个字符串,采用之前的方法,计算输出,最后将输出结果转换为vector类型。
    */
    class Solution {
    public:
        vector<int> plusOne(vector<int>& digits) {
            string num1 = "";
            for(int i = 0; i < digits.size(); ++i)
            {
                num1 += to_string(digits[i]);
            }
    
            string num2 = "1";
    
            int len1 = num1.size();
            int len2 = num2.size();
            int flag = 0;
            int temp = 0;
            string res = "";
            int i = len1 - 1;
            int j = len2 - 1;
    
            while(i >= 0 || j >= 0 || flag)
            {
                int sum = 0;
                if(i >= 0)
                {
                    sum += num1[i] - '0';
                    i--;
                }
                if(j >= 0)
                {
                    sum += num2[j] - '0';
                    j--;
                }
    
                temp = (sum + flag) / 10;
                res += to_string((sum + flag) % 10);
                flag = temp;
            }
            int len = res.size();
            vector<int> output;
            for(int i = len - 1; i >= 0; --i)
            {
                output.push_back(int2str(res[i]));
            }
            return output;
        }
    
        int int2str(char s)
        {
            int i;
            stringstream ss;
            ss<<s;
            ss>>i;
            return i;
        }
    };
  29. 两个逆序list数字串相加

    给出两个list,存的是一串数字,这串数字是逆序存储的,计算着两组数字的和。

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)

    输出:7 -> 0 -> 8

    解释:342 + 465 = 807.

    /*
        思路:方法和之前如出一辙,只不过这次不需要先逆序,因为给定的就是逆序。也不需要字符串转数字,数字转字符串。但是要注意list的新节点定义。
    */
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            int flag = 0;
            int temp = 0;
            ListNode preHead(0);
            ListNode *p = &preHead;
            while(l1 || l2 || flag)
            {
                int sum = 0;
                if(l1)
                {
                    sum += l1->val;
                    l1 = l1->next;
                }
                if(l2)
                {
                    sum += l2->val;
                    l2 = l2->next;
                }
                temp = (sum + flag) / 10;
                p->next = new ListNode((sum + flag) % 10);
                flag = temp;
                p = p->next;
            }
            return preHead.next;
        }
    };
  30. 两个顺序list数字相加

    LeetCode 445

    和上一题相反,这一题给出的list是顺序的,需要我们先逆序操作,然后运用之前的方法。

    输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)

    输出: 7 -> 8 -> 0 -> 7

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            vector<int> num1;
            vector<int> num2;
    
            while(l1)
            {
                num1.push_back(l1->val);
                l1 = l1 -> next;
            }
    
            while(l2)
            {
                num2.push_back(l2->val);
                l2 = l2 -> next;
            }
            int flag = 0;
            int i = num1.size()-1;
            int j = num2.size()-1;
            int temp = 0;
            vector<int> res;
            ListNode preHead(0);
            ListNode *p = &preHead;
    
            while(i >=0 || j >= 0 || flag)
            {
                int sum = 0;
                if(i >= 0)
                {
                    sum += num1[i];
                    i--;
                }
                if(j >= 0)
                {
                    sum += num2[j];
                    j--;
                }
                temp = (sum + flag) / 10;
                res.push_back((sum + flag) % 10);
                flag = temp;
            }
    
            for(int k = res.size() - 1; k >= 0; --k)
            {
                p->next = new ListNode(res[k]);
                p = p -> next;
            }
            return preHead.next;
        }
    };
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值