Java中关于Map,Set问题之只出现一次的数字,复制带随机指针的链表,宝石与石头,前K个高频单词

1.只出现一次的数字

在这里插入图片描述

public int singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int x:nums) {
            Integer count = map.get(x);
            if (count == null) {
                map.put(x,1);
            }else {
                map.put(x,count+1);
            }
        }
        //System.out.println(map);
        for (Map.Entry<Integer,Integer> entry:map.entrySet()) {
            if (entry.getValue().equals(1)) {
                return entry.getKey();
            }
        }
        return 0;
    }

我们可以利用键值对来进行解决,Key为数组中的每个元素,value为每个数字出现的次数,我们创建一个Map,遍历数组,如果通过key不能找到,则把(key,1)加入到map里,表示key这个关键字出现一次,如果找到了,就把(x,count+1)存到里面,因为当key重复时,会自动把以前的value修改为当前要插入的value,当整个数组遍历完后,我们的Map也就完成了,通过遍历Map来找出value为1的关键字,就是我们要找的出现一次的数。

但是这个问题还可以用另一种方法来解决:

public int singleNumber2(int[] nums) {
        int ret = 0;
        for (int x:nums) {
            ret^=x;         //a^b^b=a
        }
        return ret;
    }

简单的几行代码就可以,但其中的内涵并不是那么简单。这个是通过一个数异或两个相同的数,最终结果还是他本身这个特性来解决的,这个思路值得我们去学习。

2.复制带随机指针的链表

在这里插入图片描述
节点结构如下:

class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};

题中要求的是深拷贝,就需要我们去拷贝链表中的每一个节点,每个节点之间的关系也要和原来一样。

 public Node copyRandomList(Node head) {
        Map<Node,Node> map = new HashMap<>();
        for (Node cur = head;cur!=null;cur=cur.next) {
            map.put(cur,new Node(cur.val));
        }
        for (Node cur = head;cur!=null;cur=cur.next) {
            Node newNode = map.get(cur);
            newNode.next = map.get(cur.next);
            newNode.random = map.get(cur.random);
        }
        return map.get(head);
    }

我们依然可以用Map来解决,通过遍历旧的链表,把旧的链表中的节点当为key,然后通过旧链表的val值新建的节点作为value,形成通过旧节点可以找到新节点的关系。
然后再次去遍历链表,通过旧的节点,找到新的节点,新节点的next和random也就可以通过旧节点的next和random来找到,最后通过旧链表的头节点找到新链表的头节点并返回,这个问题就解决了。

3.宝石与石头

在这里插入图片描述

 public int numJeweIsInStones(String J,String S) {
        int count = 0;
        Set<Character> set = new HashSet<>();
        for (int i = 0;i<J.length();i++) {
            set.add(J.charAt(i));
        }
        for (int i = 0;i<S.length();i++) {
            if (set.contains(S.charAt(i))) {
                count++;
            }
        }

        return count;

    }

判断是否存在问题,我们想到可以用set,判断s中有多少是宝石,我们可以将J存到set里面,然后遍历S中的每一个,看set里面是否存在,若存在,则count加一,遍历结束后返回最终的count,就是宝石的数目。

4.前K个高频单词在这里插入图片描述

 public List<String> topKFrequent(String[] words,int k) {
        Map<String,Integer> map = new HashMap<>();
        for (String x:words) {
            Integer value = map.get(x);
            if (value == null) {
                map.put(x,1);
            }else {
                map.put(x,value+1);
            }
            List<String> result = new ArrayList<>(map.keySet());
            Collections.sort(result, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    //在这个匿名内部类里面可以访问到上面的map变量
                    int count1 = map.get(o1);
                    int count2 = map.get(o2);
                    if (count1 == count2) {
                        return o1.compareTo(o2);//默认字典序
                    }
                    return count2-count1;
                }
            });
            //取前K个
            return result.subList(0,k);
        }
    }

首先创建一个Map,key为字符串数组中的元素,value为每个元素出现的次数,由于函数的返回值类型是List,所以我们创建一个List把Map里面的key传到链表里面,有个keySet()操作,然后利用标准库中的排序对类进行排序,这里需要重写比较器,通过Key获取到每个数出现的次数,如果两个数相同,就按系统默认的字典序进行排序,否则就按从大到小进行排序,排好之后,直接利用链表的subList截取操作截取前K个元素返回,问题就完成了。

猜你喜欢

转载自blog.csdn.net/AIJXB/article/details/106145687