【力扣Java】至少在两个数组中出现的值(v & (v - 1))

目录

题目描述

思路解析

map.getOrDefault()

v & (v - 1)

Map.Entry()

解题代码


题目描述

给你三个整数数组 nums1nums2 和 nums3,请你构造并返回一个元素各不相同的数组,且由至少在两个数组中出现的所有值组成数组中的元素可以按任意顺序排列。

示例 1

输入:nums1 = [1,1,3,2], nums2 = [2,3], nums3 = [3]
输出:[3,2]
解释:至少在两个数组中出现的所有值为:
- 3 ,在全部三个数组中都出现过。
- 2 ,在数组 nums1 和 nums2 中出现过。

示例 2

输入:nums1 = [3,1], nums2 = [2,3], nums3 = [1,2]
输出:[2,3,1]
解释:至少在两个数组中出现的所有值为:
- 2 ,在数组 nums2 和 nums3 中出现过。
- 3 ,在数组 nums1 和 nums2 中出现过。
- 1 ,在数组 nums1 和 nums3 中出现过。

示例 3

输入:nums1 = [1,2,2], nums2 = [4,3,3], nums3 = [5]
输出:[]
解释:不存在至少在两个数组中出现的值。

提示

  • 1 <= nums1.length, nums2.length, nums3.length <= 100
  • 1 <= nums1[i], nums2[j], nums3[k] <= 100

思路解析

题目给出三个整数数组 nums1、nums2 和 nums3。现在我们需要求一个元素各不相同的数组,其中的元素为至少在数组 nums1、nums2 和 nums3 中两个数组出现的全部元素。

我们可以用「哈希表」来实现——由于只有三个数组,所以我们一个整数的最低三个二进制位来标记某一个数在哪几个数组中,1 表示该数在对应的数组中的,反之 0 表示不在。最后我们只需要判断每一个数对应的标记数字中二进制位个数是否大于 1 即可。

下面我们介绍一下本题代码用到的几个知识点:

map.getOrDefault()

在JDK8之后,对 map 新增了 getOrDefault() 方法

格式:
Map.getOrDefault(key,默认值);

Map中会存储一一对应的 key 和 value。
如果在 Map 中存在 key,则返回 key 所对应的的 value。
如果在 Map 中不存在 key,则返回默认值。

public class Demo {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("四宫辉夜", 20);
        map.put("凛凛蝶", 24);
        map.put("远坂凛", 23);
        String age= map.getOrDefault("四宫辉夜", 30);
        System.out.println(age);// 20,map中存在"四宫辉夜",使用其对应值20
        String age = map.getOrDefault("雪之下雪乃", 25);
        System.out.println(age);// 25,map中不存在"雪之下雪乃",使用默认值25
    }
}

v & (v - 1)

根据这个二级制数如何判断是否出现 2 次以上,代码巧妙采用了 v&(v-1) 这个公式,它的作用是将 v 的二进制的最右边的一个 1 变为 0,例如 10010100 进行该操作后变成 10010000,所以只有在经历过一个该操作后依旧大于 0 则说明至少在两个数组中出现过,则可以放入答案列表。

这是一个很重要的计算公式,需要牢记哦

Map.Entry()

Map 是 Java 中的接口,Map.Entry 是 Map 的一个内部接口。

Map 提供了一些常用方法,如 keySet()、entrySet() 等方法,keySet() 方法返回值是 Map 中 key 值的集合;entrySet()  的返回值也是返回一个 Set 集合,此集合的类型为 Map.Entry。

Map.Entry 是 Map 声明的一个内部接口,此接口为泛型,定义为 Entry<K,V>。它表示 Map 中的一个实体(一个 key-value 对)。接口中有 getKey(),getValue 方法。

解题代码

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyTest {
    public static void main(String[] args) {
        MyTest m = new MyTest();
        int[] nums1 = {1, 1, 3, 2};
        int[] nums2 = {2, 3};
        int[] nums3 = {3};
        System.out.println(m.twoOutOfThree(nums1, nums2, nums3));
    }

    public List<Integer> twoOutOfThree(int[] nums1, int[] nums2, int[] nums3) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i : nums1) {
            map.put(i, 1);
        }
        for (int i : nums2) {
            map.put(i, map.getOrDefault(i, 0) | 2);
        }
        for (int i : nums3) {
            map.put(i, map.getOrDefault(i, 0) | 4);
        }
        List<Integer> res = new ArrayList<Integer>();
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            int k = entry.getKey(), v = entry.getValue();
            if ((v & (v - 1)) != 0) {
                res.add(k);
            }
        }
        return res;
    }
}

首先第一个循环,我们把 nums1 内的值出现次数记为 1 ,放入 map ,第二个循环我们查看是否 nums2 中的值也在 nums1 中出现,具体用到 Map.getOrDefault() 函数,如果值存在,则 1 | 2,不存在则 0 | 2,第三个循环同理。

解释一下为什么 | 2 和 | 4,1 的二进制是 001,也就是说如果数在第一个数组中存在,我们就把它放到三位中的第三位上,2 的二进制是 010,也就是说如果数在第二个数组中存在,我们就把它放到三位中的第二位上,4 的二进制是 100,也就是说如果数在第三个数组中存在,我们就把它放到三位中的第一位上。

然而 | 运算的运算法则是,0|0=0;  0|1=1;  1|0=1;   1|1=1;

即:参加运算的两个对象只要有一个为 1,其值为 1。

例如:3|4 即 00000011 | 0000 0100 = 00000111  因此,3|4 的值得 7。 

另,负数按补码形式参加按位或运算。

所以我们就可以知道,如果在第二个数组中又出现了第一个数组中的值,则 001 | 010 = 011,以此类推,我们就可以把数字出现的状态记录下来。

最后使用  v&(v-1) 计算出现的次数,如果出现 1 次,001&000=000,值即为 0,出现两次,011&010=010,值不为 0。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java小白。。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值