比较器的初次尝试(二维数组比较器)+(TreeMap比较器:根据KEY的大小排列)+(优先队列)+(Map根据VALUE的大小进行排列)+(重写比较器比较)

1.二维数组排序 

  public static void main(String[] args) {
     int arr[][]=new int[][]{{5,8,1},{3,9,4},{9,10,1}};
     int sum[][]=new int[][]{{5,8,1},{3,9,4},{9,10,1}};
     Arrays.sort(arr,(a,b)->b[1]-a[1]);
//通过对数组每一行的第二列元素大小进行降序排列,从而对二维数组进行重新排列(对比较器的重写)

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

            for (int j = 0; j <arr[0].length ; j++) {

                System.out.println(arr[i][j]);

            }

        }

    }
}

二维数组有大用处,可以同时存放数值,和数值映射的值,类似与哈希表,但搜索蛮方便(treemap)也能做到,它可以通过键值进行排序。建立一个n列2行的二维数组,第一行存放key值,第二行存放value,可以用归并排序(sort)进行排序,其中归并排序属于稳定排序,即值相同的元素的相对位置不发生变动。TreeMap也可以对键和值进行排序,查找更加方便,但缺点就是key不能冲突

如下题

 public static int[] sortJumbled(int[] mapping, int[] nums) {
        int arr[][]=new int[nums.length][2];//2行nums.length列
        for (int i = 0; i <nums.length ; i++) {
            String temp="";
            String word=String.valueOf(nums[i]);
            for (int j = 0; j <word.length() ; j++) {
                //这里用的笨方法,用字符串拼接来做映射
                String temp_1=String.valueOf(word.charAt(j));
                int count=Integer.parseInt(temp_1);
                temp=temp+String.valueOf(mapping[count]);
            }
            arr[i][0]=Integer.parseInt(temp);//第一行保存映射数值key
            arr[i][1]=nums[i];//第二行保存value
        }
        Arrays.sort(arr,(a,b)->a[0]-b[0]);//排序,根据key来进行升序排序(sort默认的)
        int arr_1[]=new int[nums.length];
        for (int i = 0; i <arr_1.length ; i++) {
            arr_1[i]=arr[i][1];
        }
        return arr_1;
    }

比较器可以应用在二维数组排序上,同时也可以应用在优先队列上

   PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->b-a);

这里是将优先队列里面的元素进行降序排列,即往里面放值会进行自动的排列

比较器

重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;
如果返回0,表示相等;
返回负整数,表示o1小于o2。

2.TreeMap

2.1TreeMap根据键排序

TreeMap相比普通Map,可以起到一个排序的作用,无论是对键或者值。相比用二维数组模拟,TreeMap的查找速度更快,下面是对TreeMap的应用。

比较器覆写,对KEY的绝对值进行升序排序

  TreeMap<Integer, Integer> counter = new TreeMap<>((o1, o2) -> {
            if (Math.abs(o1) == Math.abs(o2)) {
                return o1 - o2;
            }
            return Math.abs(o1) - Math.abs(o2);
        });

 一下是对上例的测试

public class Solution {


    public static void main(String[] args) {
        // key-距离 0 的距离,value - 当前数字的出现次数,升序排列
        TreeMap<Integer, Integer> counter = new TreeMap<>((o1, o2) -> {
            if (Math.abs(o1) == Math.abs(o2)) {
                return o1 - o2;
            }

            return Math.abs(o1) - Math.abs(o2);
        });
        counter.put(-1, 0);
        counter.put(-2, 0);
        counter.put(1, 0);
        counter.put(2, 0);
        counter.put(3, 0);

        for (Map.Entry<Integer, Integer> entry : counter.entrySet()) {
            System.out.println(entry.getKey());
        }


    }
}

控制台的输出结果

需要排序键的题目,TREEMAP当仁不让!排序速度快,查找速度远超模拟的二维数组。

  因为负数和正数需要分类讨论,负数得按降序排列,正数得按升序排列,这里treemap就巧妙的利用比较器实现离0的距离实现升序排列,避免了分类讨论的繁杂情况

class Solution {
    public boolean canReorderDoubled(int[] arr) {
        // key-距离 0 的距离,value - 当前数字的出现次数,升序排列
        TreeMap<Integer, Integer> counter = new TreeMap<>((o1, o2) -> {
          //这里的if判断不能省,否则会缺失相反数中的一部分
            if (Math.abs(o1) == Math.abs(o2)) {
                return o1 - o2;
            }

            return Math.abs(o1) - Math.abs(o2);
        });
        // 统计 arr 数组中的每个数字的出现次数,若之前不在counter中置1,已有则置oldCnt+ newCnt,速度要比counter.put(num,map.getOrDefault(num,0)+1)要快一些
        for (int num : arr) {
            counter.merge(num, 1, (oldCnt, newCnt) -> (oldCnt + newCnt));
        }

        // 如果 0 的次数不为偶数,则直接返回 false

        final int ZERO = 0;
        if ((counter.getOrDefault(ZERO, 0) & 1) == 1) return false;
       
       //遍历counter的键值        
        for (Map.Entry<Integer, Integer> enrty : counter.entrySet()) {
            // 当前数字及其出现次数
            int num = enrty.getKey(), cnt = enrty.getValue();
            // 当前数字已经消耗完了,就不再匹配 2*num
            if (cnt == 0) continue; 
            // 如果 2*num 的次数小于 num 的次数,则无法构成题目要求的数对
            int numDouble = 2 * num;
            int cntDouble = counter.getOrDefault(numDouble, 0);
            if (cntDouble < cnt) return false;
            // 将 2*num 的次数抵消掉 num 的次数
            counter.put(numDouble, cntDouble - cnt);
        }

        return true;
    }
}

