在处理有序数组平方排序问题时,最直观的暴力解法是先平方再排序,但这样会导致时间复杂度上升到O(n log n)。而双指针算法能够将时间复杂度优化到O(n),这是因为它充分利用了原始数组的有序特性。
对于一个非递减排序的整数数组,平方后的最大值只可能出现在数组的两端,这是由数学性质决定的:
这个观察是双指针算法的基础。我们可以用两个指针分别指向数组的首尾,比较它们的平方值,将较大的值放入结果数组的末尾,然后移动相应的指针。
算法具体步骤如下:
这种方法的优势在于只需要线性时间就能完成排序,不需要额外的排序步骤。
cpp复制class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
vector<int> res(n);
int left = 0, right = n - 1;
int pos = n - 1;
while (left <= right) {
int leftSquare = nums[left] * nums[left];
int rightSquare = nums[right] * nums[right];
if (leftSquare > rightSquare) {
res[pos--] = leftSquare;
left++;
} else {
res[pos--] = rightSquare;
right--;
}
}
return res;
}
};
指针初始化:
left从0开始,right从n-1开始pos初始化为n-1,表示结果数组从后往前填充循环条件:
while (left <= right)确保所有元素都被处理平方计算:
指针移动:
空数组输入:
单元素数组:
全正数/全负数数组:
零值处理:
该算法的时间复杂度为O(n),其中n是数组的长度。这是因为:
相比先平方再排序的O(n log n)方法,效率显著提高。
空间复杂度为O(n),因为:
提前计算平方值:
cpp复制int leftSquare = nums[left] * nums[left];
int rightSquare = nums[right] * nums[right];
避免在if-else中重复计算
使用递减运算符:
cpp复制res[pos--] = leftSquare;
合并赋值和递减操作
循环条件优化:
使用left <= right而非left < right确保处理所有元素
三指针法:
绝对值比较法:
分治法:
图像处理:
物理模拟:
机器学习:
指针越界:
平方溢出:
结果数组顺序错误:
遗漏元素:
完整测试应包含以下情况:
普通测试用例:
cpp复制[-4,-1,0,3,10] → [0,1,9,16,100]
边界测试用例:
特殊测试用例:
暴力法实现简单:
cpp复制vector<int> sortedSquares(vector<int>& nums) {
for (int& num : nums) {
num *= num;
}
sort(nums.begin(), nums.end());
return nums;
}
但时间复杂度为O(n log n),效率较低。
vector使用:
运算符重载:
引用传递:
Python示例:
python复制def sortedSquares(nums):
n = len(nums)
res = [0] * n
left, right = 0, n - 1
pos = n - 1
while left <= right:
left_sq = nums[left] ** 2
right_sq = nums[right] ** 2
if left_sq > right_sq:
res[pos] = left_sq
left += 1
else:
res[pos] = right_sq
right -= 1
pos -= 1
return res
Java示例:
java复制public int[] sortedSquares(int[] nums) {
int n = nums.length;
int[] res = new int[n];
int left = 0, right = n - 1;
int pos = n - 1;
while (left <= right) {
int leftSquare = nums[left] * nums[left];
int rightSquare = nums[right] * nums[right];
if (leftSquare > rightSquare) {
res[pos--] = leftSquare;
left++;
} else {
res[pos--] = rightSquare;
right--;
}
}
return res;
}
立方有序数组:
多维数据:
流式数据:
并行化实现:
内存优化:
缓存友好实现:
在实际编码面试中,理解并能够解释双指针算法的原理和实现细节至关重要。这不仅考察基本的编码能力,也考察对算法复杂度的理解和优化意识。