刷题日记03

难呀,今天这题难呀,直接写的太麻烦了。看了题解发现最容易想出来的方法暴力映射超出了时间限制,其次最容易想出来的是用HashMap做的。

多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3]
输出:3

示例 2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

我先复盘一下我自己最初的思路,我是这么想的,先进行排序,得到升序序列[1,1,1,2,2,2,2]。然后我定义一个Set和一个List分别为set和list,再定义一个计数变量count = 1。遍历数组,假如当前元素a[i]和后一个元素a[i+1]相等,我就在Set中存放a[i],因为这说明a[i]这个数不止一个,是一个潜在的多数,因此要把计数count加1。这里用Set是因为其不能存储重复元素,即使add()了重复元素对Set集合也不产生改变,所以Set的作用就是存储出现次数大于1的元素。

注意的是这个Set必须是LinkedHashSet,因为这种Set元素的排序是按照存入顺序排列的,我原来就是用HashSet,但我发现有时候输出结果不对,调试的时候就发现是因为set和list没对应上,就是因为set的顺序不对。

如果a[i] != a[i+1],就说明a[i]这个数以及计数完毕,下一个新的数来了,就需要先判断count是否大于1,如果大于1就说明上一个数出现多次,就要把出现次数count存储到集合list中,然后再把count复原,开始记录下一个数。

for (int i = 0; i < nums.length - 1; i++) {
     if(nums[i] == nums[i+1]){
         set.add(nums[i]);
         count++;
     }else {
         //先判断count是否等于1,如果不等于1,说明这个nums[i]出现了超过一次,就需要把出现次数
         //存储到list2中,然后复原count
         if (count != 1){
             list.add(count);
             count = 1;
         }
     }
}
list.add(count);

这么写最坑的就是我最后还要写一句list.add(count),因为不写的话,例如[1,1,1,2,2,2,2]这样的,最后这个2的count无法存入到list中,是因为遍历索引的问题,看看有没有大神能够帮我优化一下。然后执行下面代码,找到了题目要求的多数

Integer max = Collections.max(list);
int index = list.indexOf(max);
List<Integer> setlist = new ArrayList<>(set);
Integer result = setlist.get(index);

我排序代码这次用的是归并,上次用的是快速,把之前学的高级排序都复习复习。下面是我整体代码

class Solution {
    private static int[] assist;
    public int majorityElement(int[] nums) {
        sort(nums);
        //用来存储nums中出现的次数超过1次的元素
        Set<Integer> set = new LinkedHashSet<>();
        //List<Integer> list1 = new ArrayList<>();
        //用来存储nums中出现的次数超过1次的元素的个数,和arr1对应
        List<Integer> list = new ArrayList<>();
        //计数,用来计nums中不出现的次数超过1次的元素的个数,然后存在arr2中
        int count = 1;

        if (nums.length == 1){
            return nums[0];
        }
        //遍历nums数组
        for (int i = 0; i < nums.length - 1; i++) {
            if(nums[i] == nums[i+1]){
                set.add(nums[i]);
                count++;
            }else {
                //先判断count是否等于1,如果不等于1,说明这个nums[i]出现了超过一次,就需要把出现次数
                //存储到list2中,然后复原count
                if (count != 1){
                    list.add(count);
                    count = 1;
                }
            }
        }
        list.add(count);
        System.out.println(set);
        System.out.println(list);
        Integer max = Collections.max(list);
        int index = list.indexOf(max);
        List<Integer> setlist = new ArrayList<>(set);
        Integer result = setlist.get(index);
        System.out.println(result);
        return result;
    }
    //排序
    public static void sort(int[] nums){
        assist = new int[nums.length];
        int lo = 0;
        int hi = nums.length - 1;
        sort(nums,lo,hi);
    }
    //范围内排序
    public static void sort(int[] nums,int lo,int hi){
        if (lo >= hi){
            return;
        }

        int mid = lo + (hi - lo)/2;
        sort(nums,lo,mid);
        sort(nums,mid+1,hi);
        //归并
        merge(nums,lo,mid,hi);
    }
    /*
    归并,lo到mid一组,mid+1到hi一组,对这两组数据进行合并
     */
    public static void merge(int[] num,int lo,int mid,int hi){
        //lo到mid数组和mid+1hi数组归并到assist辅助数组中
        int i = lo;//assist的指针,从头开始
        int p1 = lo;//左数组指针第一个元素
        int p2 = mid + 1;//右数组指针第一个元素

        //比较左右两个数组元素大小,哪个小就把哪个数存入到assist中
        while (p1 <= mid && p2 <= hi){
            if(less(num[p1],num[p2])){
                assist[i++] = num[p1++];
            }else {
                assist[i++] = num[p2++];
            }
        }

        //在一边数组全部填充好了之后就可填充另一个
        while (p1 <= mid){
            assist[i++] = num[p1++];
        }
        while (p2 <= hi){
            assist[i++] = num[p2++];
        }

        //拷贝
        for (int j = lo;j <= hi;j++){
            num[j] = assist[j];
        }
    }
    //比较大小
    public static boolean less(Integer v,Integer w){
        return v.compareTo(w) < 0;
    }

