算法学习 (第二部分 ) 数据结构--数组
第二部分 数据结构
一. 数组
1.有序数组的查找 --二分法
int binary1(vector<int> &num, int target, int low, int high)
{
//递归
if (high >= low)
{
int mid = low + (high - low)/ 2;
if (num.at(mid) == target)
return mid;
else if (num.at(mid) > target)
return binary1(num, target, low, mid - 1);
return binary1(num, target, mid + 1, high);
}
return -1;
}
int binary2(vector<int> &num, int target)
{
int low = 0, high = num.size() - 1;
int mid;
while (low <= high)
{
/* code */
mid = low + (high - low) >> 1;
if (num.at(mid) == target)
return mid;
if (num.at(mid) > target)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
int binary3(vector<int> &num, int target)
{
int low = 0, high = num.size();
while (low < high)
{
/* code */
int mid = low + (high - low) >> 1;
if (num.at(mid) == target)
return mid;
if (num.at(mid) > target)
high = mid;
else
low = mid + 1;
}
return -1;
}
理解二分法对于区间的划分来规定边界情况
[low,high] 边界设为 low <= high 下一次选取[low,mid-1]和[mid+1,low]
[low,high) 边界设为 low<high 下一次选取[low,mid) [mid,high)
2.移除元素/插入元素
数组需要大量的移动数据,在考虑时可以使用两个指针(下标),来记录应当保留(移动的)情况
LeetCode N27_移除元素
int removeElement(vector<int>& nums, int val)
{
int first,second;
first = 0;
for(second =0 ; second < nums.size();second++)
{
if(nums.at(second)!=val)
nums[first++]=nums[second];
}
return first;
}
3.通过 长度最小的子树组 理解滑动窗口
理解 滑动窗口
(1)滑动窗口内的元素是什么?
(2)如何移动滑动窗口起始位置?
(3)如何滑动窗口终止位置?
(1) 滑动窗口算法
滑动窗口,顾名思义,就是有一个大小可变的窗口,左右两端方向一致的向前滑动(右端固定,左端滑动;左端固定,右端滑动)。可以想象成队列,一端在push元素,另一端在pop元素
(2)适用范围
- 一般是字符串或者列表
- 一般是要求最值(最大长度,最短长度等等)或者子序列
(3) 算法模板
int left = 0,right =0;
while(right指针未越界){
char ch = arr[right++];
//右指针移动,更新窗口
...
//窗口数据满足条件 对于固定窗口而言,就是窗口的大小>=固定值;对于动态窗口,就是从left出发,窗口不断扩充,第一次满足题意的位置
while(窗口数据满足条件){
//记录或者更新全局数据
...
//右指针不动,左指针开始移动一位
char tmp = arr[left++];
//左指针移动,窗口缩小,更新窗口数据
...
}
//返回结果
...
}
(4) 结论
- 滑动窗口算法就是用以解决数组/字符串的子元素问题
- 滑动窗口算法可以将嵌套的for循环问题,转换为单循环问题,降低时间复杂度
(5) 实例
LeetCode N209_长度最小的子树组
int minSubArrayLen1(int target, vector<int>& nums)
{
int sum,res,len,i,j;
res = INT32_MAX;
for(i=0;i<nums.size();i++)
{
sum = 0;
for(j = i ; j < nums.size();j++)
{
sum+=nums[j];
if(sum>=target)
{
len = j - i +1;
res = (res<len)?res:len;
break;
}
}
}
res = (res==INT32_MAX)?0:res;
return res;
}
int minSubArrayLen(int target, vector<int>& nums)
{
//滑动窗口内的元素 : 和大于等于target的子数组
//滑动起点 : i指针 当出现sum >target 是 sum-=nums[i++]
//滑动重点 : j指针当前指针
int res,sum,i,j,len;
res=INT32_MAX;
sum = 0;
len = 0;
i=0;
for(j=0;j<nums.size();j++)
{
sum+=nums.at(j);
while (sum>=target)
{
len = j -i+1;
res =(res<len)?res:len;
sum-=nums.at(i++);
/* code */
}
}
return res==INT32_MAX?0:res;
}
4. 循环情况要理清思路
LeetCode N59_螺旋矩阵2
vector<vector<int>> generateMatrix(int n)
{
vector<vector<int>> num(n,vector<int> (n,0));
int len = n-1;
int mid = n/2;
int loop = n/2;
int offset = 1;
int stx,sty,i,j;
int count =1;
stx=sty=0;
for(int k = 0 ; k < loop ;k++)
{
i=stx;
j=sty;
//left -> right
for(j = sty ; j < sty + n - offset ;j++ )
{
num[i][j] = count++;
}
//up -> down
for(i = stx; i < stx+n-offset;i++)
{
num[i][j] = count++;
}
//right -> left
for(;j>sty;j--)
{
num[i][j] =count++;
}
for(;i>stx;i--)
{
num[i][j]= count++;
}
stx ++;sty++;
offset+=2;
}
if(n&0x01)
{
num[mid][mid] = count;
}
return num;
}