「每日一题」与面试官手撕代码:如何科学高效的寻找重复元素?

关注公众号「松宝写代码」,精选好文,每日一题

加入我们一起学习,day day up

经过三天时间,已经有小伙伴(xpf666)给我们贡献文章了,超级开心和激动,因为我们不是一个人在战斗,

不是一个人在努力提高自己,加入我们,

如何加入我们?

第一步:文章下面留言,留言内容:想写什么文章。

第二步:我们就会找到你

作者:xpf666

来源:原创

一、前言

2020.12.23 日刚立的 flag,每日一题,题目类型不限制,可以是:算法题,面试题,阐述题等等。

本文是「每日一题」第 4 题,由 xpf666 带来的文章:如何科学高效的寻找重复元素?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hIiPTZ9s-1609437872523)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/daily_question.png)]

往期「每日一题」:

https://mp.weixin.qq.com/s/QuuPd2KCp50snN7F2o3oYg

https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg

https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA

二、寻找重复元素

1. 找出任意一个重复数字

给定一个长度为 n 的数组 nums,判断是否有重复值。

示例:输入[1,2,3,2,1,4,5] 输出 1 或 2

思路:根据经验,基本上所有判断重复的需求,都可以通过 Set 或者 Map 解决,Set 解决方式就是判断 add 方法的返回是 true 还是 false,false 就证明之前已存在,也就是数据重复。Map 是通过 containsKey,true 就说明之前存在 key。

题解:


public int getResult(int[] nums) {

Set<Integer> set = new HashSet<Integer>();

int result = -1;

for (int num : nums) {

if (!set.add(num)) {

result = num;

break;

}

}

return result;

}

如果上面代码格式出现问题,可以查看下面代码图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hc7vkn6j-1609437872527)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/algorithm/carbon_0.png)]

遍历 n 次并且 Set 内容最多是 n 个字符,复杂度都是 O(n)

2. 找出任意一个重复数字

给定一个长度为 n 的数组 nums,判断是否有重复值,并且两个重复值距离不超过 k。

示例:输入[1,2,3,2,1,4,5] ,k = 2 输出 true(两个 2)

思路:同问题一,只要多判断一次 Set 长度即可。

题解:


public boolean containsNearbyDuplicate(int[] nums, int k) {

Set<Integer> set = new HashSet<Integer>();

boolean result = false;

for (int i = 0; i < nums.length; i++) {

if (!set.add(nums[i])) {

result = true;

break;

}



if (set.size() > k) { // 超过长度就删除最远的一个数

set.remove(nums[i-k]);

}

}

return result;

}

如果上面代码格式出现问题,可以查看下面代码图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQ7mVpnk-1609437872529)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/algorithm/carbon_1.png)]

遍历 n 次并且 k 最多 n 个字符,复杂度都是 O(n)

3. 寻找重复数

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和

n),只有一个重复的整数,找出这个重复的数字。

示例:输入[1,3,4,2,2] 输出 2

思路:可通过问题 1 方式解决。还可以通过快慢指针法解决:将数组看成一个链表,下标为当前指针(node),值指向下一指针(nextNode),数组出现重复的数字意味着有两个指针的 nextNode 相同。然后通过快慢指针法解决。

题解:


public int getResult(int[] nums) {

int result = 0;

int slow = 0, fast = 0;

do {

slow = nums[slow];

fast = nums[nums[fast]];

} while (slow != fast);



do {

slow = nums[slow];

result = nums[result];

} while (result != slow);

return result;

}

如果上面代码格式出现问题,可以查看下面代码图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gNAwgZda-1609437872531)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/algorithm/carbon_2.png)]

遍历 2n 次时间复杂的是 O(n),只用了常量个字符,空间复杂度是 O(1)

4. 只出现一次的数

给定一个数组

nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

示例:输入[1,1,4,2,2] 输出 4

思路:可通过问题 1 方式解决。还可以通过位运算解决,两个相同数异或后为 0,数组所有元素执行一次异或操作,剩下就是出现一次的数。

题解:


public int getResult(int[] nums) {

int result = 0;

for (int num : nums) {

result = result ^ num;

}

return result;

}

如果上面代码格式出现问题,可以查看下面代码图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRaHA7aI-1609437872533)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/algorithm/carbon_3.png)]

遍历 n 次时间复杂的是 O(n),只用了常量个字符,空间复杂度是 O(1)

5. 只出现一次的数

给定一个数组

nums,除了两个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

示例:输入[1,1,3,4,2,2] 输出[3,4]

思路:可通过问题 1 方式解决。还可以通过位运算解决,和题 4 区别是存在 2 个只出现一次的数,所以要想办法把这两个数区分出来。先将数组所有元素异或,得出的值是两个只出现一次元素 a,b 的异或值 numsXOR(如 10010)。numsXOR 二进制中 1 的位就是 a 和 b 差异位(因为不同的值异或才是 1),现在只需要找 lowbit(最右一位差异值,10),然后通过 lowbit 和 a

, b

进行与运算(&),得出的值就一定不同,这样可以分出 a 和 b,最后按照异或运算就能得出结果(其他重复的不用管,不管分到哪一组,重复的数异或都是 0)

题解:


public int[] singleNumber(int[] nums) {

int[] results = new int[]{0,0};

int numsXOR = 0; // 两个数异或值

for (int num : nums) {

numsXOR = numsXOR ^ num;

}



int lowBit = numsXOR & (-numsXOR); // lowbit值,用于区分a和b



for (int num : nums) {

if ((lowBit & num) == 0) {

results[0] = results[0] ^ num;

} else {

results[1] = results[1] ^ num;

}

}



return results;

}

如果上面代码格式出现问题,可以查看下面代码图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wB09Zl5T-1609437872537)(https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/algorithm/carbon_4.png)]

遍历 2n 次时间复杂的是 O(n),只用了常量个字符,空间复杂度是 O(1)

各种福利

关注「松宝写代码」,后台回复

1、字节内推福利

回复「校招」获取内推码

回复「社招」获取内推

回复「实习生」获取内推

后续会有更多福利

2、学习资料福利

回复「算法」获取算法学习资料

3、每日一题

https://mp.weixin.qq.com/s/QuuPd2KCp50snN7F2o3oYg

https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg

https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA

谢谢支持

1、喜欢的话可以「分享,点赞,在看」三连哦。

2、作者昵称:saucxs,songEagle,松宝写代码。字节跳动的一枚前端工程师,一个正在努力成长的作者,星辰大海,未来可期,内推字节跳动各个部门各个岗位。

3、长按下面图片,关注「松宝写代码」,是获取开发知识体系构建,精选文章,项目实战,实验室,每日一道面试题,进阶学习,思考职业发展,涉及到JavaScript,Node,Vue,React,浏览器,http等领域,希望可以帮助到你,我们一起成长~

img-gn8RWR06-1609437872538]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值