一、Arrays.sort(nums)的一般用法
- 整个数组按照升序排序
若需要降序排序,将数组转置即可
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]
- 对指定范围内的数组元素进行排序
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,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表达式的写法!