第三十八天:回文数组
回文数组
一、问题
小蓝随机生成了一个长度为 n
的整数数组,数组中的元素为 a1, a2, ⋯, an
。他希望将这个数组变成回文数组,即对于任意 i ∈ [1, n]
,都满足 ai = an - i + 1
。小蓝拥有两种操作方式:
- 可以指定相邻的两个数,将它们一起加
1
或减1
。 - 也可以只指定一个数加
1
或减1
。
我们的目标就是帮助小蓝找出最少需要操作多少次,才能把这个数组成功变成回文数组。
二、思路
- 核心思想:
-
遍历策略详解:
采用双指针法遍历数组的前半部分(当数组长度为奇数时,排除中间的孤立元素)。具体来说,初始化指针i = 0
和j = n-1
(其中n
为数组长度),在循环中逐对比较对称位置的元素arr[i]
和arr[j]
。例如,对于数组[3, 7, 1, 9, 5]
,我们会依次比较 (3,5)、(7,9) 这两对元素。 -
差值计算与处理:
对于每对对称元素,计算其数值差diff = arr[i] - arr[j]
的绝对值。当diff ≠ 0
时:-
常规对称对处理(当该对元素不是中间或紧邻中间时):
- 优先采用"相邻元素联动操作"策略:通过同时调整
arr[i+1]
和arr[j-1]
的值来消除差值。例如,若arr = [2, 4, 6, 8]
,处理第一对 (2,8) 时,可以同时增加arr[1]
和减少arr[2]
各 3 个单位。 - 计算最小操作次数
minOp = |diff| / 2
,并更新arr[i+1] -= minOp
和arr[j-1] += minOp
。 - 这种策略的优势在于:单次操作可以同时影响两个对称位置的值调整。
- 优先采用"相邻元素联动操作"策略:通过同时调整
-
中间对称对处理(当处理到数组中间或次中间位置时):
- 例如在数组
[1, 3, 5, 3, 1]
中,处理到第三对 (5,5) 时,或数组[4, 2, 2, 4]
处理到第二对 (2,2) 时。 - 此时由于缺乏相邻元素可供联动操作,只能直接累加差值绝对值到总操作次数。
- 操作示例:若
arr = [6, 3, 9]
,处理 (6,9) 时需要直接进行 3 次单元素操作。
- 例如在数组
-
-
边界条件处理:
- 当数组长度为奇数时,中间元素不需要处理(自然满足回文对称要求)。
- 对于长度为 1 的数组,直接返回 0 次操作。
- 在实现时需要注意索引边界,避免数组越界访问。
-
复杂度分析:
该算法只需单次遍历数组前半部分,时间复杂度为 O(n/2) 即 O(n)。空间复杂度为 O(1),仅需常数个额外变量存储操作计数和临时差值。
三、C++ 代码实现
#include <iostream>
#include <vector>using namespace std;int minOperationsToPalindrome(vector<int>& nums) {int n = nums.size();int operations = 0;for (int i = 0; i < n / 2; ++i) {int diff = nums[i] - nums[n - i - 1];if (diff != 0) {if (i < n - i - 2) {int minOp = abs(diff);operations += minOp;nums[i] += diff > 0? -minOp : minOp;nums[n - i - 1] += diff > 0? minOp : -minOp;} else {operations += abs(diff);}}}return operations;
}int main() {int n;cin >> n;vector<int> nums(n);for (int i = 0; i < n; ++i) {cin >> nums[i];}int result = minOperationsToPalindrome(nums);cout << result << endl;return 0;
}
四、代码解读
-
函数定义与初始化:
minOperationsToPalindrome
函数是一个专门设计用于解决数组回文化问题的工具函数。它的核心功能是计算将任意给定的整数数组nums
转变为回文数组所需的最少操作次数。这里的"操作"特指对数组元素进行加1或减1的调整。- 在函数开始时,首先通过
nums.size()
获取数组的长度n
,这为后续的对称元素遍历提供了边界依据。同时初始化一个整型变量operations
并设为0
,这个变量将作为累加器,精确记录整个转换过程中所需的所有操作步骤总数。例如,对于数组[1, 2, 3]
,初始时operations
为0。
-
遍历数组:
- 采用经典的
for
循环结构来遍历数组的前半部分,循环变量i
从索引0
开始,以步长1
递增,直到达到n / 2
为止。这种设计确保了我们能处理数组中所有对称的元素对。比如对于长度为5的数组,会遍历索引0-1(对应索引4-3);对于长度为4的数组,则遍历索引0-1(对应索引3-2)。这种对称遍历方式正是处理回文问题的关键。
- 采用经典的
-
处理对称元素:
- 在每次循环中,首先计算当前对称元素对
nums[i]
和nums[n - i - 1]
的差值diff
。这个差值直接反映了这对元素当前的不对称程度。例如,当nums[i] = 3
而nums[n-i-1] = 5
时,diff = -2
。 - 当
diff
为0时,表明这对元素已经满足回文要求,可以直接跳过本次循环。这种优化避免了不必要的计算。 - 当
diff
不为0时,根据元素在数组中的位置关系采取不同的处理策略:- 可优化操作的情况(
i < n - i - 2
):这种情况通常出现在数组的前半部分。通过计算最小操作次数minOp = abs(diff)
,并同时调整当前元素和下一个相邻元素的值。例如,若nums = [1, 3, 5, 2]
,处理第一对元素(1,2)时,可以同时操作第二对元素(3,5)来减少总操作次数。 - 必须单独操作的情况(
i >= n - i - 2
):这种情况出现在数组的中间位置附近。此时只能通过直接调整当前元素的值来达到对称要求。比如对于数组[1, 2, 3]
的中位元素2,必须单独调整。
- 可优化操作的情况(
- 在每次循环中,首先计算当前对称元素对
-
主函数:
- 在
main
函数中,首先通过标准输入读取一个整数n
,表示待处理数组的长度。例如输入"4"表示要处理一个4元素的数组。 - 接着动态创建一个大小为
n
的向量容器nums
,通过一个循环结构逐个读取数组元素。比如依次输入"1 2 3 4"会填充到向量中。 - 最后调用核心函数
minOperationsToPalindrome
进行计算,并将得到的操作次数通过标准输出显示。例如输出"3"表示需要3次操作才能使数组成为回文。这个输出结果可以直接用于算法验证或后续处理。
- 在