    //交换
    public static void exch(int[] a,int i,int j){
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

根据此题题解,我知道可以用HashMap来做,键用来存数字,值用来存出现的次数。如果第一个元素是2,我们就可以去集合中看看这个2是否存在,如果不存在,是第一次出现,就往集合中添加2和1就行,表示2出现了1次了。如果第二元素也是2,还要去集合中判断一下,已经存在了,把值加1,以此类推。把所有数字以及出现次数都存入到HashMap中后,进行遍历,得到max,用打擂台的方式。最后再进行一次遍历,找到max对应的键。即为出现最多的数字。附上找最大值的代码,排序方法同上。

public int majorityElement(int[] nums) {
        sort(nums);
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if(hashMap.containsKey(nums[i])){
                //如果这个键已经存在,就把之前的值取出来然后加一
                int count = hashMap.get(nums[i]);
                count++;
                hashMap.put(nums[i],count);
            }else {
                //这个数不存在,添加进入作为键,值就是1
                hashMap.put(nums[i],1);
            }
        }

        //设最大值为0
        int max = 0;
        //遍历map,找出最大值
        Set<Map.Entry<Integer, Integer>> entries = hashMap.entrySet();
        for (Map.Entry<Integer, Integer> entry : entries) {
            int value = entry.getValue();
            if (value > max){
                max = value;
            }
        }
        System.out.println(hashMap);
        System.out.println(max);
        //找到最大值对应的键
        Integer key = 0;
        for (Map.Entry<Integer, Integer> entry : entries) {
            int value = entry.getValue();
            if(value == max){
                key = entry.getKey();
            }
        }
        return key;
    }

这题真是花费我好久时间,先把自己想的整出来了,再去学学Map,不过收获颇丰,不枉我花费时间。

#你们的毕业论文什么进度了##你觉得一个人能同时学好硬件和软件吗##你的秋招进展怎么样了##我的求职思考##你觉得今年秋招难吗#
全部评论
这题没这么复杂吧。摩尔投票了解一下?既然说最多的超过一半了,让每个元素为自己投票,为他人减票最后剩的就是最多的
点赞 回复
分享
发布于 2023-01-10 19:17 山东
而且map用的也很乱,前面的if语句完全可以换成map.getOrDefault(map.get(nums[i]),0)+1一行代码就行。题目说了超过一半直接遍历一遍查到有大于n/2的直接返回就行。而且循环时可以记录下来key没必要再遍历一次。
点赞 回复
分享
发布于 2023-01-10 19:32 山东
联易融
校招火热招聘中
官网直投
建议楼主去买一个acwing 的算法课 系统的学习下
点赞 回复
分享
发布于 2023-01-16 23:50 陕西

相关推荐

34 2 评论
分享
牛客网
牛客企业服务