Files
leetcode-master/problems/kamacoder/0121.小红的区间翻转.md
programmercarl 2d9604baa5 Update
2024-07-26 11:35:38 +08:00

3.1 KiB
Raw Blame History

121. 小红的区间翻转

比较暴力的方式,就是直接模拟, 枚举所有 区间,然后检查其翻转的情况。

在检查翻转的时候,需要一些代码优化,否则容易超时。

#include <iostream>
#include <vector>
using namespace std;

bool canTransform(const vector<int>& a, const vector<int>& b, int left, int right) {
    // 提前检查翻转区间的值是否可以匹配
    for (int i = left, j = right; i <= right; i++, j--) {
        if (a[i] != b[j]) {
            return false;
        }
    }
    // 检查翻转区间外的值是否匹配
    for (int i = 0; i < left; i++) {
        if (a[i] != b[i]) {
            return false;
        }
    }
    for (int i = right + 1; i < a.size(); i++) {
        if (a[i] != b[i]) {
            return false;
        }
    }
    return true;
}

int main() {
    int n;
    cin >> n;

    vector<int> a(n);
    vector<int> b(n);

    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }

    int count = 0;

    // 遍历所有可能的区间
    for (int left = 0; left < n; left++) {
        for (int right = left; right < n; right++) {
            // 检查翻转区间 [left, right] 后a 是否可以变成 b
            if (canTransform(a, b, left, right)) {
                count++;
            }
        }
    }
    cout << count << endl;
    return 0;
}

也可以事先计算好,最长公共前缀,和最长公共后缀。

在公共前缀和公共后缀之间的部分进行翻转操作,这样我们可以减少很多不必要的翻转尝试。

通过在公共前缀和后缀之间的部分,找到可以通过翻转使得 a 和 b 相等的区间。

以下 为评论区 卡码网用户码鬼的C++代码

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }

    vector<int> prefix(n, 0), suffix(n, 0);
    
    // 计算前缀相等的位置
    int p = 0;
    while (p < n && a[p] == b[p]) {
        prefix[p] = 1;
        p++;
    }

    // 计算后缀相等的位置
    int s = n - 1;
    while (s >= 0 && a[s] == b[s]) {
        suffix[s] = 1;
        s--;
    }

    int count = 0;

    // 遍历所有可能的区间
    for (int i = 0; i < n - 1; i++) {
        for (int j = i + 1; j < n; j++) {
            // 判断前缀和后缀是否相等
            if ((i == 0 || prefix[i - 1] == 1) && (j == n - 1 || suffix[j + 1] == 1)) {
                // 判断翻转后的子数组是否和目标数组相同
                bool is_palindrome = true;
                for (int k = 0; k <= (j - i) / 2; k++) {
                    if (a[i + k] != b[j - k]) {
                        is_palindrome = false;
                        break;
                    }
                }
                if (is_palindrome) {
                    count++;
                }
            }
        }
    }

    cout << count << endl;

    return 0;
}