C++ 在交换某些字符后具有最大数量的给定子字符串的字符串?

C++ 在交换某些字符后具有最大数量的给定子字符串的字符串?,c++,string,algorithm,C++,String,Algorithm,所以,这是我正在经历的一个面试问题 我有字符串a、b和c。我想通过交换a中的一些字母来获得字符串k,这样k应该包含尽可能多的非重叠子字符串,这些子字符串等于b或c。字符串x的子字符串是由x中的连续字符段组成的字符串。如果字符串x中存在位置i,则字符串x的两个子字符串重叠 输入:第一行包含字符串a,第二行包含字符串b,第三行包含字符串c(1 ≤ |a |, |b |, |c| ≤ 10^5,其中| s |表示字符串s的长度) 所有三个字符串仅由小写英文字母组成 b和c可能重合 输出:找到一个可能的

所以,这是我正在经历的一个面试问题

我有字符串
a、b和c
。我想通过交换
a
中的一些字母来获得字符串
k
,这样
k
应该包含尽可能多的非重叠子字符串,这些子字符串等于
b
c
。字符串
x
的子字符串是由
x
中的连续字符段组成的字符串。如果字符串
x
中存在位置
i
,则字符串
x
的两个子字符串重叠

输入:第一行包含字符串a,第二行包含字符串b,第三行包含字符串c(1 ≤ |a |, |b |, |c| ≤ 10^5,其中| s |表示字符串s的长度)

所有三个字符串仅由小写英文字母组成

b和c可能重合

输出:找到一个可能的字符串k

Example: 
I/P 
abbbaaccca
ab
aca

O/P
ababacabcc
this optimal solutions has three non-overlaping substrings equal to either b or c on positions 1 – 2 (ab), 3 – 4 (ab), 5 – 7 (aca).
现在,我能想到的方法是为每个字符串创建一个字符计数数组,然后继续。基本上,迭代原始字符串(a),检查是否出现b和c。如果没有,则交换尽可能多的字符以生成b或c(以较短者为准)。但是,这显然不是最佳方法。 有人能提出更好的建议吗?(只有伪代码就足够了)
谢谢

假设允许的字符具有ASCII代码0-127,我将编写一个函数来计算字符串中每个字符的出现次数:

int[] count(String s) {
    int[] res = new int[128];
    for(int i=0; i<res.length(); i++)
        res[i] = 0;
    for(int i=0; i<a.length(); i++)
        res[i]++;
    return res;
}
然后,我们可以编写一个函数来计算一个字符串可以从另一个字符串的字符中分割出多少次:

int carveCount(int[] strCount, int[] subStrCount) {
    int min = Integer.MAX_VALUE;
    for(int i=0; i<subStrCount.length(); i++) {
        if (subStrCount[i] == 0)
            continue;
        if (strCount[i] >= subStrCount[i])
            min = Math.min(min, strCount[i]-subStrCount[i]);
        else {
            return 0;
        }
    }
    for(int i=0; i<subStrCount.length(); i++) {
        if (subStrCount[i] != 0)
            strStrCount[i] -= min;
    }
    return min;
}
编辑:我不知道你想要所有的角色最初都在一个,在这里修复

最后,要产生输出:

