青训营X豆包MarsCode 技术训练396题 | 豆包MarsCode AI刷题

101 阅读5分钟

该题目为:小J的字母矩阵问题,描述如下 小R拿到了一个 nn 行 mm 列的小写字母矩阵,她想知道有多少个子矩阵满足以下条件:每个字母在这个子矩阵中最多出现一次。 思路就是,我们可以使用滑动窗口和位运算的结合。具体步骤如下:

  1. 预处理:将每个字符映射到一个唯一的位表示。例如,'a' 映射到 1 (000...001),'b' 映射到 2 (000...010),'c' 映射到 4 (000...100),依此类推。这样,我们可以使用一个整数来表示一个子矩阵中出现的所有字符。
  2. 滑动窗口:对于每一列,我们使用滑动窗口来计算以该列为右边界的子矩阵。具体来说,我们维护一个位掩码 mask,表示当前窗口内出现的所有字符。如果 mask 中某一位重复出现,则说明当前窗口内的子矩阵不满足条件,需要移动左边界以移除重复的字符。
  3. 计数:对于每一个有效的子矩阵,我们记录其面积,并累加到结果中。 用代码来描述:
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>

int solution(int n, int m, std::vector<std::string> s) {
    int count = 0;

    // 遍历所有可能的子矩阵的左上角和右下角
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            for (int k = i; k < n; ++k) {
                for (int l = j; l < m; ++l) {
                    // 检查当前子矩阵是否满足条件
                    std::unordered_set<char> uniqueChars;
                    bool isValid = true;
                    for (int x = i; x <= k; ++x) {
                        for (int y = j; y <= l; ++y) {
                            if (uniqueChars.find(s[x][y]) != uniqueChars.end()) {
                                isValid = false;
                                break;
                            }
                            uniqueChars.insert(s[x][y]);
                        }
                        if (!isValid) break;
                    }
                    if (isValid) count++;
                }
            }
        }
    }

    return count;
}

int main() {
    std::cout << (solution(2, 3, {"aad", "abc"}) == 13) << std::endl;
    std::cout << (solution(3, 3, {"abc", "def", "ghi"}) == 36) << std::endl;
    std::cout << (solution(4, 4, {"abcd", "efgh", "ijkl", "mnop"}) == 100) << std::endl;
}

知识点:

  1. 位运算:通过位运算可以高效地表示和操作集合。例如,使用一个整数的每一位来表示一个字符是否出现在子矩阵中。
  2. 滑动窗口:滑动窗口是一种常用的优化技巧,适用于需要在连续子序列中查找满足某些条件的问题。
  3. 二维数组的预处理:将原始数据转换为便于后续处理的形式,可以简化问题的解决过程。

自己的理解和建议

  • 位运算的灵活性:位运算不仅可以用于集合操作,还可以用于状态压缩等高级技巧。掌握位运算的基本操作(如按位与、按位或、按位异或等)对于解决复杂问题非常有帮助。
  • 滑动窗口的适用性:滑动窗口适用于需要在连续子序列中查找满足某些条件的问题。通过维护一个窗口内的状态,可以避免重复计算,提高算法效率。
  • 预处理的重要性:预处理可以将原始数据转换为更易于处理的形式,减少后续计算的复杂度。在解决复杂问题时,预处理往往能起到事半功倍的效果。

制定计划

  1. 确定目标:明确自己的学习目标,比如在一定时间内掌握某种算法或数据结构。
  2. 选择题库:选择合适的题库,如LeetCode、Codeforces等,这些平台提供了丰富的题目和详细的题解。
  3. 制定计划:根据自己的时间和能力,合理安排每天需要解决的问题数量。初期可以选择一些基础题型,随着技能的提升逐渐挑战更难的题目。

利用错题进行针对性学习

  1. 记录错题:将每次刷题中做错的题目记录下来,分析错误原因。
  2. 定期复习:定期回顾错题,确保自己真正理解了错误的原因,并能正确解决这些问题。
  3. 拓展学习:对于错题中涉及的知识点,可以查阅相关资料或参加线上课程,进行深入学习。
  4. 在线课程:参加Coursera、edX等平台上的编程课程,系统学习算法和数据结构。
  5. 技术社区:加入GitHub、Stack Overflow等技术社区,与他人交流解题思路,共同进步。
  6. 书籍:阅读《算法导论》、《编程珠玑》等经典书籍,深入理解算法原理。

AI 刷题功能的优势

  1. 个性化推荐:AI刷题功能根据用户的学习情况智能推荐适合的题目,帮助用户高效地提升编程能力。
  2. 详细解析:每道题目都提供了详细的解题思路和代码示例,帮助用户快速理解解题方法。
  3. 实时反馈:提交答案后,AI刷题功能会立即给出反馈,指出错误并提供改进建议,帮助用户及时纠正错误。 通过使用豆包MarsCode AI刷题功能,我在编程学习的道路上取得了显著的进步。AI刷题功能不仅帮助我高效地掌握编程思维,还在知识掌握程度上带来了显著的提升。通过与同学的互动和竞争,我感受到了团队合作的力量,同时也深刻认识到AI技术在教育领域的巨大潜力。未来,我将继续利用这一强大的工具,不断探索和学习,为实现自己的梦想而努力。希望我的经验能对其他学习编程的同学有所帮助,让我们一起在编程的世界里不断前行。