【问题标题】:Issues related to framing logic for RGB substring problem in c++与 c++ 中 RGB 子字符串问题的框架逻辑相关的问题
【发布时间】:2019-07-25 14:35:23
【问题描述】:

前几天我正在解决一个关于 RGB 子字符串的问题。问题是:

给定一个由 n 个字符组成的字符串 s,每个字符是 'R'、'G' 或 'B'。

你还得到一个整数 k。您的任务是更改初始字符串 s 中的最小字符数,以便在更改后会有一个长度为 k 的字符串,它是 s 的子字符串,也是无限字符串“RGBRGBRGB ...”的子字符串

例如输入字符串为BBBRR,k为2,则输出为3

如何解决这个问题?我想不出一个有效的算法来做同样的事情

【问题讨论】:

  • 你能发布你到目前为止的代码吗?
  • 不要试图提高效率,先找到有效的方法。它可以帮助将其分解为几个步骤:替换字母,比较字符串等。然后当您遇到特定方面时再回来。没有人一开始就写出 100% 高效的算法;)(至少我从来没有这样做过)
  • For example if the input string is BBBRR, the output is 3 与问题定义相比,这毫无意义。输出什么?这个字符串是哪个k
  • @SergeyA 抱歉,我错过了有关 k 的信息。对于此示例,k=2。我将编辑问题。
  • @ShadowMitia 当我问“如何解决这个问题?空间。这种约束需要更合乎逻辑的方法,我想这就是我失败的地方。哈哈!!无论如何,我发布了这个问题,以便这个社区可以帮助我提出一些想法。

标签: c++ string substring


【解决方案1】:

正如 SergeyA 提议的那样。我们首先尝试理解问题,然后逐步解决。然后我们编写代码。好的。

所以,前几天,我正在解决交给你的问题。

  1. 首先,我们有一个包含随机字符“R”、“B”、“G”的字符串。
  2. 然后我们有 RGBRGBRGB 的序列...
  3. 我们想找到一个给定长度的子字符串
  4. 我们必须找到 RGBRGBRGB... 字符串的子字符串
  5. 然后我们需要将其与随机字符串进行比较,并检查随机字符串中某个位置的最小必要字符更改(或最大相同字符)

从 4. 我们了解到,结果必须是 RGBRGBRGB... 字符串的子字符串。所以我们正在寻找一个 RGBRGBRGB... 部分。这是解决问题的关键。

由于子字符串可以在 RGBRGBRGB 中的任何位置开始...如果我们不知道 RGB 的周期性重复,我们将需要做很多工作。所以,我们需要找到一个 RGBRGBRGB...、GBRGBRGB... 或 BRGBRGB... 的子字符串,子字符串长度为 k。

所以我们计划进行 3 次比较运行,分别为 1.RGBRGBRGB...、2.GBRGBRGB...和 ​​3.BRGBRGB...

接下来,我们执行一个循环,比较随机字符源字符串中的 k 个元素,并将其与其中一个周期性字符串进行比较。我们将从位置 1 开始,然后是位置 2,依此类推。

当我们进行了至少 k 次比较时,我们计算相等字符的总和。如果这个和大于前一个,那么我们找到了一个新的最大值并将其存储。

等等等等。

复杂度大约是 3*sizeof(input string)

我只需要一些额外的内存用于计数器(计数:sizeof 子字符串长度)。

请查看大约 35 行代码。到目前为止我还没有优化。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>


constexpr size_t SubStringSize = 6U;
const std::string testInput{ "RRRGBGBGGGBBRRRBGGBRGBGRRRGBBGRGGBBGRRBGRBBGGRGRGRGGRBRBGRRBGRGGBBGGBGBGBBBGGBBRBBRGRGGBRRR" };

const std::string rgbSourceCharacters("RGBRG");
inline char getRGB(size_t shift, size_t offset)
{
    return rgbSourceCharacters[shift + offset % 3U];
}

