字符串问题汇总

数据结构和算法 专栏收录该内容
33 篇文章 1 订阅

http://v.youku.com/v_show/id_XMTQzMDA0MDI1Ng==.html?spm=a2hzp.8253869.0.0

NO1 求一个字符串中输出最长的无重复字符的子串。

 NO2  给定一个仅有小写字母构成的字符串,只能删除一些字符而不能修改字符串顺序,使得字符串中原先每种字符只出现一次并且字典序最小。

NO3  给定一个字符串,只包含左右括号( ),寻找最长的配对的子串并求其长度。比如”(()”最长配对是”()”,返回长度2;”)()()”最长配对子串是”()()”,返回长度4;

 

NO1 求一个字符串中输出最长的无重复字符的子串。

int LengthOfLongestSubString(string s)
{
    int answer = 0;
    vector<bool> hash(256, false);
    for (int i = 0, j = 0;; i++)
    {
        while (j < s.length() && !hash[s[j]])
        {
            hash[s[j++]] = true;
        }
        answer = max(answer, j - i);
        if (j >= s.length())
        {
            break;
        }
        while (s[i] != s[j])
        {
            hash[s[i++]] = false;
        }
        hash[s[i]] = false;
    }
    return answer;

}

2)方法二(要求将最长的子数组res显示出来!!!)

#include<stdio.h>  
#include<stdlib.h>  
#include<iostream>  
#include<queue>  
#include<climits>  
#include<cstring>  
using namespace std;
#define N 5 // N件宝贝  
#define V 10 // C是背包的总capacity  

vector<char> LengthOfLongestSubString(string s)
{
    int answer = 0;
    vector<char> maxs;
    vector<bool> hash(256, false);
    for (int i = 0, j = 0;; i++)
    {
        while (j < s.length() && !hash[s[j]])
        {
            hash[s[j++]] = true;
        }
        if ((j - i)>answer)
        {
            answer = j - i;
            int jj = j, ii = i;
            maxs.clear();
            while (ii < jj)
            {
                
                maxs.push_back(s[ii++]);
            }
        }
        if (j >= s.length())
        {
            break;
        }
        while (s[i] != s[j])
        {
            hash[s[i++]] = false;
        }
        hash[s[i]] = false;
    }
    return maxs;

}
int main() {
    string s = "cdec";
    vector<char> res = LengthOfLongestSubString(s);
    for (int i = 0; i < res.size(); i++)
    {
        cout << res[i] << " ";
    }

    
    system("pause");
    return 0;

}

方法3(显示出数组来)

int maxStr(string str, vector<string> &vec, string &res)//vec存储每个不重复的子数组;res存储最终的最长的子数组
{
    bool hashStr[256] = { false };
    int len = str.length();
    int maxRes = 0;
    for (int i = 0,j=0; i < len;)
    {
        string tmp = "";
        while ((hashStr[str[i]] != true)&&(i < len))
        {
            tmp += str[i];
            hashStr[str[i]] = true;
            i++;
        }
        tmp += '\0';
        vec.push_back(tmp);
        if ((i - j)>maxRes)
        {
            maxRes = (i - j);
            res = tmp;
        }
        //maxRes = max(maxRes, i - j);
        while (j != i)
        {
            hashStr[str[j++]] == false;
        }
        hashStr[str[j]] = false;
    }
    return maxRes;
}

int main() {
    string str = "abccwsx";
    vector<string> vec;
    string res;
    cout << maxStr(str, vec, res) << endl;
    system("pause");
    return 0;
}

 NO2  给定一个仅有小写字母构成的字符串,只能删除一些字符而不能修改字符串顺序,使得字符串中原先每种字符只出现一次并且字典序最小。

方法1   贪心的思路

string removeDuplicateLetters(string s)
{
    vector<int> num(26, 0);//i或者右边出现次数
    vector<bool> in(26, false);//是否在answer最终的字符串里
    for (int i = 0; i < s.length(); i++)
    {
        ++num[s[i]-'a'];
    }
    string answer = "";
    for (int i = 0, last = 0; i < s.length();)//挨个i判断是否要加到answer里面
    {
        int c = s[i] - 'a';
        if ((num[c] == 1) && (!in[c]))//如果只剩下最后一次并且没有在answer里面,那么就必需需要加到answer里面了
        {
            int x = -1;//x就是最小的字母
            for (int j = last; j <= i; ++j)//如果字符串前面有更小的字符没有加到answer里面,那就找出字典序最小的字母s[x]。
            {
                if ((!in[s[j] - 'a']) && ((x < 0) || (s[j] < s[x])))
                {
                    x = j;
                }
            }
            answer += s[x];
            in[s[x] - 'a'] = true;
            if (s[x] == s[i])
            {
                ++i;
            }
            last = x + 1;
        }
        else
        {
            --num[c];
            ++i;
        }
    }
    return answer;
}