根据键排序,TreeMap可以直接实现,但根据值排序,并未找到TreeMap自带的功能

2.2根据值排序

可以将map放入List中,利用Collections.sort,覆写内置的比较器,实现对值的一个排序,下面是对值排序的一个测试

    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("say",9);
        map.put("hash",10);
        map.put("you",3);        System.out.println("排序前");
        for (String s : map.keySet()) {
            System.out.println(s+":"+map.get(s));
        }
        //通过ArrayList构造函数将map.entrySet()转换成list,即将map放到List中进行排序,这样就可对value值进行排序
        List<Map.Entry<String,Integer>> list= new ArrayList<>(map.entrySet());
        //通过比较器进行比较排序
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> entry1, Map.Entry<String, Integer> entry2) {
                //返回值为1,代表前面>后面,-1相反,0表示相等
                return entry2.getValue().compareTo(entry1.getValue());
            }
        });
        //将排序后的结果打印出来
        System.out.println("排序后");
        for (Map.Entry<String, Integer> entry : list) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
    }
}

控制台输出如下图所示,对值进行了一个降序排列 

 练习如下,见力扣的题目

这里便是对值进行一个降序排序,再将其遍历输出K个即可

代码如下所示

class Solution {
      public int[] topKFrequent(int[] nums, int k) {
           Map<Integer,Integer>map=new HashMap<>();
           int res[]=new int[k];
       for (int i = 0; i <nums.length ; i++) {
            map.put(nums[i],map.getOrDefault(nums[i],1)+1);
        }
     //利用List对map的值进行排序
            List<Map.Entry<Integer,Integer>>list=new ArrayList<>(map.entrySet());
           Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
               @Override
               public int compare(Map.Entry<Integer, Integer> integerIntegerEntry, Map.Entry<Integer, Integer> t1) {
                   return t1.getValue()-integerIntegerEntry.getValue();
               }
           });

           for (int i=0;i<k;i++) {

              res[i]=list.get(i).getKey();
           }
           return  res;


}
}

3.自定义数组比较器

重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;
如果返回0,表示相等;
返回负整数,表示o1小于o2。

如题,需要自己重写比较器进行排序

Arrays.sort默认对数组元素进行升序排序

 代码如下,有注释

 public static String[] reorderLogFiles(String[] logs) {
        Arrays.sort(logs, new Comparator<String>() {
            @Override
            public int compare(String log1, String log2) {
                String id1, id2, c1, c2;
                boolean isNum1 = false, isNum2 = false;
                int n1 = log1.length(), n2 = log2.length(), t = 0;
                while(t < n1 && log1.charAt(t) != ' ') {
                    t ++;
                }
                id1 = log1.substring(0, t);
                c1 = log1.substring(t, n1);
                //isNum1 表示它是数字型还是字母型,false是字母型,true为数字型
                isNum1 = log1.charAt(t + 1) >= '0' && log1.charAt(t + 1) <= '9';
                t = 0;
                while(t < n2 && log2.charAt(t) != ' ') {
                    t ++;
                }
                id2 = log2.substring(0, t);
                c2 = log2.substring(t, n2);
                //isNum2 表示它是数字型还是字母型,false是字母型,true为数字型
                isNum2 = log2.charAt(t + 1) >= '0' && log2.charAt(t + 1) <= '9';
                if(isNum1 != isNum2) {
                    //数字型,排后面
                    if(isNum1) {
                        return 1;
                    }
                    //字母型,排前面
                    else {
                        return -1;
                    }
                }
                //如果都是数字型,保留原来的顺序
                else if(isNum1) {
                    return 0;
                }
                //如果是字母型
                else {
                    //内容相同时,比较标识符
                    if(c1.equals(c2)) {
                        return id1.compareTo(id2);
                    }
                    //内容不同时,比较内容
                    else {
                        return c1.compareTo(c2);
                    }
                }
            }
        });
        return logs;
    }

4、字符串形式数字比较大小(重写比较器)

        有的时候,比如说像“13231315464654”如此大的字符串,想转换成数字来比较大小,非常容易溢出,而逐个去比较字符大小呢,复杂度非常的高,很痛苦,可见力扣2343题。

 这里我转换成数字进行比较器重写,不行,字符串长度太长,直接溢出,不能单纯的进行转换。

暴力解法(只是适用于字符串长度一致,不用考虑其他问题)

重写比较器,采用compareto这个API,二维数组,首位记录下标位置,下一位记录截取后的字符串,进行排序。

 public static int[] smallestTrimmedNumbers(String[] nums, int[][] queries) {
        int res[]=new int[queries.length];
        for (int i = 0; i <queries.length ; i++) {
           String arr[][]=new String[nums.length][2];
             int cut=queries[i][1];
            for (int j = 0; j <nums.length ; j++) {
                String a=nums[j].substring(nums[j].length()-cut,nums[j].length());
                String temp=a;
                arr[j][0]=String.valueOf(j);
                arr[j][1]=temp;
            }
            Arrays.sort(arr,(a,b)->(a[1].compareTo(b[1]));
            int count=queries[i][0];
            for (int j = 0; j <arr.length ; j++) {
                count--;
                //达到指定位置
                if(count==0){
                    res[i]=Integer.valueOf(arr[j][0]);
                    break;
                }
            }

        }
        return res;

    }

基数排序(待更新)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值