首页 > 其他分享 >面试经典1-2题

面试经典1-2题

时间:2024-11-26 18:35:14浏览次数:6  
标签:p1 int 复杂度 面试 数组 经典 nums1 指针

1.合并两个有序数组

链接:88. 合并两个有序数组 - 力扣(LeetCode)

方法一:直接合并后排序

最直观的方法是先将数组 nums2​ 放进数组 nums1​ 的尾部,然后直接对整个数组进行排序。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        for (int i = 0; i != n; ++i) {
            nums1[m + i] = nums2[i];
        }
        Arrays.sort(nums1);
    }
}

复杂度分析

时间复杂度:O((m+n)log(m+n))。
排序序列长度为 m+n,套用快速排序的时间复杂度即可,平均情况为 O((m+n)log(m+n))。

空间复杂度:O(log(m+n))。
排序序列长度为 m+n,套用快速排序的空间复杂度即可,平均情况为 O(log(m+n))。

方法二:双指针

方法一没有利用数组 nums1与 nums2已经被排序的性质。为了利用这一性质,我们可以使用双指针方法。这一方法将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中。

我们为两个数组分别设置一个指针 p1​ 与 p2​ 来作为队列的头部指针。代码实现如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = 0, p2 = 0;
        int[] sorted = new int[m + n];
        int cur;
        while (p1 < m || p2 < n) {
            if (p1 == m) {
                cur = nums2[p2++];
            } else if (p2 == n) {
                cur = nums1[p1++];
            } else if (nums1[p1] < nums2[p2]) {
                cur = nums1[p1++];
            } else {
                cur = nums2[p2++];
            }
            sorted[p1 + p2 - 1] = cur;
        }
        for (int i = 0; i != m + n; ++i) {
            nums1[i] = sorted[i];
        }
    }
}

复杂度分析

时间复杂度:O(m+n)。
指针移动单调递增,最多移动 m+n 次,因此时间复杂度为 O(m+n)。

空间复杂度:O(m+n)。
需要建立长度为 m+n 的中间数组 sorted。

方法三:逆向双指针

方法二中,之所以要使用临时变量,是因为如果直接合并到数组 nums1中,nums1中的元素可能会在取出之前被覆盖。那么如何直接避免覆盖 nums1中的元素呢?观察可知,nums1的后半部分是空的,可以直接覆盖而不会影响结果。因此可以指针设置为从后向前遍历,每次取两者之中的较大者放进 nums1的最后面。严格来说,在此遍历过程中的任意一个时刻,nums1数组中有 m − p1 − 1 个元素被放入 nums1的后半部,nums2数组中有 n − p2 − 1 个元素被放入 nums1的后半部,而在指针 p1的后面,nums1数组有 m + n − p1 − 1 个位置。由于m + n − p1 − 1 ≥ m − p1 − 1 + n − p2 − 1等价于p2 ≥ −1永远成立,因此 p1后面的位置永远足够容纳被插入的元素,不会产生 p1的元素被覆盖的情况。

实现代码如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1, p2 = n - 1;
        int tail = m + n - 1;
        int cur;
        while (p1 >= 0 || p2 >= 0) {
            if (p1 == -1) {
                cur = nums2[p2--];
            } else if (p2 == -1) {
                cur = nums1[p1--];
            } else if (nums1[p1] > nums2[p2]) {
                cur = nums1[p1--];
            } else {
                cur = nums2[p2--];
            }
            nums1[tail--] = cur;
        }
    }
}

复杂度分析

时间复杂度:O(m+n)。
指针移动单调递减,最多移动 m+n 次,因此时间复杂度为 O(m+n)。

空间复杂度:O(1)。
直接对数组 nums1原地修改,不需要额外空间。

2.移除元素

链接:27. 移除元素 - 力扣(LeetCode)

方法一:双指针

由于题目要求删除数组中等于 val 的元素,因此输出数组的长度一定小于等于输入数组的长度,我们可以把输出的数组直接写在输入数组上。可以使用双指针:右指针 right 指向当前将要处理的元素,左指针 left 指向下一个将要赋值的位置。

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

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

整个过程保持不变的性质是:区间 [0,left) 中的元素都不等于 val。当左右指针遍历完输入数组以后,left 的值就是输出数组的长度。

这样的算法在最坏情况下(输入数组中没有元素等于 val),左右指针各遍历了数组一次