方法2,利用堆栈结构,时间复杂度为o(n)

string removeDuplicateLetters(string s)
{
    vector<int> num(26, 0);//i或者右边出现次数
    vector<bool> in(26, false);//是否在answer最终的字符串里
    stack<char>st;//存储最终的字符串
    for (int i = 0; i < s.length(); i++)
    {
        ++num[s[i]-'a'];//确定每个字母的出现次数
    }
    string answer = "";
    for (int i = 0, last = 0; i < s.length();++i)
    {
        int c = s[i] - 'a';
        --num[c];//判断第i个字符,先要将其出现次数减去1
        if (!in[c])
        {
            while ((!st.empty()) && (st.top()>s[i]) && (num[st.top() - 'a']))//stack结构跟第i个字符比较,如果stack的头要大于第i个字符,那么就pop
            {
                in[st.top() - 'a'] = false;
                st.pop();
            }
            st.push(s[i]);
            in[c] = true;
        }
    }
    for (; !st.empty(); st.pop())
    {
        //answer += st.top();
        answer = st.top() + answer;//因为是反着,所以注意加法的前后顺序!!
    }
    return answer;        

}

NO3  给定一个字符串,只包含左右括号( ),寻找最长的配对的子串并求其长度。比如”(()”最长配对是”()”,返回长度2;”)()()”最长配对子串是”()()”,返回长度4;

int GetLongestMatch(string inputStr) {
    int maxLength = 0;  //记录最长的括号匹配长度
    int deep = 0;
    int start = -1;
    //适合处理右括号数大于左括号数
    for (int i = 0; i < inputStr.length(); i++) {
        char c = inputStr.at(i);
        if (c == '(') {
            deep++;
        }
        else {
            deep--;
            if (deep == 0) {
                maxLength = maxLength < (i - start) ? i - start : maxLength;
            }
            //右括号数大于左括号数  不连续 重新计数
            if (deep < 0){
                start = i;
                deep = 0;
            }
        }
    }
    deep = 0;
    start = inputStr.length();
    //适合处理左括号数大于右括号数
    for (int i = inputStr.length() - 1; i >= 0; i--) {
        char c = inputStr.at(i);
        if (c == ')') {
            deep++;
        }
        else {
            deep--;
            if (deep == 0) {
                maxLength = maxLength < (start - i) ? start - i : maxLength;
            }
            else if (deep < 0) {
                deep = 0;
                start = i;
            }
        }
    }
    return maxLength;

}

 

NO 4   仅由三个字母abc构成字符串,且字符串要求人以三个相邻元素不能相同,如acccba不合法,accbbaa合法。求满足长度为n的,且满足上述条件的字符串的个数有多少?

假定不考虑整数溢出,要求时间空间复杂度不高于O(N)

http://v.youku.com/v_show/id_XMTM5MDUxNDU1Mg==.html?spm=a2hzp.8253869.0.0

动态规划思路!!

#define INT_MAX 3000

int dp[INT_MAX][INT_MAX] = { 0 };
int ThreeMax(int n)
{
    dp[1][1] = 0;
    dp[1][0] = 3;
    for (int i = 2; i <= n; i++)
    {
        dp[i][0] = 2 * dp[i - 1][0] + 2 * dp[i - 1][1];//dp[i][0]代表前i个字符串最后两个字符不相同;dp[i][1]代表前i个字符串最后两个字符相同
        dp[i][1] = dp[i - 1][0] + 0 * dp[i - 1][1];
    }
    return dp[n][0] + dp[n][1];
}

所以方法改进为如下,降低了空间复杂度!

int ThreeMax2(int n)
{
    int dp1 = 0;
    int dp0 = 3;//dp0代表前i个字符串最后两个字符不相同;dp1代表前i个字符串最后两个字符相同
    for (int i = 2; i <= n; i++)
    {
        int tempdp0 = dp0;
        int tempdp1 = dp1;
        dp0 = 2 * tempdp0 + 2 * tempdp1;
        dp1 = tempdp0 + 0 * tempdp1;
    }
    return dp0 + dp1;

}

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值