数组专题
- 一:二分法
- 二:移除元素
- 题目一:[移除元素](https://leetcode.cn/problems/remove-element/)
- 题目二:[删除有序数组的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)
- 题目三:[移动零元素](https://leetcode.cn/problems/move-zeroes/)
- 题目四:[比较含退格元素的字符串](https://leetcode.cn/problems/backspace-string-compare/submissions/484737131/)
- 题目五:[有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/submissions/484819040/)
- 长度最小的子数组
一:二分法
基础解法(略)参考代码随想录
题目:求x的平方根
链接:求x的平方根
可以使用二分法:
1.大体思想:x的平方根(保留整数)就是k2<=x,k的最大值
利用二分法求这个k的最大值
2.与基础二分法的变动:
因为要找出k的最大值,所以应该创建一个ans来储存更新k的最大值
二:移除元素
题目一:移除元素
1.相向双指针法:
出现的错误:
起初的方法:
while(left < right)
{
while(nums[left] != val) left++;
nums[left] = nums[right];
right--;
}
return left;
上面代码的错误在于left的while循环,如果数组中没有val元素,数组可能越界访问出现错误
改错后:
int left = 0;int right = nums.size()-1;
while(left < right)//错误在这
{
if(nums[left] == val)
{
nums[left] = nums[right-1];
right--;
}
else
{
left++;
}
}
return left;
上面while循环的判断条件有错误,应该是left<=right
但是这样写会发现它的运行时间很长 8ms,只超过20%的人
但是做一个小改动
int right = nums.size();//这里
while(left < right)//这里
{
if(nums[left] == val)
{
nums[left] = nums[right];//这里
right--;
}
}
提交会发现运行时间为 0 ms,提升了很多
所以以后在遇到双指针的问题是,尽量把后面的指针设置 nums.size();
2.快慢指针法:
本题也可以使快慢指针法
int slow = 0;
for(int fast = 0;fast < nums.size();fast++)
{
//slow not val
if(nums[fast]!=val)
{
nums[slow++] = nums[fast];
}
}
return slow;
总结以下就是:快指针一直前进,如果指向的值不等于val就把慢指针指向的值改为快指针指向的
题目二:删除有序数组的重复项
初始代码:
int n = nums.size();
if(n==0) return 0;
int slow = 0;
for(int fast = 0;fast < nums.size();fast++)
{
if(nums[fast] != nums[slow])
{
nums[slow++] = nums[fast];
}
}
return slow+1;
这个的错误原因在于 nums[slow++] = nums[fast]
这种写法可能出现的情况:
数组 1 2 2 3
删除后:第一个元素为 2,因为slow是后缀++
应该改为前缀++
变式:
上面for循环的第一层一直是成立的,可以把第一层for循环简化,即slow和fast都从1开始,此时不能比较
~~~~~~~~
nums[slow++] = nums[fast]
所以比较: nums[fast] = nums[fast - 1]
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int index = 1;
int len = nums.size();
for(int i = 1; i < len; i++)
{
if(nums[i] != nums[i - 1])
{
nums[index++] = nums[i];
}
}
return index;
}
};
题目三:移动零元素
int slow = 0;
for(int fast = 1;fast < nums.size();fast++)
{
if(nums[slow]!=0) slow++;
else if(nums[fast] != 0&& nums[slow]==0)
{
int temp = nums[fast];
nums[fast] = nums[slow];
nums[slow] = temp;
slow++;
}
}
这个题与前面的题相差不大,做题的时候第一遍就过了。就不细说了
题目四:比较含退格元素的字符串
方法一:双指针法:
fast指针遇到非#元素,则:s[slow++] = s[fast++]
遇到 # :则slow后退一位:slow–
int change(string &s)
{
int slow = 0,fast = 0;
while(fast < s.length())
{
if(s[fast] != '#')
{
s[slow++] = s[fast++];
}
else
{
slow--;
fast++;
}
if(slow < 0) slow = 0;
}
return slow;
}
bool backspaceCompare(string s, string t) {
int ls = change(s);
int lt = change(t);
if(ls != lt) return false;
for(int i = 0;i < ls;i++)
if(s[i] != t[i]) return false;
return true;
方法二:借助栈
如果是非#则压栈,#则将栈顶弹出
题目五:有序数组的平方
方法一:双指针法
(1)找到中间绝对值最小元素,向两侧延伸
(2)从两侧向中间遍历 (比较简便)
int left = 0,right = nums.size()-1;
int n = right;
vector<int>ans(n+1);
while(left <= right)
{
if(nums[left]*nums[left] <= nums[right]*nums[right])
{
ans[n--] = nums[right]*nums[right];
right--;
}
else
{
ans[n--] = nums[left]*nums[left];
left++;
}
}
return ans;
方法二:各种排序
用到的时候再复习
长度最小的子数组
题目一 :长度最小的子数组
方法一:滑动窗口法:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//滑动窗口
int sum = 0;
int result = INT32_MAX;
int winl = 0;
for(int i = 0,j = 0;j < nums.size();j++)
{
sum += nums[j];
while(sum >= target)
{
winl = j-i+1;
result = min(winl,result);
sum -= nums[i];//前窗口向前移动,如果大于target则继续向前,如果小于,也没问题,因为已经把result记录了
i++;
}
}
return result==INT32_MAX ? 0 : result;
}
};
注意:
这里的for中 j 代表的是后指针,如果循环 i 指针最终效果和暴力算法是一样的
滑动窗口就是先拉后窗口直到 sum > target
然后开始移动前窗口,找到合适的最小长度
这里有一个重点:
sum -= nums[i];//前窗口向前移动,如果大于target则继续向前,如果小于,也没问题,因为已经把result记录了
i++;
思考它的两个作用
题目二:水果成篮
方法一:滑动窗口(我自己的方法)
class Solution {
public:
int totalFruit(vector<int>& fruits) {
if(fruits.size() == 0) return 0;
if(fruits.size() == 1) return 1;
if(fruits.size() == 2) return 2;
int result = 2;
int winl = 0;
int a = fruits[0],b = fruits[1];
for(int i = 0,j = 2;j < fruits.size();j++)
{
if(fruits[j] != a&&fruits[j] != b) //出现第三种种类
{
a = fruits[j-1];
b = fruits[j];
i = j-1;
while(i>=1&&fruits[i-1] == a) i--;
}
winl = j - i + 1;
result = (winl > result) ? winl: result;
}
return result;
}
};
遇到的错误:
1.无论出没出现第三个种类的树,最后都要再次进行result的更新。
不然会出现:3 3 1
当1处理之前result = 2,1处理完之后没有即时进行result的更新,导致循环结束后result还是2
2.while(fruits[i-1] == a) i--;的越界问题
应该是while(i>=1&&fruits[i-1] == a) i--;保证fruits[i-1]不越界
**以后遇到i--问题应该注意**
方法二:滑动窗口(别人的)
这种方法还会使用到哈希表,等以后再看
题目三:最小覆盖字串
(困难题)还需要用到哈希表,等学哈希表再来看