一、Arrays.sort(nums)的一般用法

  1. 整个数组按照升序排序
    若需要降序排序,将数组转置即可
int[] testNums = {1,3,6,5,4,1,2,8};
Arrays.sort(testNums);
System.out.println(Arrays.toString(testNums));

//输出:[1, 1, 2, 3, 4, 5, 6, 8]
  1. 对指定范围内的数组元素进行排序
int[] testNums2 = {1,3,6,5,4,1,2,8};
Arrays.sort(testNums2,1,6);
System.out.println(Arrays.toString(testNums2));

//输出:[1, 1, 3, 4, 5, 6, 2, 8]
  1. 自定义排序
    二维数组排序为例,比如,将:[[1,2],[3,4],[1,3],[2,4]] 按照每个一维数组的和的升序进行排序
int[][] testNums3 = {{1,2},{3,4},{1,3},{2,4}};
Arrays.sort(testNums3, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return (o1[0]+o1[1])-(o2[0]+o2[1]);
    }
});
for (int[] nums:testNums3){
    System.out.println(Arrays.toString(nums));
}

/*
    输出:
        [1, 2]
        [1, 3]
        [2, 4]
        [3, 4]
 */
  • 若要实现自定义排序,要给sort()函数传入一个继承Comparator接口的对象,在compare方法中定义自己的排序规则。
  • compare函数返回一个int类型:
    • o1,o2可以看成原数组中相邻的前后两个元素。返回值可以看成o1-o2的值。
    • 若返回负数,则说明o1-o2<0,sort方法将数组按升序(o1,o2)排列。
    • 反之若返回正数,说明o1-o2>0,按降序(o2,o1)排列。
    • 注意这里o1和o2并不一定能直接相加减,以上只是提供初学者一种记忆的方法,还是需要在实战中理解,接下来以两道算法题具体说明sort函数的一些应用。

4.使用lambda表达式自定义排序规则(重要!)

在3中,对应的接口函数可以用lambda表达式简写如下:

Arrays.sort(testNums3,(o1, o2) -> {
        return (o1[0]+o1[1])-(o2[0]+o2[1]);
    }
});

注意,要想改变默认的排列顺序,不能使用基本类型(int,double, char) ,而要使用它们对应的包装类。

二、最大数(力扣179)

原题连接
在这里插入图片描述

