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

简介: 剑指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--];
    }
}

轮转数组

消失的数字

这里两个题, 在我另一篇数据结构与算法的博客中有讲解,

博客链接如下:消失的数字,轮转数组的博客链接

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



相关文章
|
11天前
|
Java
Java 基础语法-面试题(54-63道)(数组+类+包)
Java 基础语法-面试题(54-63道)(数组+类+包)
29 16
|
5天前
|
安全 编译器 C++
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
|
1月前
|
存储 算法
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
|
2月前
|
开发框架 .NET
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
|
2月前
|
数据采集 算法 数据挖掘
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】
|
3月前
【一刷《剑指Offer》】面试题 23:从上往下打印二叉树
【一刷《剑指Offer》】面试题 23:从上往下打印二叉树
|
3月前
【一刷《剑指Offer》】面试题 22:栈的压入、弹出系列
【一刷《剑指Offer》】面试题 22:栈的压入、弹出系列
|
3月前
|
算法
【一刷《剑指Offer》】面试题 21:包含 main 函数的栈
【一刷《剑指Offer》】面试题 21:包含 main 函数的栈
|
3月前
【一刷《剑指Offer》】面试题 20:顺时针打印矩阵
【一刷《剑指Offer》】面试题 20:顺时针打印矩阵
|
3月前
【一刷《剑指Offer》】面试题 19:二叉树的镜像
【一刷《剑指Offer》】面试题 19:二叉树的镜像