leecode 合集: 合并一个有序数组、二分查找

第一题:合并有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2
中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m
个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

解法一: 放入同一数组,再快速排序。

int comp(int *a,int*b)
{
    return  *a - *b; 
}


void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
          int s=m;
          for(int i=0;i<n;i++)
          {
              
              nums1[s]=nums2[i];
              s+=1;
          }
    qsort(nums1,m+n,sizeof(nums1[0]),comp);
      
 

}

解法2:双指针

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int s1=0,s2=0;
    int *brr=(int *)malloc(sizeof(int)*nums1Size);
    assert (brr!=NULL);
    int i=0;
    while(s1<m && s2<n)
    {
        
        if(nums1[s1]<=nums2[s2])
        {
            brr[i]=nums1[s1];
            s1+=1;
            i++;
        }
        else
        {
            brr[i]=nums2[s2];
            s2+=1;
            i++;
        }
    }
    while(s1<m)
    {
        brr[i]=nums1[s1];
            s1+=1;
            i++;
    }
   while(s2<n)
    {
        brr[i]=nums2[s2];
        s2+=1;
        i++;
    }
    for(int j=0;j<nums1Size;j++)
    {
        nums1[j]=brr[j];
    }
free(brr);
}

这里注意int s1 ,s2=0 // 错误 因为s1没有被初始化!!!!!

第二题:二分查找

在这里插入图片描述

int search(int* nums, int numsSize, int target){
    int left=0,right=numsSize-1;
    int mid=(left+right+1)/2;
    while(left<=right)
    {
        if(nums[mid]==target)
        {
            return mid;
        }
        if(nums[mid]>target)
        {
            right=mid-1;
            mid=(left+right)/2;
        }
        else
        {
            left=mid+1;
            mid=(left+right+1)/2;
        }
    }
     return -1;
     
}

这里要注意的是left 和right的取值,每次mid都已经不等于target,所以left和right要+1或-1。


在这里插入图片描述

class Solution {

public:
    vector<int> searchRange(vector<int>& nums, int target) {
    int len=nums.size();
    int l=0,r=len;
    int lval=lower_bound(nums,target);
    int rval=upper_bound(nums,target);
    if(lval==rval){return {-1,-1};}
    else
    return {lval,rval-1};
    }
    int lower_bound(vector<int>&nums,int target)
    {
        const int n=nums.size();
          int l=0,r=n;
        while(l<r)
        {
            int mid=l+(r-l)/2;
            if(nums[mid]>=target)
            {r=mid;}
            else{
                l=mid+1;
            }
        }
        return l;
    }
    int upper_bound(vector<int>&nums,int target)
    {
        const int n=nums.size();//和while(l<r)一起配合使得不会出现数组越界,就不用数组越界的检查。
        int l=0,r=n;
        while(l<r) //难点
        {
            int mid=l+(r-l)/2;//防止数组过大时l+r出现内存最大区间的越界
            if(nums[mid]<=target)
            {l=mid+1;}  
            else{
                r=mid;//难点是怎么和没找到target时做到统一代码。
            }
        }
        return l;
    }
};

重点:怎么找到左侧的边界?

可⻅,找到 target 时不要⽴即返回,⽽是缩⼩「搜索区间」的上界 right,在区间 [left, mid) 中继续搜索,即不断向左收缩,达到锁定左侧边界的⽬的(如果值不等于target,就将left减小以达到退出条件l<r)。
难点:是怎么和没找到target时(或者说普通的二分查找时)做到统一代码。


在这里插入图片描述

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = (int)nums.size();
        if (!n) {
            return -1;
        }
        if (n == 1) {
            return nums[0] == target ? 0 : -1;
        }
        int l = 0, r = n - 1;
       while(l<=r)
       {
           int mid=(l+r)/2;
           if(nums[mid]==target){return mid;}
           if(nums[0]<=nums[mid])//说明mid左侧是有序数组,则可以查找
           {
             
                    if(nums[0]<=target&&target<nums[mid])
                    {
                        r=mid-1;
                    }
                    else{
                        l=mid+1;
                    }
           }
           else
           {
               if(nums[mid]<target&&target<=nums[n-1])//如果mid左半部不有序,那么mid右侧一定有序,我们在mid右侧操作。范围则继续缩小到target所在的那个区域,下个循环继续找。
               {
                   l=mid+1;

               }
               else{
                   r=mid-1;
               }

           }
       }
      return -1;

    }
};

总结:只要那个区间是有序的就可以二分查找。我们只需要不断的在可以查找的区间去缩小target所在的范围。直到找到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode一个在线的编程题库,提供了各种各样的算法数据结构问题供开发者练习和提高编程能力。其中,提到了三个与数组相关的问题。 第一个引用是关于合并两个有序数组的问题,即将两个有序的整数数组合并一个有序数组。具体的解法可以使用双指针法,分别指向两个数组的末尾,然后比较两个指针指向的元素大小,将较大的元素放入结果数组的末尾,然后将指针向前移动。这个过程重复直到其中一个数组遍历完毕,然后将剩下的元素依次放入结果数组中。 第二个引用是关于移除元素的问题,即移除数组中指定的元素,并返回新数组的长度。可以使用双指针法,左指针维护非指定元素的末尾位置,右指针遍历数组。当右指针指向的元素不等于指定元素时,将右指针指向的元素赋值给左指针指向的位置,然后将左指针和右指针都向前移动一位。直到右指针遍历完整个数组,最后返回左指针的值,即为新数组的长度。 第三个引用也是关于移动零元素的问题,即将数组中的零元素移动到数组末尾,同时保持非零元素的相对顺序不变。可以使用双指针法,左指针维护非零元素的末尾位置,右指针遍历数组。当右指针指向的元素不等于零时,将右指针指向的元素与左指针指向的元素交换位置,然后将左指针和右指针都向前移动一位。直到右指针遍历完整个数组,即完成了零元素的移动。 这些问题都可以使用双指针法解决,利用双指针在数组上进行遍历和操作,实现对数组的操作和处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [LeeCode每日一题–合并两个有序数组](https://download.csdn.net/download/weixin_38645669/14856034)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [LeeCode 数组题目](https://blog.csdn.net/weixin_43763903/article/details/114675786)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值