数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标下对应的数据。
注:数组下标从0开始,内存空间地址连续。
删除添加元素需要移动其他元素地址。数组元素不能删除,只能覆盖。
二维数组内存空间地址也是连续的。
根据代码随想录,记录学习一些算法经验,
题目描述:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
这里面关键词有序,数组,无重复元素,满足两个条件可以考虑二分法。
注:边界条件设定,中间取值到底是-1,还是+1,
一般边界设置左闭右闭,或者左闭右开,
采用的是左闭右闭写法,这样写记得左+1,右-1的边界条件即可,在一个while(left<=right)条件下一直循环,下面是伪代码:
class solution{
int search(vector&nums, int target){
int left = 0;//左端边界
int right = nums.size()-1;//右端边界
while(left<=right){//边界使用左闭右闭条件
int mid = left + ((right - left) / 2);//中间值
if(nums[mid]< target){
left = mid+1;//左端+1;
}else if(nums[mid] > target){
right = mid -1;//右端-1;
}else{
return mid;//找到下标值,返回
}
}
return -1; //未找到返回-1;
}
};
下面介绍左闭右开写法
class Solution {
public:
int search(vector& nums, int target) {
int left = 0,right = nums.size() ;
while(leftnums[mid]){
left=mid+1;
}else{
return mid;
}
}
return -1;
}
};
区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则 。
总结:right值是否减一与设置有关,左必右闭->nums.size()-1->mid-1,左闭右开->nums.size()->mid;二分法的时间复杂度是O(logn)。
题目描述:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
数组元素在内存地址上连续的,删除不了元素,只能覆盖。
暴力解法:不建议采用双循环做法,两个循环,第一个循环遍历数组,第二个循环更新数组。
class Solution {
public:
int removeElement(vector& nums, int val) {
int size = nums.size();
for(int i = 0 ;i
暴力解法的时间复杂度o(n2)空间复杂度o(1)
双指针解法:定义一个快指针和一个慢指针在一个循环下完成任务,代码如下:
class Solution {
public:
int removeElement(vector& nums, int val) {
int slow = 0;//定义慢指针,
for(int fast = 0;fast
双指针时间复杂度是:o(n),空间复杂度o(1);
总结数组链表大多数题目都可以使用双指针来解决。
题目描述:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
暴力解法:先平方在排序,代码如下:
class Solution {
public:
vector sortedSquares(vector& nums) {
vectorresult;
for(int i = 0; i
时间复杂度是 O(n + nlogn)
双指针方法:数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
class Solution {
public:
vector sortedSquares(vector& nums) {
int k = nums.size()-1;//准备定义新数组的大小
vectorresult(nums.size(),0);//定义全为0数组
for(int i = 0, j=nums.size()-1;i<=j;)//定义两个指针从首段和尾端开始
{
if(nums[i]*nums[i]
时间复杂度为O(n)总结:体现用空间换时间的操作。
题目描述:给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
暴力解法:双循环,找出符合条件数组,
class Solution {
public:
int minSubArrayLen(int target, vector& nums) {
int result = INT32_MAX;
int sum = 0;
int sublength = 0;
for(int i = 0;i= target){
sublength = j - i + 1;//取子数组长度
result = result < sublength ? result : sublength;//返回结果
break;//跳出这次循环
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
滑动窗口方法:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。滑动窗口也可以理解为双指针法的一种。
实现滑动窗口,主要确定如下三点:
class Solution {
public:
int minSubArrayLen(int target, vector& nums) {
int result = INT32_MAX;
int i = 0;// 滑动窗口起始位置
int sum = 0;// 滑动窗口数值之和
int sublength = 0;// 滑动窗口的长度
for(int j = 0;j < nums.size();j++){
sum+=nums[j];
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while(sum >= target){
sublength = j - i + 1;//取子数组长度
result = result < sublength ? result : sublength;//返回结果
sum -=nums[i++];// 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
模拟:螺旋打印过程,遵循循环不变量原则
模拟顺时针画矩阵的过程:
class Solution {
public:
vector> generateMatrix(int n) {
vector>res(n,vector(n,0));
int startx = 0,starty = 0;//循环一圈的起始位置
int loop = n/2;//需要循环的圈数
int mid = n/2;//矩阵中间位置
int count = 1;//赋值
int offset = 1;//遍历边长度
int i,j;
while(loop--){
i = startx;
j = starty;
//下面四个循环模拟转一圈
for(j = starty;jstarty;j--){
res[i][j]=count++;
}
for(;i>startx;i--){
res[i][j]=count++;
}
//第二圈
startx++;
starty++;
offset += 2;
}
if(n%2){
res[mid][mid]=count;
}
return res;
}
};
数组理论基础:数组是存放在连续内存空间上的相同类型数据的集合。通过下标进行索引,查找很方便,删除增加元素麻烦,内存空间地址连续。
二分查找:注意边界问题,左右边界定义,记得数组有序,无重复元素,左闭右开和左闭右闭的写法和边界处理问题,right值是否减一与设置有关,左必右闭->nums.size()-1->mid-1,左闭右开->nums.size()->mid,遵循循环不变量原则。
移除元素:因为数组连续地址空间,删除某元素只能通过覆盖,所以采用双指针操作来完成,
有序数组平方:有序,平方之后也有一定的规律,同样可以采用双指针的形式来完成操作,两侧的值较大,中间小,对比可以从结果集后向前进行插入,放较大值。
长度最小的子数组:滑动窗口方法,要知道窗口是什么,起始位置和终止位置,如何移动,此题指针移动就是窗口的末尾位置,改变前指针就是初始位置,判断条件就是给出的条件。
螺旋矩阵:循环打印过程遵循循环不变量原则,模拟的过程,要知道需要转多少圈,以及中心点变化,循环打印的边界。
值得思考的问题是滑动窗口的长度最小的子数组!!!!