StringBuilder sb = new StringBuilder();
for(int i=0; i<bFitCount; i++) {
    sb.append(b);
for(int i=0; i<cFitCount; i++) {
    sb.append(c);
for(int i=0; i<aCount.length; i++) {
    for(int j=0; j<aCount[i]; j++) 
        sb.append((char)i);
}
return sb.toString();
StringBuilder sb=新建StringBuilder();

对于(int i=0;i来说,首先要做的是计算每个字符串中每个字符的出现次数。
a
的出现次数将是您的背包,您需要用尽可能多的
b
c
填充它们

请注意,当我说背包时,我指的是a的字符计数向量,而将
b
插入
a
将意味着将
a的字符计数向量减少
b的字符计数向量。
我的数学证明有点短,但你需要

  • 在背包中插入尽可能多的
    b

  • 在背包中插入尽可能多的
    c
    (在1之后的空白处)

  • 如果从背包中移除a
    b
    将允许插入更多的
    c
    ,则从背包中移除
    b
    。否则,完成

  • 将尽可能多的
    c
    填充到背包中

  • 重复3-4次

  • 在整个程序中,计算背包中b和c的数量,输出应为:

    [b_count times b][c_count times c][char_occurrence_left_in_knapsack_for_char_x times char_x for each char_x in lower_case_english]
    

    这将解决O(n)处的问题。

    称为相关问题。 这基本上就是@Tal Shalti所描述的解决方案。 我尽量让每件事都可读

    我的程序将
    abbcabacac
    作为出现次数最多的字符串之一返回(3)

    为了在不重复排列的情况下获得所有排列,我使用
    算法中的
    std::next_permutation
    。主函数中没有太多变化。我只存储出现次数和排列,如果出现次数更多

    int main()
    {
        std::string word = "abbbaaccca";
        std::string patternSmall = "ab";
        std::string patternLarge = "aca";
    
    
        unsigned int bestOccurrence = 0;
        std::string bestPermutation = "";
    
    
        do {
            // count and remove occurrence
            unsigned int occurrences = FindOccurences(word, patternLarge, patternSmall);
    
            if (occurrences > bestOccurrence) {
                bestOccurrence = occurrences;
                bestPermutation = word;
    
                std::cout << word << " .. " << occurences << std::endl;
            }
    
    
        } while (std::next_permutation(word.begin(), word.end()));
    
    
        std::cout << "Best Permutation " << bestPermutation << "  with " << bestOccurrence << " occurrences." << std::endl;
    
        return 0;
    }
    
    此函数返回找到的模式的第一个位置。如果未找到该模式,
    std::string::npos
    string返回。find(…)
    。另外
    string.find(…)
    开始搜索从索引
    i
    开始的模式

    bool FindPattern(const std::string& word, const std::string& pattern, std::string::size_type& i)
    {
          std::string::size_type foundPosition = word.find(pattern, i);
    
          if (foundPosition == std::string::npos) {
             return false;
          }
    
          i = foundPosition;
    
         return true;
    }
    

    您提供的代码有很多错误。第三条语句,what is
    y
    ?另外,在函数
    carveCount
    中,what is
    Subcount
    。这些都是可以忽略的错误,但是,根据您的逻辑,首先检查短字符串(b或c)的最大出现次数看看它能被刻多少次,然后检查是否有更长的字符串。然后加上两个,对吗?对不起,我在手机上写的,无法测试。如果目的是最大化总和(b+c的外观),那么是第二个问题,那么我相信您需要在
    Findoccurences
    函数中刻出最短的第一个,当您使用
    unsigned int finish=pattern1.size()+pattern2.size()-1;std::string strSub=tmpWord.substr(I,finish)获得相关子字符串时,我并没有真正得到该部分
    。我的意思是,finish在这里代表什么?你能再详细一点吗?这是我代码中的一个错误。我试图得到pattern1周围可以与pattern2重叠的区域。所以我从pattern1的开头开始,走pattern1
    pattern1的距离。size()
    ,返回一个字符
    -1
    ,然后返回模式2的距离
    pattern2.size()
    。但是忘记了,我更改了代码的(d)部分。
    int main()
    {
        std::string word = "abbbaaccca";
        std::string patternSmall = "ab";
        std::string patternLarge = "aca";
    
    
        unsigned int bestOccurrence = 0;
        std::string bestPermutation = "";
    
    
        do {
            // count and remove occurrence
            unsigned int occurrences = FindOccurences(word, patternLarge, patternSmall);
    
            if (occurrences > bestOccurrence) {
                bestOccurrence = occurrences;
                bestPermutation = word;
    
                std::cout << word << " .. " << occurences << std::endl;
            }
    
    
        } while (std::next_permutation(word.begin(), word.end()));
    
    
        std::cout << "Best Permutation " << bestPermutation << "  with " << bestOccurrence << " occurrences." << std::endl;
    
        return 0;
    }
    
    unsigned int FindOccurrences(const std::string& word, const std::string& pattern1, const std::string& pattern2)
    {
        unsigned int occurrenceCounter = 0;
    
        std::string tmpWord(word);
    
        // '-1' makes implementation of while() easier
        std::string::size_type i = -1;
    
        i = -1;
        while (FindPattern(tmpWord, pattern2, ++i)) {
            occurrenceCounter++;
            tmpWord.replace(tmpWord.begin() + i, tmpWord.begin() + i + pattern2.size(), "@@");
        }
    
        i = -1;
        while (FindPattern(tmpWord, pattern1, ++i)) {
            occurrenceCounter++;
            tmpWord.replace(tmpWord.begin() + i, tmpWord.begin() + i + pattern1.size(), "@@");
        }
    
        return occurrenceCounter;
    }
    
    bool FindPattern(const std::string& word, const std::string& pattern, std::string::size_type& i)
    {
          std::string::size_type foundPosition = word.find(pattern, i);
    
          if (foundPosition == std::string::npos) {
             return false;
          }
    
          i = foundPosition;
    
         return true;
    }