数组的相关操作我觉得基本可以总结成遍历遍历再遍历。如果不考虑时间与空间复杂度的话,暴力循环是最“好”的方法(完全不用动脑子当然好)。但往往空间与时间复杂度总会有这样那样的限制,这时候就需要使用一些处理技巧了(基本可以类比为“剪枝”,也就是去除不必要的循环过程,i->j能解决的问题,绝不i->k嘿嘿)。
双指针
双指针故名思意,就是使用两个指针同时指明索引来简化一些操作(暴力两层循环我觉得也可以理解成双指针吧)。双指针的关键我觉得是通过要求对两个指针的移动方法进行设计。
滑动窗口
两个指针(i;j)分别指示指示数组的一个索引,而i->j可以视为一个滑块。根据条件对i,j进行变更,就达到了滑块移动的目的。常用于处理数组中的“子数组”的问题(如几个连续的数等于几啊balabala)
这个方法我个人觉得如果事先没接触过很难凭空弄出来,因此算是一个重点吧。下面这个是leetcode的滑动窗口的典型题。
长度最小的子数组
**题意:**给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。
传送门
int minSubArrayLen(int s, vector<int>& nums) {
int left=0,right=-1;
int res=nums.size()+1;
int sum=0;
while(left<nums.size()){
if(sum<s&&right+1<nums.size()){
sum+=nums[++right];
}
else
sum-=nums[left++];
if(sum>=s)
res=min(res,right-left+1);
}
if(res==nums.size()+1)
return 0;
return res;
}
对撞指针
设置一个指针l指向数组头,一个指针j指向数组尾。根据具体要求移动指针(i++,j–),最后也就能够达到遍历完数组找到最优解的目的。(“搜索”类型的要求可以先将数组排序再使用这种方法进行查找)
下面这是一道典型的题目了,题目思路很直观,算是体现了这种方法的思想吧。
盛最多水的容器
leetcode
int maxArea(vector<int>& height) {
int i=0,j=height.size()-1;
int res=0;
while(i<j){
int temp=(j-i)*min(height[i],height[j]);
if(temp>res)
res=temp;
height[i]<height[j]?i++:j--;
}
return res;
}
二分
二分就是二分咯,有时候有序数组之类的可以使用来优化算法。
寻找重复数
leetcode
**题意:**给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
**思路:**不断二分,找左右两边数的个数,进而判断多的那个数在哪个范围内。
int findDuplicate(vector<int>& nums) {
int n=nums.size();
int left=0,right=n;
while(left<right){
int count=0;
int mid=left+(right-left)/2;
for(int i=0;i<n;i++){
if(nums[i]<=mid)
count++;
}
if(count<=mid)
left=mid+1;
else
right=mid;
}
return left;
}