【C++代码】二分查找,移除元素

题目:二分查找

  • 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
题解
  • 在升序数组 nums \textit{nums} nums 中寻找目标值 target \textit{target} target,对于特定下标 i,比较 nums [ i ] \textit{nums}[i] nums[i] target \textit{target} target 的大小:

    • 如果 nums[i]=target,则下标 i 即为要寻找的下标;

    • 如果 nums[i]>target,则 target 只可能在下标 i 的左侧;

    • 如果 nums[i]<target,则 target 只可能在下标 i 的右侧。

  • 二分查找的做法是,定义查找的范围 [ left , right ] [\textit{left}, \textit{right}] [left,right],初始查找范围是整个数组。每次取查找范围的中点 mid,比较 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] 和 target 的大小,如果相等则 mid 即为要寻找的下标,如果不相等则根据 nums[mid] 和 target 的大小关系将查找范围缩小一半。由于每次查找都会将查找范围缩小一半,因此二分查找的时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn),其中 n 是数组的长度。

  • 二分查找的条件是查找范围不为空,即 left ≤ right \textit{left} \le \textit{right} leftright。如果 target 在数组中,二分查找可以保证找到 target,返回 target 在数组中的下标。如果 target 不在数组中,则当 left > right \textit{left} > \textit{right} left>right 时结束查找,返回 −1。

  • #include<iostream>
    #include<vector>
    using namespace std;
    int search_binary(vector<int>nums, int target)
    {
          
          
    	int left=0,right=nums.size()-1;
            while(left<=right){
          
          
                int mid = (right-left)/2+left;
                int num = nums[mid];
                if(num==target)
                    return mid;
                else if (num>target)
                    right = mid-1;
                else
                    left = mid+1;
            }
            return -1;
    }
    int main()
    {
          
          
       	vector<int>v{
          
           8,11,19,23,27,33,45,55,67,98 };
    	cout << search_binary(v, 19);
       	return 0;
    }
    
  • mid索引计算优化,可用位运算

    • int mid = left&right+(left^right)>>1;//效率略高
      

      作者:力扣官方题解
      链接:https://leetcode.cn/problems/binary-search/solutions/980494/er-fen-cha-zhao-by-leetcode-solution-f0xw/

题目:移除元素

  • 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
题解
  • 由于题目要求删除数组中等于 val 的元素,因此输出数组的长度一定小于等于输入数组的长度,我们可以把输出的数组直接写在输入数组上。可以使用双指针:右(快)指针 right 指向当前将要处理的元素,左(慢)指针 left 指向下一个将要赋值的位置

    • 如果右指针指向的元素不等于 val,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;

    • 如果右指针指向的元素等于 val,它不能在输出数组里,此时左指针不动,右指针右移一位

  • 整个过程保持不变的性质是:区间 [0,left) 中的元素都不等于 val。当左右指针遍历完输入数组以后,left 的值就是输出数组的长度。这样的算法在最坏情况下(输入数组中没有元素等于 val,左右指针各遍历了数组一次

  • 在这里插入图片描述

  • 时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多两次。空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

  • #include<iostream>
    #include<vector>
    using namespace std;
    int removeElement(vector<int>& nums, int val) {
          
          
    	int fast =0,slow=0;
    	for(fast;fast<nums.size();fast++){
          
          
    		if(nums[fast]!=val){
          
          
    			nums[slow] = nums[fast];
    			slow++;
    		}
    	}
    	return slow;
    }
    int main()
    {
          
          
       	vector<int>v{
          
           8,11,19,23,19,33,45,19,67,19 };
    	cout << removeElement(v, 19);
       	return 0;
    }
    
  • 暴力删除法

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

    • class Solution {
              
              
      public:
          int removeElement(vector<int>& nums, int val) {
              
              
              for(vector<int>::iterator iter=nums.begin();iter!=nums.end();iter++)
              {
              
                      //从vector中删除指定的某一个元素 
                  if(*iter==val)
                  {
              
              
                       iter= nums.erase(iter);
                       iter--;
                   }
              }
              return nums.size();
          }
      };
      

数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标下对应的数据。代码随想录 (programmercarl.com)

  • 在这里插入图片描述

    • 数组下标都是从0开始的;

    • 数组内存空间的地址是连续的.

  • 使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。数组的元素是不能删的,只能覆盖

  • 二维数组在内存的空间地址是连续的么?

    • 不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。

    • #include <iostream>
      #include <vector>
      using namespace std;
      void test_arr() {
              
              
          int array[2][3] = {
              
              
      		{
              
              0, 1, 2},
      		{
              
              3, 4, 5}
          };
          cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
          cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl;
      }
      int main() {
              
              
          test_arr();
      }
      
    • 在这里插入图片描述

    • 0x7ffd58fb62f0 与 0x7ffd58fb62f4 差了一个4,就是4个字节,因为这是一个int型的数组,所以两个相邻数组元素地址差4个字节。

猜你喜欢

转载自blog.csdn.net/weixin_43424450/article/details/132461180
今日推荐