class Solution {
    public int removeElement(int[] nums, int val) {
        int n = nums.length;
        int left = 0;
        for (int right = 0; right < n; right++) {
            if (nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多两次。

  • 空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

方法二:双指针优化

思路

如果要移除的元素恰好在数组的开头,例如序列 [1,2,3,4,5],当 val 为 1 时,我们需要把每一个元素都左移一位。注意到题目中说:「元素的顺序可以改变」。实际上我们可以直接将最后一个元素 5 移动到序列开头,取代元素 1,得到序列 [5,2,3,4],同样满足题目要求。这个优化在序列中 val 元素的数量较少时非常有效。

实现方面,我们依然使用双指针,两个指针初始时分别位于数组的首尾,向中间移动遍历该序列。

算法

如果左指针 left 指向的元素等于 val,此时将右指针 right 指向的元素复制到左指针 left 的位置,然后右指针 right 左移一位。如果赋值过来的元素恰好也等于 val,可以继续把右指针 right 指向的元素的值赋值过来(左指针 left 指向的等于 val 的元素的位置继续被覆盖),直到左指针指向的元素的值不等于 val 为止。

当左指针 left 和右指针 right 重合的时候,左右指针遍历完数组中所有的元素。

这样的方法两个指针在最坏的情况下合起来只遍历了数组一次。与方法一不同的是,方法二避免了需要保留的元素的重复赋值操作。

class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length;
        while (left < right) {
            if (nums[left] == val) {
                nums[left] = nums[right - 1];
                right--;
            } else {
                left++;
            }
        }
        return left;
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多一次。

  • 空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

标签:p1,int,复杂度,面试,数组,经典,nums1,指针
From: https://blog.csdn.net/weixin_74146322/article/details/144035752

相关文章

  • Hadoop面试题总结
    1.1、介绍Hadoop广义上来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈。狭义上说,Hadoop指Apache这款开源框架,它的核心组件有:(1)、HDFS(分布式文件系统):解决海量数据存储(2)、YARN(作业调度和集群资源管理的框架):解决资源任务调度(3)、MAPREDUCE(分布式运算编程框架):解决海量......
  • 面试课程__性能测试讲解(5.1)
    一、你做过性能测试吗?方法1:做过方法2:在公司性能是专门性能小组做的,但是我也会做二、性能测试有哪些类型?(1)压力测试(破坏性测试)压力测试是系统在一定饱和状态下,例如:cpu、内存、磁盘io在饱和使用情况下,不断给系统施加压力,看系统处理能力,以及系统是否会出现错误;(2)负载测试负载测......
  • 重温经典,一网万游:在线红白机FC游戏平台:webgame.one
    前言还记得小时候守在电视机前,手握红白机手柄,沉浸在《魂斗罗》紧张刺激的战斗、《超级马里奥兄弟》奇妙的冒险世界,或是与小伙伴一起在《坦克大战》里并肩作战的美好时光吗?那些经典的FC游戏,承载着我们童年最纯真的快乐与回忆。如今,有一个名为webgame.one的在线FC游戏平台......
  • 面试题精选12-聚集索引和非聚集索引
    聚集索引和非聚集索引包括哪些在Mysql中,聚集索引一般指的是主键。非聚集索引指的是辅助索引、二级索引。聚集索引和非聚集索引优缺点查询速度上,聚集索引优于非聚集索引。插入数据速度上,非聚集索引要比聚集索引要快。聚集索引特点一个表只能有一个聚集索引,通常是主键,但不......
  • 华为技术岗位笔试&面试题-第四篇
    说在前面本篇文章是华为技术岗位笔试&面试题-第四篇后续将持续推出互联网大厂,如阿里,腾讯,百度,美团,头条等技术面试题目,以及答案,专家出题人分析汇总。欢迎大家点赞关注转发问题1:一个指针可以是volatile吗可以,因为指针和普通变量一样,有时也有变化程序的不可控性。常见例:子中......
  • springmvc核心点(面试题)
    一,什么是SpringMVC   SpringMVC是基于Java的实现了MVC设计模式的轻量级Web框架,通过把Model,View,Controller分离,将Web层进行职责解耦把复杂的Web应用分成逻辑清晰的几部分,简化开发,减少出错,方便开发人员之间的配合二,什么是MVCMVC主要的用途就是对组件之间进行隔离分层M:......
  • 重拾JS-手写bind(延伸作用域理解,有助于面试)
    简言最近在做前端知识的复习和整理,有了一些自己新的体会。更多在于记录,通过反复的温习,写笔记改变自己以前学习知识点的误区关于Bind,Apply,Call大家本能知道,当函数调用他们的时候就会将函数中的this,显示指向他们的第一个参数(新对象),那么为什么大家在面试或者其他场景下仍然会因......
  • 极智嘉嵌入式面试题及参考答案
    对于交叉编译器的理解交叉编译器是一种在一个计算机平台上为另一个不同架构的计算机平台生成可执行代码的编译器。它在嵌入式系统开发中起着关键作用。从其必要性来看,嵌入式系统通常使用的处理器架构与我们日常使用的PC等通用计算机不同,如ARM、MIPS等。而我们开发嵌入......
  • Java面试要点41 - Java时间日期API
    文章目录一、引言二、传统日期时间API的不足三、Java8新日期时间API四、日期时间格式化与解析五、时区处理总结一、引言在Java开发中,时间日期处理是一个非常常见且重要的话题。从Java8开始,Java引入了全新的日期时间API,这些新的API不仅解决了原有java.util.Date......
  • Java面试要点42 - Java IO:字节流与字符流详解
    文章目录一、引言二、IO流的基本概念三、字节流体系四、字符流体系五、字节流与字符流的转换六、IO操作的最佳实践6.1资源管理和异常处理6.2性能优化策略6.3字符编码处理6.4现代文件操作API的使用6.5安全性考虑总结一、引言在Java编程中,IO(输入/输出)操作是一......