mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-08-06 09:29:56 +08:00
3.1 KiB
3.1 KiB
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;
}