class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
// for(int i =0;i<nums.size();i++){
// nums[i]= pow(nums[i],2);
// }
// sort(nums.begin(),nums.end());
// return nums;
int left = 0;
int right = nums.size()-1;
vector<int> res(nums.size());
int index = right;
while(left<=right){
if(nums[left]*nums[left] >= nums[right]*nums[right] ){
res[index--] = nums[left]*nums[left];
left++;
}
else{
res[index--] = nums[right]*nums[right];
right --;
}
}
return res;
}
};
好的,我会详细解释这段代码的逻辑,它使用了 双指针法 来实现原地修改数组,移除所有值等于 val
的元素。下面我们逐步分析每一行代码的作用:
代码:
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != val) {
nums[k] = nums[i]; // 将不等于 val 的元素移到前面
k++; // 更新下一个可以存放不等于 val 的位置
}
}
1. 外部循环:for (int i = 0; i < nums.size(); i++)
- 这里使用了一个
for
循环来遍历数组nums
中的每个元素。i
是当前遍历到的元素的索引。 i
从0
开始,直到nums.size()
(数组的大小),也就是遍历整个数组。
2. 检查当前元素是否等于 val
:if (nums[i] != val)
- 在每次遍历中,判断当前元素
nums[i]
是否不等于val
。 - 如果
nums[i] != val
,说明该元素应该保留在数组中。也就是说,这个元素不等于要移除的元素,我们希望它继续存在并移到数组的前面。 - 如果
nums[i] == val
,则跳过当前元素,不做任何操作,因为题目要求删除所有等于val
的元素。
3. 将符合条件的元素放到数组前面:nums[k] = nums[i];
- 当当前元素
nums[i]
不等于val
时,将它放到nums[k]
位置。 - 这里的关键在于
k
的作用,k
是指向数组中下一个可以放置有效元素的位置。也就是说,k
标记着数组中不等于val
的元素的个数,同时也指向下一个可以存放不等于val
元素的位置。 - 这样,所有不等于
val
的元素都会依次被放到数组的前k
个位置。
4. 更新 k
的值:k++;
k
每次加 1,意味着下一个符合条件的元素应该存放在nums[k]
的位置。- 这样,
k
会随着遍历逐渐增长,最终它的值表示数组中不等于val
的元素的数量。
整体流程:
-
初始化:
- 假设数组
nums = {3, 2, 2, 3, 4, 5}
,val = 3
。 - 初始化
k = 0
,表示可以放置第一个不等于val
的元素的位置。
- 假设数组
-
遍历数组:
- 第一次遍历:
i = 0
,nums[0] = 3
,它等于val
,所以跳过。 - 第二次遍历:
i = 1
,nums[1] = 2
,它不等于val
,所以将nums[1]
移到nums[0]
位置,nums
变成{2, 2, 2, 3, 4, 5}
,同时更新k = 1
。 - 第三次遍历:
i = 2
,nums[2] = 2
,它不等于val
,所以将nums[2]
移到nums[1]
位置,nums
变成{2, 2, 2, 3, 4, 5}
,同时更新k = 2
。 - 第四次遍历:
i = 3
,nums[3] = 3
,它等于val
,所以跳过。 - 第五次遍历:
i = 4
,nums[4] = 4
,它不等于val
,所以将nums[4]
移到nums[2]
位置,nums
变成{2, 2, 4, 3, 4, 5}
,同时更新k = 3
。 - 第六次遍历:
i = 5
,nums[5] = 5
,它不等于val
,所以将nums[5]
移到nums[3]
位置,nums
变成{2, 2, 4, 5, 4, 5}
,同时更新k = 4
。
- 第一次遍历:
-
结束遍历:
- 最终,数组的前
k
个位置保存了所有不等于val
的元素:nums = {2, 2, 4, 5, _, _}
,其中_
表示数组后面的部分不重要。 - 返回
k = 4
,即不等于val
的元素数量。
- 最终,数组的前
结果:
最终,数组 nums
被修改为 nums = {2, 2, 4, 5, _, _}
,返回 4
。
总结:
k
记录数组中不等于val
的元素数量。k
同时也指向下一个可以放置不等于val
元素的位置。- 通过
nums[k] = nums[i]
,我们将所有不等于val
的元素移到数组的前面,最终返回k
,表示有效元素的数量。 - 这种方式是 原地 修改数组,空间复杂度是
O(1)
,且时间复杂度是O(n)
,因为只需要一次遍历。
这种做法既高效又符合题目要求,不需要额外的空间来存储结果。
是的,result[index--] = leftSquare;
这一行的作用可以分解成以下两步:
result[index] = leftSquare;
:- 这里把
leftSquare
赋值给result[index]
,即将leftSquare
(当前左指针位置的平方值)存储到result
数组的当前位置。
- 这里把
index--
:index--
是自减操作,意味着在赋值之后,index
的值会减 1。这样,下一次存值时,index
会指向result
数组的前一个位置,从而实现从数组的尾部向前填充结果数组。
为什么这么做?
我们使用了 双指针法 从两端开始比较平方值,然后按降序的顺序(较大的平方值先放入结果数组)填充 result
数组。由于是从尾部开始填充,最终 result
数组会按照升序排列。
举个例子:
假设输入数组为 nums = [-4, -1, 0, 3, 10]
,目标是返回它们的平方并按升序排序。
初始状态:
nums = [-4, -1, 0, 3, 10]
left = 0 // 指向 -4
right = 4 // 指向 10
result = [0, 0, 0, 0, 0] // 初始结果数组,全为0
index = 4 // 从结果数组的最后一个位置开始
第一步:
leftSquare = (-4) * (-4) = 16
rightSquare = 10 * 10 = 100
- 由于
rightSquare
更大,将100
放入result[index]
,即result[4] = 100
,然后index--
变为3
,right--
变为3
。
第二步:
leftSquare = (-4) * (-4) = 16
rightSquare = 3 * 3 = 9
leftSquare
更大,将16
放入result[index]
,即result[3] = 16
,然后index--
变为2
,left++
变为1
。
第三步:
leftSquare = (-1) * (-1) = 1
rightSquare = 3 * 3 = 9
rightSquare
更大,将9
放入result[index]
,即result[2] = 9
,然后index--
变为1
,right--
变为2
。
第四步:
leftSquare = (-1) * (-1) = 1
rightSquare = 0 * 0 = 0
leftSquare
更大,将1
放入result[index]
,即result[1] = 1
,然后index--
变为0
,left++
变为2
。
第五步:
leftSquare = 0 * 0 = 0
rightSquare = 0 * 0 = 0
- 将
0
放入result[index]
,即result[0] = 0
,然后index--
变为-1
,循环结束。
最终结果:
result = [0, 1, 9, 16, 100]
总结:
result[index--] = leftSquare;
是一个复合操作,先将leftSquare
存入result[index]
,然后将index
减 1,使得下一次可以将值存入result
数组的前一个位置。- 这样做的目的是 从结果数组的后端向前填充,确保我们按照降序选择平方数填充,最终数组是升序的。