这是悦乐书的第279次更新,第295篇原创

01 看题和准备

今天介绍的是LeetCode算法题中Easy级别的第147题(顺位题号是645)。集合S最初包含从1到n的数字。 但不幸的是,由于数据错误,集合中的一个数字被复制到集合中的另一个数字,这导致重复一个数字而丢失另一个数字。给定一个数组nums,表示错误后该集的数据状态。要求先找到两次出现的数字,然后找到丢失的数数字,最后以数组的形式返回它们。例如:

输入:nums = [1,2,2,4]

输出:[2,3]

注意:

  • 给定的数组大小将在[2,10000]范围内。

  • 给定数组的数字无序。

本次解题使用的开发工具是eclipse,jdk使用的版本是1.8,环境是win7 64位系统,使用Java语言编写和测试。

02 第一种解法

题目的意思是根据给出的数组,找出两个数,第一个数是该数组中重复出现的那个数,第二个数是该数组中缺失的那个数,也就是说最后返回的结果数组,两个数是有先后顺序的。

先对数组排序,然后从第二位开始遍历数组,如果当前一位与前一位相等,说明重复了,那么第一位数就找到了。如果当前元素比前一位元素加1后还要大,说明前一位元素是重复出现的那个数的第二个,也就是要找的缺失的那个数。

但是,还有两种特殊情况需要考虑,因为题目并不能保证数组首尾不缺少元素。第一,nums的第一位是不是从1开始?如果不是,那么第二个数就是1。第二,nums的最后一位元素是不是和数组长度相等?如果不相等,那么第二个数就是数组的长度。

此解法的时间复杂度是O(nlog(n)),空间复杂度是O(1)。

public int[] findErrorNums(int[] nums) {
// 排序
Arrays.sort(nums);
int[] result = new int[2];
for (int i=1; i<nums.length; i++) {
if (nums[i] == nums[i-1]) {
// 第一个数,重复出现的元素
result[0] = nums[i];
} else if (nums[i] > nums[i-1]+1) {
// 第二个数,缺失的那个数
result[1] = nums[i-1]+1;
}
}
// 数组第一个元素不是1
if (nums[0] != 1) {
result[1] = 1;
} else if (nums[nums.length-1] != nums.length) {
// 数组最后一个元素不是数组的长度
result[1] = nums.length;
}
return result;
}

03 第二种解法

我们也可以不排序,使用HashMap。先将数组的元素都添加进map中,以元素值为key,出现次数为value。然后开始循环,从0到数组的长度,如果map中包含当前索引值加1,并且它出现的次数为2次,那么第一个数就是该元素,否则第二个元素就是当前缺失的索引值加1。

此解法的时间复杂度是O(n),最坏情况是O(n^2),空间复杂度是O(n)。

public int[] findErrorNums(int[] nums) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0)+1);
}
for (int i=0; i<nums.length; i++) {
if (map.containsKey(i+1)) {
// 出现两次的重复元素
if (map.get(i+1) == 2) {
result[0] = i+1;
}
} else {
// 缺失的元素
result[1] = i+1;
}
}
return result;
}

04 第三种解法

我们也可以不使用HashMap,使用数组进行代替。思路与第二种解法类似。

此解法的时间复杂度是O(n),空间复杂度是O(n)。

public int[] findErrorNums(int[] nums) {
int[] result = new int[2];
// 新建一个数组,长度比nums大1
int[] arr = new int[nums.length+1];
for (int i=0; i<nums.length; i++) {
// 以nums的元素作为索引,出现次数为value
arr[nums[i]]++;
}
// 数组的元素值是从1开始的,所以新数组也从第二位开始遍历
for (int i=1; i<arr.length; i++) {
// 重复出现的元素
if (arr[i] == 2) {
result[0] = i;
} else if (arr[i] == 0) {
// 缺失的元素
result[1] = i;
}
}
return result;
}

05 第四种解法

我们还可以使用减法。先将数组元素正常情况下的元素之和算出来,因为是从1到n的数,是一个公差为1的等差数列,可以直接套用等差数列求和的公式来计算和,然后用算出来的和减去数组中的每一个元素,最后和可能是正1,也可能是负1,因为数组中有重复元素,也就可能多1或者少1,也即是重复项元素值多1或者少1,所以缺失的那个数可以直接使用最后的和与重复项元素相加得到。

此解法的时间复杂度是O(n),空间复杂度是O(n)。

public int[] findErrorNums(int[] nums) {
int[] result = new int[2];
// 定义一个HashSet
Set<Integer> set = new HashSet<Integer>();
// 等差数列求和公式
long sum = nums.length*(nums.length+1)/2;
for (int i=0; i<nums.length; i++) {
// 重复出现的那个数
if (set.contains(nums[i])) {
result[0] = nums[i];
}
set.add(nums[i]);
// 减去每一个元素
sum -= nums[i];
}
// sum最后可能是正数,也可能是负数,与重复元素相加后,正好是缺失的那个数
result[1] = (int)sum + result[0];
return result;
}

06 第五种解法

我们可以对原数组进行标记,将元素变成负数,如果遇到的元素是小于0的,说明已经对该元素变过一次负数,也就是说该元素重复了,最后在遍历一次数组,如果遇到大于0的数,表明在该位置缺少一个元素。

此解法的时间复杂度是O(n),空间复杂度是O(1)。

