剑指offer(数组相关面试题)

做题温馨提示

每个题的解题方法有很多,你不要纠结于它的优解, 先用最笨的方法(或者你能想到的方法解决出来), 然后自己在一步一步的优化。

移除元素

在这里插入图片描述
在这里插入图片描述

移除元素OJ链接

思路一:在nums数组中,一个元素一个元素的找,假设数组大小为N,如果第一个数等于val,那么就让第一个数 = 第二个数, 如果不想等,就跳过第一个数,比较第二个数 。
但是,时间复杂度通常考虑最坏的情况
当数组中的元素,大部分或者基本都为val,那么就第一个数 = 第二个数(挪动n - 1次),第二个数 = 第三个数(挪动n - 2次)(这样遍历), …
时间复杂度(就为一个等差数列)
= n - 1 + n - 2 + n - 3 + … 1
= n^2 / 2 - n / 2
时间复杂度大O的渐进表示法:O(n^2)
空间复杂度 : O(n)

思路二(以空间换时间, 创建一个数组)
第一步:创建一个数组tmp
第二步:用val,与nums数组中的元素挨个比较,如果数组中的元素 = val, 与下一个比较, 如果不相等, 把这个值 放到数组tmp中, 就这这样挨个遍历
第三步: 把tmp数组中的值,拷贝到nums数组中
时间复杂度(nums数组大小为 n, 比较了n次)
O(n
)
空间复杂度:O(n)
时间复杂度 O(n)

思路三(优解)
有点类似于双指针思想
在这里插入图片描述
如图,
第一步,定义两个变量 int src = 0, dest =0 ;, 都代表着数组的下标
第二步:用nums[src]去与val比较,如果相同,src++,继续比较nums数组下一个元素,如果不相同, 那么让nums[dst] = nums[scr], 然后让src++, dst++,这样依次遍历
第三步:第二步完成之后, nums[dst] 就代表着移除之后的数组,可以让(dst = 0, dst = 1,…)挨个把移除后的数组打印出来, dst是数组下标, dst+1 便是这个数组的大小。
注意 scr++时候, scr大小不能够超过nums数组大小.

思路三最好自己画图理解一下
空间复杂度 O(1)
时间复杂度 O(n)

思路三的代码如下

int removeElement(int* nums, int numsSize, int val)
{
    int scr = 0, dst = 0;

    while(scr < numsSize)
    {
        if(nums[scr] != val)
        {
            nums[dst] = nums[scr];
            scr++;
            dst++;

        }
        else
        {
            scr++;
        }
    }
    
    return dst;
}

删除有序数组的重复项

在这里插入图片描述
在这里插入图片描述

删除有序数组的重复项链接
这道题就是个去重的问题,数据结构的题做的时候,一定要画图理解下

思路1与思路二,都跟上一题一样
这里我还是来介绍下,优解思路三
这里我定义数组的三个下标来做2个下标也可以来做, )
在这里插入图片描述
在这里插入图片描述
如图
第一步:int i = 0, j = 1, dst = 0;
第二步:就让nums[i]与nums[j]进行比较, 如果相等, j++,如果不等,说明j,已经跳出了nums数组元素相等的那个区间了(因为题目说:这是一个有序的数组)
就让nums[dst] = nums[i], i = j, j++
注意:
在这里插入图片描述
在这里插入图片描述
可能会出现这样几种情况, j++就越界了,就结束了while(j < numsSize)这个循环
那么
第三步:单独对数组中最后一个元素进行处理, nums[dst] = nums[i];
第四步: return dst;

int removeDuplicates(int* nums, int numsSize)
{
    if(numsSize == 0)  //判断numsSize是否为0
    {
        return 0;
    }

  int dst = 0, i = 0, j = 1;

  while(j < numsSize)
  {
      if(nums[i] == nums[j])
      {
          ++j;
      }
      else
      {
          nums[dst] = nums[i];
          dst++;
          i = j;
          j++;
      }
  }

  nums[dst] = nums[i];
  dst++;

  return dst;
}

:定义两个下标来做
原理是一样的,自己画图理解

代码如下;

int removeDuplicates(int* nums, int numsSize)
{
    if(numsSize == 0)  //判断numsSize是否为0
    {
        return 0;
    }
    int i = 0, j = 1;

    while(j < numsSize)
    {
        if(nums[j] == nums[j - 1])
        {
            j++;
        }
        else
        {
            nums[i] = nums[j - 1];
            i++;
            j++;
        }
    } 
    
    nums[i] = nums[j - 1];
    i++;
    
    return i;
}

合并两个有序的数组

在这里插入图片描述
[合并两个有序数组的链接](https://leetcode.cn/classic/problems/merge-sorted-array/description/)
思路一:跟前面思路二一样,用空间换时间,开辟一个新的数组。

思路二(优解)
思想:从数组最后一个元素比较,找最大的数(如果从数组第一个元素比较,找最小的数,那么将会出现问题,自己可以画图举例试试), 最大的数放在合并的数组下标那里,然后都下标都减减,就这样一次找,
下面看具体操作:

第一步:定义三个下标,int end1, end2, end; 分别为第一个数组的下标,第二个数组的下标,合并后数组的下标.
第二步:找最大数,如果num1[end1] < num2[end2]; 那么num1[end] = nums[end2], 然后end --, end2-- ,像这样比较,

要考虑两种情况,第一个数组(num1,为两个数组合并之后的数组)先结束的话

如图, num1 [2, 2 ,3, 0, 0, 0] (这里面0,0,0 是合并后数组大小,并没有开始赋值,所以为0) num2[1, 1, 6]
2 > 1, end1–, 然后数组1先结束, 但是合并后的数组中, 并没有数组2中 (1, 1), 所以这里只需判断下, 把第二个数组剩余的值,赋给那个合并的数组哪里。
在这里插入图片描述

第二个数组先结束的话
如图 结果就完成,剩下的 1,2,
无需变动,自然在数组num1中
在这里插入图片描述
思路二代码如下

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int end1  = m - 1, end2 = n - 1, end = m + n - 1;

    while(end1 >= 0 && end2 >= 0)
    {
        if(nums1[end1] > nums2[end2])
        {
            nums1[end--] = nums1[end1--];
            //这步意思是
           //nums1[end] = nums1[end1];
           // end--;
           //end1--;
        }
        else
        {
            nums1[end--] = nums2[end2--];
        }
    } 

    while(end2 >= 0)
    {
        nums1[end--] = nums2[end2--];
    }
}

轮转数组

消失的数字

这里两个题, 在我另一篇数据结构与算法的博客中有讲解,
博客链接如下:消失的数字,轮转数组的博客链接

当然你的关注与支持就是对我最大的鼓励,后面可能会有补充,敬请期待

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔了岁月.c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值