int main()
{
    // Some test string
    const size_t size = testInput.size();

    // Delta between Strings with RGBRGBRGB..... and testInput String
    std::vector<size_t> delta(SubStringSize);

    // This is the number of maxEquals for the given SubString Size
    size_t maxEquals{ 0U };

    // Position of char of best fitting substring
    size_t lastMaxEqualsPos{ 0U };
    // Which rgb sequence corresponds to ´best fitting substring
    size_t rgbShiftForMax{ 0U };

    // Check all possible RGB sequences, RGBRGBRGB... , GBRGBRGB..., BRGBRGB...
    for (size_t i = 0U; i < 3U; ++i)
    {
        // Set all values of our counters to 0
        std::fill(delta.begin(), delta.end(), 0U);

        // We will always begin with writing to the first position of the delta vector
        size_t indexInDeltaVector{ 0U };

        // Iterate over all characters of the source string
        for (size_t k = 0U; k < size; ++k)
        {
            // Check if the character is equal to RGB sequence, RGBRGBRGB... , GBRGBRGB..., BRGBRGB...
            delta[indexInDeltaVector] = (testInput[k] == getRGB(i,k)) ? 1U : 0U;
            // Increment index in delta vector, only until last position. Then stop
            if (indexInDeltaVector < (SubStringSize - 1U)) 
                ++indexInDeltaVector;
            // If we compared enough values
            else {
                // Calculate the sum of the previous n comparisons
                const size_t sum = std::accumulate(delta.begin(), delta.end(), 0U);
                // Check, if we found a new maximum
                if (sum > maxEquals) {
                    // If so then store relevant data
                    maxEquals = sum;
                    lastMaxEqualsPos = k - SubStringSize + 1U;
                    rgbShiftForMax = i;
                }
                // Make space for nect comparison
                std::rotate(delta.begin(), delta.begin() + 1U, delta.end());
            }
        }
    }
    // Show result
    std::cout << "\n\nFinal Result\n\nSource String:\n\n" << "0123456789012345678901234567890123456789012345678901234567890\n" << testInput
        << "\n\nSubstring Length:  " << SubStringSize
        << "\nMax Equals:        " << maxEquals
        << "\nTo be changed:     " << SubStringSize - maxEquals
        << "\n\nSub String at pos: " << lastMaxEqualsPos
        << "\n\n--> " << testInput.substr(lastMaxEqualsPos, SubStringSize)
        << "\n--> "; 
    for (size_t offset = lastMaxEqualsPos; offset < lastMaxEqualsPos + SubStringSize; ++offset)
        std::cout << getRGB(rgbShiftForMax, offset);
    std::cout << '\n';

    return 0;
}

第一轮优化。将代码的功能行数减少到 ~20 行:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>

constexpr size_t SubStringSize = 6U;
constexpr std::string_view testInput{ "RRRGBGBGGGBBRRRBGGBRGBGRRRGBBGRGGBBGRRBGRBBGGRGRGRGGRBRBGRRBGRGGBBGGBGBGBBBGGBBRBBRGRGGBRRR" };

int main()
{
    // Delta between Strings with RGBRGBRGB..... and testInput String
    std::vector<size_t> delta(SubStringSize);

    // This is the result, the number of minDifferences for the given SubString Size
    size_t minDifference{ SubStringSize };

    // Check all possible RGB sequences, RGBRGBRGB... , GBRGBRGB..., BRGBRGB...
    for (size_t i = 0U; i < 3U; ++i)
    {
        // Set all values of our counters to 0
        std::fill(delta.begin(), delta.end(), 0U);

        // We will always begin with writing to the first position of the delta vector
        size_t indexInDeltaVector{ 0U };

        // Iterate over all characters of the source string
        for (size_t k = 0U; k < testInput.size(); ++k) {

            // Check, if the char is equal to RGB sequence, RGBRGBRGB... , GBRGBRGB..., BRGBRGB...
            delta[indexInDeltaVector] = (testInput[k] == "RGBRG"[k % 3U + i]) ? 0U : 1U;

            // Increment index in delta vector, only until last position. Then stop
            if (indexInDeltaVector < (SubStringSize - 1U))
                ++indexInDeltaVector;
            // If we compared enough values
            else {
                // Calculate the sum of the previous n comparisons
                const size_t sum = std::accumulate(delta.begin(), delta.end(), 0U);

                // Check, if we found a new minimum
                if (sum < minDifference) 
                    // If so then store relevant data
                    minDifference = sum;

                // Make space for next comparison
                std::rotate(delta.begin(), delta.begin() + 1U, delta.end());
            }
        }
    }
    // Show result
    std::cout << "\n\nFinal Result. Minimum characters to be changed: " << minDifference << '\n';

    return 0;
}

【讨论】:

    猜你喜欢
    • 2013-11-16
    • 2021-12-21
    • 2022-01-05
    • 2020-08-24
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多