数组-算法总结

 数组常用算法:二分查找,双指针,滑动窗口,模拟行为,我们将从这四个思想介绍


 

目录

二分查找

移除元素

长度最小的子数组

螺旋矩阵


二分查找

使用条件:

1.有序数组,2.无重复元素

原理:

在数组中先从中间位置的元素开始判断和目标值的关系,然后调整left或者right,从而实现不用按个遍历整个数组。

方法:

对于在一个有序数组中寻找目标元素的位置类问题,采用二分法。常见二分法的写法分为两种

1.左闭右闭

2.左闭右开

我们将附上两者代码。

现在说一下具体的实现方法:我们以左闭右闭举例。

1.确定left和right的值,由于都是闭合,则表示左右区间元素都可以取到

int left=0,right=nums.size()-1;

 2.确定while的判断条件,由于都是闭合,则表示区间元素都可以取到

while(left<=right){

}

3.确定left和right的变换情况,由于都是闭合,则表示区间元素都可以取到,那么下一次判断则不需要边界元素

if(nums[middle]>target){
    right=middle-1;
}
else if(nums[middle]<target){
    left=middle+1;
}
else{
    //找到了
}

综上所述,整个代码就分析完了,同理,左闭右开也是如此,两个代码如下:

1.左闭右闭

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
       
        while(left<=right){
             int middle=left+((right-left)>>1);
            if(nums[middle]>target){
                right=middle-1;
            }
            else if(nums[middle]<target){
                left=middle+1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
};

2.左闭右开

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size();
       
        while(left<right){
             int middle=left+((right-left)>>1);
            if(nums[middle]>target){
                right=middle;
            }
            else if(nums[middle]<target){
                left=middle+1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
};

常见题型:

704. 二分查找 - 力扣(LeetCode)https://leetcode.cn/problems/binary-search/367. 有效的完全平方数 - 力扣(LeetCode)https://leetcode.cn/problems/valid-perfect-square/35. 搜索插入位置 - 力扣(LeetCode)https://leetcode.cn/problems/search-insert-position/34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

移除元素

使用条件:

1.不产生新的内存空间,2.原地删除指定元素

原理:

数组中无法直接删除元素,都是通过覆盖实现,因此思路就是遍历原数组,利用其他值把特定值进行覆盖,当遍历完成后即完成了新数组。需要注意的是,数组在内存中还是之前大小,只是按照你的想法留下了一些元素。

方法:

对于删除特定元素的问题,一般有两个办法,1暴力法,2双指针法。

我们将附上两者代码。

现在说一下具体的实现方法:我们以暴力法举例。

1.遍历整个数组

for(int i=0;i<nums.size();i++){
    
}

2.当遍历数组发现目标元素时,把目标元素后所有元素进行前移

if(nums[i] == val){
    for(int j = i +1 ; j < nums.size(); j++){
        nums[j-1] = nums[j];
    }
    //数组大小--
}

综上所述,整个代码就分析完了,代码如下:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for(int i = 0; i<size; i++){
            if(nums[i]==val){
                for(int j = i + 1; j<size; j++){
                    nums[j-1]=nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }
};

我们以双指针法举例。

双指针的思路是:快指针遍历整个数组,慢指针为需要保留元素的下标。当快指针符合条件时(一般是≠),慢指针++,然后把当前快指针的值赋值给慢指针下标,然后++

1.定义一个快指针来遍历所有元素,一个慢指针保留有效元素的下标

int slow=0;
        for(int fast = 0; fast < nums.size(); fast++){
            

            }
        }

2.当快指针遍历的元素满足条件时,把保留元素存入数组,且下标为当前慢指针,当满足一次后,慢指针后移,因此,整体代码如下

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow=0;
        for(int fast = 0; fast < nums.size(); fast++){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
};

常见题型:

27. 移除元素 - 力扣(LeetCode)https://leetcode.cn/problems/remove-element/submissions/

26. 删除有序数组中的重复项 - 力扣(LeetCode)https://leetcode.cn/problems/remove-duplicates-from-sorted-array/submissions/ 283. 移动零 - 力扣(LeetCode)https://leetcode.cn/problems/move-zeroes/

977. 有序数组的平方 - 力扣(LeetCode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/squares-of-a-sorted-array/

长度最小的子数组

使用条件:

寻找数组中的子数组

原理:

利用双指针思想,有两个指针分别指向数组。但是:滑动窗口中,我们用last进行移动数组,first只有在满足条件的时候才进行移动。

因此,我们定义last在一个for中不断遍历数组,且每次遍历时把当前last位置的元素++。然后判断该元素和是否满足条件。当满足条件后,我们先求当前的字符串长度,然后开始first++,然后元素和减去first之前的元素,再判断元素和是否满足。

方法:

1.定义first指向0位置,last指向0位置,ans=INT_MAX,元素和sum=0

        int first = 0;
        int ans =INT_MAX;
        int sum = 0;

2.移动last指针,遍历整个数组,并求每次移动后的元素和

        for(int last = 0; last < nums.size(); last++){
            sum += nums[last];
            }

 3.对元素和进行判断是否满足要求,如果满足,先求得当前字符串长度,然后把first++,然后把之前的first的值移除,再判断元素和。因此总代码如下:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int first = 0;
        int ans =INT_MAX;
        int sum = 0;
        for(int last = 0; last < nums.size(); last++){
            sum += nums[last];
            while(sum >= target){
                ans = min(ans , last - first + 1);
                sum -= nums[first++];
            }
        }
        return ans == INT_MAX ? 0 : ans;//防止空数组
    }
};

 如下:为暴力法

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    int ans=INT_MAX;
    for(int i = 0; i < nums.size(); i++){
        int sum = 0;
        for(int j = i; j < nums.size(); j++){
            sum += nums[j];
            if(sum >= target){
                ans=min(ans, j - i + 1);
            }
        }
    }
    return ans == INT_MAX ? 0 : ans;
    }
};

