27.移除数组中的相同元素
题干
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。返回 k。
前提知识
什么是原地修改?
如果不是原地修改的话,直接新建一个int[ ] 数组,将去重之后的元素放进这个新的数组中,然后返回这个数组即可,但现在题目要求不能新建数组,只能在原数组上修改,
vector 创建数组对象
vector<元素类型>数组对象名(数组长度)
尖括号中的类型名表示数组元素的类型,数组长度是一个表达式,表达式中可以包含变量,也可以为动态数组对象指定初值,但只能为所有的元素指定相同的初值,形式如下
vector<元素类型>数组对象名(数组长度,元素初值)
int x = 10;
vector<int>arr(x);
//指定初值
vector<int>arr(x,0);
//可以将vector<int>作为一种新的数据类型名,
引用传递
一般的函数调用过程中,使用实参来初始化形参,直接将实参的值传递给形参,一旦形参获得了值之后就会立刻与实参脱离关系,此后无论形参如何变化,都不会影响实参,如果要使子函数中对形参做出的更改对主函数中的实参有效,就需要用到 引用传递。
引用是一种特殊类型的变量,可以认为是另一个变量的别名,通过引用名访问变量与通过被引用的变量名访问变量的效果是一样的
int i,j;
int &ri = i;
j = 10;
ri = j; //相当与 i = j
解题思路
定义两个变量作为数组下标,fast和slow,fast依次与数组中每个元素比较,当数组中的元素值不等于目标值val时,让nums[slow]=nums[fast],然后slow自加,fast自加,具体实现代码如下:
class Solution
{
public:
int removeElement(vector<int>& nums, int val)
{
int fast, slow = 0;
while(fast < nums.size())
{
if(nums[fast] != val)
{
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return solw;
}
}
704.二分查找
题干
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
二分查找的基本框架
int binarySearch(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = left + (right - left) / 2; //为了防止溢出,化简后就等于1/2(right+left)
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
}
}
return ...;
}
在数组中寻找一个数,数组中所有元素都不同(基本的二分搜索应用)
算法基本框架如下:
int binarySearch(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 注意
while(left <= right) {
int mid = left + (right - left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意左边界收缩+1,排除mid这个点的元素
else if (nums[mid] > target)
right = mid - 1; // 注意右边界收缩-1,排除mid这个点的元素,避免搜索某些重复索引增加运行时间
}
return -1;
}
有序数组的平方
题干
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
解题思路
最直观的想法,莫过于:每个数平方之后,排个序,这种算法的时间复杂度是 O(n + nlogn)
双指针法
数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。此时,定义两个指针,i指向起始位置,j指向终止位置,定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
如果A[i] * A[i] < A[j] * A[j] 那么result[k- -] = A[j] * A[j]; 。
如果A[i] * A[i] >= A[j] * A[j] 那么result[k- -] = A[i] * A[i]; 。
此时的时间复杂度为O(n),相对于暴力排序的解法O(n + nlog n)还是提升不少的。
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
int k = A.size() - 1;
vector<int> result(A.size(), 0);
for (int i = 0, j = A.size() - 1; i <= j;)
{
if (A[i] * A[i] < A[j] * A[j]) {
result[k--] = A[j] * A[j];
j--;
}
else {
result[k--] = A[i] * A[i];
i++;
}
}
return result;
}
};
代码分析:
- 循环语句
for (int i = 0, j = A.size() - 1; i <= j;)
for(初始语句;表达式1;表达式2),int i = 0, j = A.size() - 1这一段都是初始语句,这种形式的写法省略了表达式3,在循环体中改变控制循环的条件
2. result[k- -]
result[k–]中会将首次的值赋给result[k],然后自减1,使指针指向下一个位置,因为 k-- 是后缀递减运算符,它会先返回 k 的当前值,再对 k 进行递减。