• 二分法-算法总结


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


     

    目录

    二分查找

    移除元素

    长度最小的子数组

    螺旋矩阵


    二分查找

    使用条件:

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

    原理:

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

    方法:

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

    1.左闭右闭

    2.左闭右开

    我们将附上两者代码。

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

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

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

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

    1. while(left<=right){
    2. }

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

    1. if(nums[middle]>target){
    2. right=middle-1;
    3. }
    4. else if(nums[middle]
    5. left=middle+1;
    6. }
    7. else{
    8. //找到了
    9. }

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

    1.左闭右闭

    1. class Solution {
    2. public:
    3. int search(vector<int>& nums, int target) {
    4. int left=0,right=nums.size()-1;
    5. while(left<=right){
    6. int middle=left+((right-left)>>1);
    7. if(nums[middle]>target){
    8. right=middle-1;
    9. }
    10. else if(nums[middle]
    11. left=middle+1;
    12. }
    13. else{
    14. return middle;
    15. }
    16. }
    17. return -1;
    18. }
    19. };

    2.左闭右开

    1. class Solution {
    2. public:
    3. int search(vector<int>& nums, int target) {
    4. int left=0,right=nums.size();
    5. while(left
    6. int middle=left+((right-left)>>1);
    7. if(nums[middle]>target){
    8. right=middle;
    9. }
    10. else if(nums[middle]
    11. left=middle+1;
    12. }
    13. else{
    14. return middle;
    15. }
    16. }
    17. return -1;
    18. }
    19. };

    常见题型:

    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.遍历整个数组

    1. for(int i=0;isize();i++){
    2. }

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

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

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

    1. class Solution {
    2. public:
    3. int removeElement(vector<int>& nums, int val) {
    4. int size = nums.size();
    5. for(int i = 0; i
    6. if(nums[i]==val){
    7. for(int j = i + 1; j
    8. nums[j-1]=nums[j];
    9. }
    10. i--;
    11. size--;
    12. }
    13. }
    14. return size;
    15. }
    16. };

    我们以双指针法举例。

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

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

    1. int slow=0;
    2. for(int fast = 0; fast < nums.size(); fast++){
    3. }
    4. }

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

    1. class Solution {
    2. public:
    3. int removeElement(vector<int>& nums, int val) {
    4. int slow=0;
    5. for(int fast = 0; fast < nums.size(); fast++){
    6. if(nums[fast] != val){
    7. nums[slow] = nums[fast];
    8. slow++;
    9. }
    10. }
    11. return slow;
    12. }
    13. };

    常见题型:

    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

    1. int first = 0;
    2. int ans =INT_MAX;
    3. int sum = 0;

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

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

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

    1. class Solution {
    2. public:
    3. int minSubArrayLen(int target, vector<int>& nums) {
    4. int first = 0;
    5. int ans =INT_MAX;
    6. int sum = 0;
    7. for(int last = 0; last < nums.size(); last++){
    8. sum += nums[last];
    9. while(sum >= target){
    10. ans = min(ans , last - first + 1);
    11. sum -= nums[first++];
    12. }
    13. }
    14. return ans == INT_MAX ? 0 : ans;//防止空数组
    15. }
    16. };

     如下:为暴力法

    1. class Solution {
    2. public:
    3. int minSubArrayLen(int target, vector<int>& nums) {
    4. int ans=INT_MAX;
    5. for(int i = 0; i < nums.size(); i++){
    6. int sum = 0;
    7. for(int j = i; j < nums.size(); j++){
    8. sum += nums[j];
    9. if(sum >= target){
    10. ans=min(ans, j - i + 1);
    11. }
    12. }
    13. }
    14. return ans == INT_MAX ? 0 : ans;
    15. }
    16. };

    常见题型:

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

    螺旋矩阵

    方法:

    采取左闭右开

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

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

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

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

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

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

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

    1. class Solution {
    2. public:
    3. vectorint>> generateMatrix(int n) {
    4. vectorint>>ans(n,vector<int>(n,0));
    5. int startx = 0, starty = 0;
    6. int offest = 1;
    7. int i, j;
    8. int loop = n / 2;//转的圈数
    9. int mid = n / 2 ;//中间补充的位置
    10. int count = 1;
    11. while(loop--){
    12. i = startx;
    13. j = starty;
    14. //上
    15. for( j = starty; j < n - offest; j++){
    16. ans[startx][j] = count++;
    17. }
    18. //右
    19. for( i =startx; i < n -offest; i++){
    20. ans[i][j] = count++;
    21. }
    22. //下
    23. for(; j > starty; j--){
    24. ans[i][j] = count++;
    25. }
    26. //左
    27. for(; i > startx; i--){
    28. ans[i][j] = count++;
    29. }
    30. //第二圈
    31. startx++;
    32. starty++;
    33. offest+=1;
    34. }
    35. if(n % 2){
    36. //奇数
    37. ans[mid][mid] = count;
    38. }
    39. return ans;
    40. }
    41. };

    相关题目:

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

  • 相关阅读:
    【笔试题】【day16】
    vue项目中将html转为pdf并下载
    百度直播iOS SDK平台化输出改造
    【Latex】错误类型总结(持更)
    6.6K Star,比 Pandas 快很多的数据处理库
    vulnhub靶机:Kioptrix : Level 1.2
    第1关:Hbase数据库的安装
    leetcode 300. Longest Increasing Subsequence 最长递增子序列 (中等)
    Python中的数据常见问题
    ubuntu 清理缓存
  • 原文地址:https://blog.csdn.net/m0_60524373/article/details/126705757