常见题型:

209. 长度最小的子数组 - 力扣(LeetCode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/minimum-size-subarray-sum/

螺旋矩阵

方法:

采取左闭右开

1.定义其实位置startx=starty=0,offest=1控制边界长度,i,j控制移动,loop控制圈数,mid控制中间那个格子

        int startx = 0, starty = 0;
        int offest = 1;
        int i, j;
        int loop = n / 2;//转的圈数
        int mid = n / 2 ;//中间补充的位置
        int count = 1;

2.上排,采用左闭右开,数据采用(i,j),因此上排遍历只有 j 改变,i 不动

for( j = starty; j < n - offest; j++){
           ans[startx][j] = count++;
            }

2.右排,采用左闭右开,数据采用(i,j),因此右排遍历只有i 改变,j 不动

            for( i =startx; i < n -offest; i++){
                ans[i][j] = count++;
            }

同理可以得到另外两排数据,总代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>ans(n,vector<int>(n,0));
        int startx = 0, starty = 0;
        int offest = 1;
        int i, j;
        int loop = n / 2;//转的圈数
        int mid = n / 2 ;//中间补充的位置
        int count = 1;
        while(loop--){
            i = startx;
            j = starty;
            //上
            for( j = starty; j < n - offest; j++){
                ans[startx][j] = count++;
            }
            //右
            for( i =startx; i < n -offest; i++){
                ans[i][j] = count++;
            }
            //下
            for(; j > starty; j--){
                ans[i][j] = count++;
            }
            //左
            for(; i > startx; i--){
                ans[i][j] = count++;
            }
            //第二圈
            startx++;
            starty++;
            offest+=1;
            }
            if(n % 2){
                //奇数
                ans[mid][mid] = count;
           
        }
         return ans;
    }
};

相关题目:

59. 螺旋矩阵 II - 力扣(LeetCode)icon-default.png?t=M85Bhttps://leetcode.cn/problems/spiral-matrix-ii/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值