leetcode 数组中重复的数据
数组中重复的数据
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[2,3]
示例 2:
输入:nums = [1,1,2]
输出:[1]
示例 3:
输入:nums = [1]
输出:[]
提示:
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
nums 中的每个元素出现 一次 或 两次
Java
package com.jerry.stack.algorithm.test;
import cn.hutool.core.date.StopWatch;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* LeetCode672,数组中重复的数据
*
* @author zrj
* @since 2022/5/16
**/
public class FindDuplicates {
public static void main(String[] args) {
int[] nums = {4, 3, 2, 7, 8, 2, 3, 1};
int[] nums2 = {4, 3, 2, 7, 8, 2, 3, 1};
int[] nums3 = {1};
StopWatch stopWatch = new StopWatch("findDuplicatesNums");
stopWatch.start("findDuplicatesNums-one");
List<Integer> distinct = findDuplicatesNums(nums);
System.out.println("方式一,执行结果:" + distinct);
stopWatch.stop();
stopWatch.start("findDuplicatesNums-two");
List<Integer> distinct2 = findDuplicatesNums2(nums);
System.out.println("方式二,执行结果:" + distinct2);
stopWatch.stop();
stopWatch.start("findDuplicatesNums-three");
List<Integer> distinct3 = findDuplicatesNums3(nums);
System.out.println("方式三,执行结果:" + distinct3);
stopWatch.stop();
stopWatch.start("findDuplicatesNums-for");
List<Integer> distinct4 = findDuplicatesNums4(nums2);
System.out.println("方式四,执行结果:" + distinct4);
stopWatch.stop();
// 打印出耗时
System.out.println(stopWatch.prettyPrint());
}
/**
* 方式一:找出数组重复的数字
* 通过Set的add方法找到重复的数字
*
* @param nums 数组
* @return List
*/
private static List<Integer> findDuplicatesNums(int[] nums) {
int length = nums.length;
Set<Integer> set = new HashSet<>(length);
List<Integer> result = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
if (!set.add(nums[i])) {
result.add(nums[i]);
}
}
return result;
}
/**
* 方式二:找出数组重复的数字
* 通过双层循环遍历对比
*
* @param nums 数组
* @return List
*/
private static List<Integer> findDuplicatesNums2(int[] nums) {
int length = nums.length;
List<Integer> result = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
if (nums[i] == nums[j]) {
result.add(nums[i]);
}
}
}
return result;
}
/**
* 方式三:找出数组重复的数字
* 先排序,在通过对比坐标,坐标与值不等则重复
*
* @param nums 数组
* @return List
*/
private static List<Integer> findDuplicatesNums3(int[] nums) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
//返回一个数的绝对值
int index = Math.abs(nums[i]) - 1;
// 如果当前位置的值是负数,说明出现过重复的
if (nums[index] < 0) {
res.add(index + 1);
continue;
}
nums[index] = -nums[index];
}
return res;
}
/**
* 方式四:找出数组重复的数字
* 将已经存在的转换为对应的负数,若转换后值为负数
*
* @param nums 数组
* @return List
*/
private static List<Integer> findDuplicatesNums4(int[] nums) {
int length = nums.length;
for (int i = 0; i < length; ++i) {
//把当前元素放到对应的位置
while (nums[i] != nums[nums[i] - 1]) {
swap(nums, i, nums[i] - 1);
}
}
// 如果当前元素的值和对应的下标不一致,说明出现了两次
List<Integer> res = new ArrayList<>();
for (int i = 0; i < length; ++i) {
if (nums[i] - 1 != i) {
res.add(nums[i]);
}
}
return res;
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
执行结果
Connected to the target VM, address: '127.0.0.1:55447', transport: 'socket'
方式一,执行结果:[2, 3]
方式二,执行结果:[3, 2]
方式三,执行结果:[2, 3]
方式四,执行结果:[3, 2]
StopWatch 'findDuplicatesNums': running time = 584800 ns
---------------------------------------------
ns % Task name
---------------------------------------------
000458800 078% findDuplicatesNums-one
000040100 007% findDuplicatesNums-two
000058000 010% findDuplicatesNums-three
000027900 005% findDuplicatesNums-for
Process finished with exit code 0