分析:先考虑两个数的情况,假设有两个数num1,num2,则答案要么是num1+num2,要么是num2+num1(注意这里的+表示拼接操作:1+2 = 12
定义num1>num2:num1+num2>num2+num1,举例说明:因为"3"+“31”=“331”>“31”+“3”=“313”,所以"3">“31”。
不难看出,当整个数组都按照我们定义的大小关系降序排序,最后依次拼接即为结果。比如:“31”>“30”>“2”,"31302"为所求最大数。代码如下:

public class Solution179 {
    /*
        给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
        注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

        输入:nums = [3,30,34,5,9]
        输出:"9534330"
        链接:https://leetcode-cn.com/problems/largest-number/
     */
    public static void main(String[] args) {
        int[] nums = {0,20,2190,5,38,21,1};
        System.out.println(Solution.largestNumber(nums));
    }
    static class Solution {
	    public static String largestNumber(int[] nums) {
	        String ans = "";
	        String[] temp = new String[nums.length];
	        for (int i = 0; i < nums.length; i++) {
	            temp[i] = Integer.toString(nums[i]);
	        }
	
	        Arrays.sort(temp, new Comparator<String>() {
	            @Override
	            public int compare(String o1, String o2) {
	                String o12 = o1+o2,o21 = o2+o1;
	                for (int i = 0; i < o12.length(); i++) {//逐个比较对应字符的大小
	                    //返回负数,顺序为(o1,o2)
	                    if(o12.charAt(i)>o21.charAt(i)) return -1;
	                    //返回正数,顺序为(o2,o1)
	                    else if(o12.charAt(i)<o21.charAt(i)) return 1;
	                    //无论是那种顺序,字符大的都在前面,因此是按降序排列
	                }
	                //若直到最后一个字符都相等,按照最后一个字符的大小来决定
	                return o12.charAt(o12.length()-1)<o21.charAt(o21.length()-1)?1:-1;
	            }
	        });
	        for (String s :
	                temp) {
	            ans += s;
	        }
	        return ans;
	    }
	}
}

三、合并区间(力扣59)

原题连接
在这里插入图片描述

分析:首先对intervals进行排序,排序规则为第一列按升序,第一列相等时第二列按降序,例如:[1,2]>[0,3],[2,2]>[2,3](思考为什么要这样排序)。
然后再遍历intervals进行合并。

  • 合并的过程中维护两个数值,左端点L,右端点R。
  • 一开始先给L和R赋初值为第一个区间的端点值,遍历intervals。
  • 若左端点和L相同,直接跳过(和一开始的排序有关)。
  • 若左端点大于L且大于R,说明L,R之间没有重叠区域了,记录L,R,并更新为当前区间的左右端点。
  • 若左端点大于L但是小于等于R,可能有重叠区域,将R更新为R与右端点之间的最大值。
  • 遍历结束后判断L,R是否记录。代码如下:
/*
    以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。
    请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

    [[1,3],[1,2],[2,6],[8,10],[15,18]]

    输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
    输出:[[1,6],[8,10],[15,18]]
    解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

    链接:https://leetcode-cn.com/problems/merge-intervals
 */
public class Solution56 {
    public static void main(String[] args) {
        int[][] intervals =  {{1,3},{1,2},{2,6},{8,10},{15,18},{19,20}};
//        int[][] intervals =  {{1,4},{0,4}};
        System.out.println(Arrays.deepToString(Solution.merge(intervals)));

    }

    private static class Solution {
        public static int[][] merge(int[][] intervals) {
            //1.第一维升序,第二维降序进行排序
            //2.遍历数组,记录当前区间的端点;
            // 若下一个区间的左端点相同,直接跳过;若大于前一个的右端点,记录前一个区间,更新区间的左右端点;若小于前一个的右端点,则存在重合区域,更新区间端点
            int[][] ans = new int[10005][2];
            Arrays.sort(intervals, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    if(o1[0]!=o2[0]) return o1[0]-o2[0];
                    else return o2[1]-o1[1];
                }
            });

            int L = 0,R = 0;//左右端点
            int nums = 0;//合并后的区间个数
            for (int i = 0; i < intervals.length; i++) {
                if(i==0){
                    L = intervals[0][0];R = intervals[0][1];continue;
                }
                if(intervals[i][0]==L) continue;//左区间端点相等直接跳过
                else if (intervals[i][0]>L){ //左区间端点大于前一个的左区间端点
                    if(intervals[i][0]>R){  //仍然大于右区间端点,记录
                        ans[nums][0] = L;ans[nums][1] = R;L = intervals[i][0];R = intervals[i][1];nums++;
                    }
                    else {//若小于等于右区间端点,比较它的右端点和原右端点的值,更新R
                        R = Math.max(intervals[i][1],R);
                    }
                }


            }

            //存在结束循环但是最后一个区间还没有加入ans的情况
            //最后一个区间也是首个区间
            if(nums==0) {ans[nums][0]=L;ans[nums][1]=R;}
            //最后一个区间不是首个区间的话只需要判断左端点是否相等,不相等说明还没有记录
            if(nums!=0 && ans[nums][0]!=L) {ans[nums][0]=L;ans[nums][1]=R;}

            return Arrays.copyOfRange(ans,0,nums+1);
        }
    }
}

四、总结

在理解各类排序算法的情况下,熟练使用Arrays.sort()方法解决问题,尤其掌握Comparator接口或lambda表达式的写法!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