public int[] findErrorNums(int[] nums) {
int[] result = new int[2];
for (int num : nums) {
if (nums[Math.abs(num)-1] < 0) {
// 已经转过一次负数的数,表明重复
result[0] = Math.abs(num);
} else {
// 将所有元素转为负数
nums[Math.abs(num)-1] *= -1;
}
}
for (int i=1; i<nums.length; i++) {
// 剩下那个没有被转成负数的数
if (nums[i] > 0) {
result[1] = i+1;
}
}
return result;
}

07 第六种解法

此解法是使用异或运算,来自讨论区。传送门:https://leetcode.com/problems/set-mismatch/discuss/105513/XOR-one-pass

public int[] findErrorNums(int[] nums) {
int[] ans = new int[2];
for(int i = 0; i < nums.length; i++) {
int val = Math.abs(nums[i]);
ans[1] ^= (i+1) ^ val;
if (nums[val-1] < 0) ans[0] = val;
else nums[val-1] = -nums[val-1];
}
ans[1] ^= ans[0];
return ans;
}

08 小结

算法专题目前已日更超过四个月,算法题文章147+篇,公众号对话框回复【数据结构与算法】、【算法】、【数据结构】中的任一关键词,获取系列文章合集。

以上就是全部内容,如果大家有什么好的解法思路、建议或者其他问题,可以下方留言交流,点赞、留言、转发就是对我最大的回报和支持!

LeetCode算法题-Set Mismatch(Java实现)的更多相关文章

  1. LeetCode算法题-Heaters(Java实现)

    这是悦乐书的第239次更新,第252篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第106题(顺位题号是475).冬天来了!您在比赛期间的第一份工作是设计一个固定温暖半径 ...

  2. LeetCode算法题-Sqrt(Java实现)

    这是悦乐书的第158次更新,第160篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第17题(顺位题号是69). 计算并返回x的平方根,其中x保证为非负整数. 由于返回类型 ...

  3. LeetCode算法题-Subdomain Visit Count(Java实现)

    这是悦乐书的第320次更新,第341篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第189题(顺位题号是811).像"discuss.leetcode.com& ...

  4. LeetCode算法题-Number of Lines To Write String(Java实现)

    这是悦乐书的第319次更新,第340篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第188题(顺位题号是806).我们要将给定字符串S的字母从左到右写成行.每行最大宽度为 ...

  5. LeetCode算法题-Unique Morse Code Words(Java实现)

    这是悦乐书的第318次更新,第339篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第186题(顺位题号是804).国际莫尔斯电码定义了一种标准编码,其中每个字母映射到一系 ...

  6. LeetCode算法题-Rotate String(Java实现)

    这是悦乐书的第317次更新,第338篇原创 在开始今天的算法题前,说几句,今天是世界读书日,推荐两本书给大家,<终身成长>和<禅与摩托车维修艺术>,值得好好阅读和反复阅读. 0 ...

  7. LeetCode算法题-Rotated Digits(Java实现)

    这是悦乐书的第316次更新,第337篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第185题(顺位题号是788).如果一个数字经过180度旋转后,变成了一个与原数字不同的 ...

  8. LeetCode算法题-Letter Case Permutation(Java实现)

    这是悦乐书的第315次更新,第336篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第184题(顺位题号是784).给定一个字符串S,将每个字母单独转换为小写或大写以创建另 ...

  9. LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)

    这是悦乐书的第314次更新,第335篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第183题(顺位题号是783).给定具有根节点值的二叉搜索树(BST),返回树中任何两个 ...

随机推荐

  1. 干货 | Java8 新特性教程

    本教程翻译整理自 https://github.com/winterbe/java8-tutorial 本教程首发自个人网站: https://www.exception.site/java8/jav ...

  2. java多线程(3)---synchronized、Lock

    synchronized.Lock 一.概述 1.出现线程不安全的原因是什么? 如果我们创建的多个线程,存在着共享数据,那么就有可能出现线程的安全问题:当其中一个线程操作共享数据时,还未操作完成,另外 ...

  3. asp.net core 系列 16 Web主机 IWebHostBuilder

    一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...

  4. es6学习笔记--模板字符串

    这几天简单看了一下深入浅出es6这本书,感觉特实用,学习了一个新特性---模板字符串在项目开发中,拼接字符串是不可缺少的,动态创建dom元素以及js操作数据都要拼接字符串,在es6出来之前,我们都通常 ...

  5. Java基础11:Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 本文参考https://blog.csdn.net/s10461/article/details/53941091 具体代码在我的GitHub中可以找 ...

  6. Linux~上部署.net MVC出现的问题与解决

    这几天一直在搞linux下面的.net mvc的部署工作,遇到了很多问题,还好有一些朋友的帮助,问题才得到了解决! 环境:Linux+Mono+Jexus 希望的结果:直接运行windows+vist ...

  7. 记一次查询超时的解决方案The timeout period elapsed......

    问题描述 在数据库中执行查询语句,大约1秒钟查询出来,在C#中用ado进行连接查询,一直等待很久未查出结果,最后抛出查询超时异常. 异常内容如下: Execution Timeout Expired. ...

  8. Mybatis源码之StatementType

      在mybatis中StatementType的值决定了由什么对象来执行我们的SQL语句.本文来分析下在mybatis中具体是怎么处理的. StatementType 1.StatementType ...

  9. Shiro源码分析之SecurityManager对象获取

    目录 SecurityManager获取过程 1.SecurityManager接口介绍 2.SecurityManager实例化时序图 3.源码分析 4.总结 @   上篇文章Shiro源码分析之获 ...

  10. spring boot(四) 多数据源

    前言 前一篇中我们使用spring boot+mybatis创建了单一数据源,其中单一数据源不需要我们自己手动创建,spring boot自动配置在程序启动时会替我们创建好数据源. 准备工作 appl ...