2020-09-06腾讯笔试

前言

上次没有参加,以为可以避免参加,这次是回学校以后参加的,果然自己蠢得不行,写题目都没有思路,于是被自己的智商吊打,不过事情已经过了,只能抱着每一次挫折都是前进的冲锋号来鼓励自己了,然后参照他人的题解,将题目做一个复盘吧!

1. 降序链表公共部分

题目:
降序排列的链表,求出当前链表的公共部分
6
6 5 4 3 2 1
5
6 5 3 2 1

题目很清晰了,只是用链表来混淆视听实质就是求两个的公共数字。

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n =scanner.nextInt();
        List<Integer> res = new ArrayList<>();
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < n; i++) {
            set.add(scanner.nextInt());
        }
        int m = scanner.nextInt();
        for (int i = 0; i < m; i++) {
            int tmp = scanner.nextInt();
            if(!set.add(tmp)){
                res.add(tmp);
            }
        }
        for (Integer re : res) {
            System.out.print(re+" ");
        }
    }
}

2. 消息覆盖的人数

题目:
通知传递,n个人(序号0~n),m个小组,每个小组有k个人,1个人也能在不同的小组。由0发起的一个通知,每个人都能把通知告诉自己同组的人,求最后收到通知的人数。
50 5
2 1 2
5 10 11 12 13 14
2 0 1
2 49 2
4 6 7 8 2

最后结果7 => 0 1 2 6 7 8 49

这是道并查集问题,以为会有通用的解法,实质上还是使用暴力解法。利用一个HashMap将所有人关联到的对象放入到一个Set中,然后最后将0中的元素遍历,利用Set存储即可

public class Solution {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        Map<Integer, Set<Integer>> map = new HashMap<>();
        for (int i = 0; i < m; i++) {
            int k = scanner.nextInt();
            Set<Integer> set = new HashSet<>();
            // 在处理过程中遍历所有的元素
            // 这是当前这个分组中所有的元素
            for (int j = 0; j < k; j++) {
                set.add(scanner.nextInt());
            }
            // 建立一个图,即获取当前元素的一个set集合
            for (Integer integer : set) {
                Set<Integer> set1 = map.get(integer);
                if (set1 == null || set1.isEmpty()) {
                    map.put(integer, set);
                    continue;
                }
                // 如果当前已经有的话再添加一次
                set1.addAll(set);
                map.put(integer, set1);
            }
        }
        System.out.println(map);
        // 现在需要遍历所有的然后加入即可
        Queue<Integer> queue = new LinkedList<>(map.get(0));
        // 使用一个set来存储结果
        Set<Integer> result = new HashSet<>();
        while (!queue.isEmpty()) {
            Integer poll = queue.poll();
            Set<Integer> integers = map.get(poll);
            // 结果集中不包含的才可以放入,否则排除
            for (Integer integer : integers) {
                if (!result.contains(integer)) {
                    queue.add(integer);
                    result.add(integer);
                }
            }
        }
        System.out.println(result);
        System.out.println(result.size());
    }
}

3. 取出出现次数最多的k个字符和出现次数最少的k个字符

题目:
输入N个字符串(有重复),输出这N个字符串中出现次数最多的前K个及出现次数最少的前K个和他们的出现的次数,注意出现次数一样的时候都要进行字典排序

这里主要是一个重排序的问题,因为要求最多,和最少,此时需要进行两次排序即可,第一遍排序取出最多的,第二遍排序取出最小的k个即可。

这里注意,在比较器中,基本默认的排序都是从小到大排,即在比较器中的逻辑就是 i1 > i2 返回正数。如果想要从大到小就要颠覆这个即i1 > i2 返回负数,反之亦然。同时这里由于涉及到字典序的问题,即如果数字出现次数相同,按照字典序排。

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();// 出现次数最多的k个,和出现次数最小的k个
        Map<String, Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            String val = scanner.next();
            map.put(val, map.getOrDefault(val, 0) + 1);
        }
        List<Word> list = new ArrayList<>();
        for (String s : map.keySet()) {
            list.add(new Word(s, map.get(s)));
        }
        // 重写比较器
        list.sort((o1, o2) -> {
            // 先比较出现次较多
            // 默认是小的排在前面,但是如果想让大的排在前面的话,需要使用小于则返回1
            if (o1.rank < o2.rank) return 1; 
            if (o1.rank > o2.rank) return -1;
            return o1.str.compareTo(o2.str);
        });
        // 输出后k个
        for (int i = 0; i < k; i++) {
            Word word = list.get(i);
            System.out.println(word.str + " " + word.rank);
        }
        list.sort((o1, o2) -> {
            // 先比较出现次比较少的两个
            if (o1.rank > o2.rank) return 1;
            if (o1.rank < o2.rank) return -1;
            return o1.str.compareTo(o2.str);
        });
        for (int i = 0; i < k; i++) {
            Word word = list.get(i);
            System.out.println(word.str + " " + word.rank);
        }
    }
}

class Word {
    String str;
    int rank;

    public Word(String str, int rank) {
        this.str = str;
        this.rank = rank;
    }
}

4. 求数组的中位数

题目:
给定一个偶数的数组,求去掉下表为i的数字的时候,整个数组的中位数是多少,注意是无序的。

思路:刚开始是想的利用list来,每次移除,然后排序,然后输出中位数,无奈时间复杂度过高。后面参考别人的写法,发现其实去掉下标i,中位数其实就是在中间的两个数之间摆动,占用了前面的位置,则输出后面的为中位数,占用了后面的则输出前面的为中位数。

public class Solution {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }
        if (n == 2) {
            System.out.println(a[0]);
        }
        // 拷贝一份数组
        int[] t = Arrays.copyOf(a, n);
        Arrays.sort(t);
        int l = t[n / 2 - 1];
        int r = t[n / 2];
        // 这一步处理的很妙,因为中位数无非就是两个,只有轮到两个被删除的时候
        // 此时中位数才会被替换为对方,所以只需要判断当前值是否小于前一个中位数
        // 如果是的话,当前数在前面,则后面多一个位置,则中位数输出后面的
        // 如果当前的数不小于前一个中位数,表示当前数字在后面,则前面多出一个位置,输出前面的
        for (int i = 0; i < n; i++) {
            if (a[i] <= l) {
                System.out.println(r);
            } else {
                System.out.println(l);
            }
        }
    }
}

5. 最少的次数给红黑棋子排序

这道题不会,题目大致意思也理解,不会

Keep thinking, keep coding!
继续保持加油吧,每一天都会有一个新的起点,每一天充满期待,生活就会变得多彩!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值