LeetCode5539.按照频率将数组升序排序(Java+四种做法)

题目

给你一个整数数组 nums ,请你将数组按照每个值的频率 升序 排序。如果有多个值的频率相同,请你按照数值本身将它们 降序 排序。

示例 1:
输入:nums = [1,1,2,2,2,3]
输出:[3,1,1,2,2,2]
解释:‘3’ 频率为 1,‘1’ 频率为 2,‘2’ 频率为 3 。
示例 2:
输入:nums = [2,3,1,3,2]
输出:[1,3,3,2,2]
解释:‘2’ 和 ‘3’ 频率都为 2 ,所以它们之间按照数值本身降序排序。
示例 3:
输入:nums = [-1,1,-6,4,5,-6,1,4,1]
输出:[5,-1,4,4,-6,-6,1,1,1]

范围:1 <= nums.length <= 100
-100 <= nums[i] <= 100

题目分析

题目要求:求出数组内每个元素出现的频率,然后按照频率来升序排序数组,如果存在频率相同的数,进行降序排列。
确保读懂题。然后慢慢分析。
根据数据的范围,我可以新设一个count数组,用于统计每个整数出现的频率,但是这个会存在一个问题。我们发现数组元素的范围在-100~100之间,也就是说存在负整数,那么我新设的数组count,就要避免这个问题。
然后我们再读题,一想到排序,我们应该想到学过的排序算法:冒泡、快速、选择、归并等等,我们需要思考能不能用我们学过的、我们掌握的技巧去解题。

法一:新设数组+循环+交换

我们先来看看我第一次写的代码:

public int[] frequencySort(int[] nums) {
		//计算每个元素出现的频率
		int[] count = new int[400];
		for (int i : nums) {
			count[i + 200]++;
		}
		//进行排序
		for (int i = 0; i < nums.length; i++) {
			for (int j = i + 1; j < nums.length; j++) {
				if (count[nums[i] + 200] > count[nums[j] + 200]) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}
				if (count[nums[i] + 200] == count[nums[j] + 200] && nums[j] > nums[i]) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}
			}
		}
		return nums;
	}

设立了一个大小为400的数组,统计nums数组中元素频率的时候,我们让 i+200,相当于让该元素在count数组里的位置右移200位,那么我们在比较的时候,也要+200。
双重循环里面的第一个if,用于交换:将出现频率高的整数交换到后面。第二个if,用于比较相等频率的元素,谁更大,大的放前面,小的放后面。
最后返回nums即可。
这样做,是在原数组的基础上进行交换。重点要学会的是:count[nums[i]]。count统计的 是nums数组中每个元素出现的频率,比较频率的时候,就可以count[nums[i]],去看nums[i] 这个数的频率了。
<---------------------------------------------------------------------------------------------------------------------->
当然也可以设置新数组的大小比数据最大限度 大1。

public int[] frequencySort(int[] nums) {
		// 计算每个元素出现的频率
		int[] count = new int[201];
		for (int i : nums) {
			count[i + 100]++;
		}
		// 进行排序
		for (int i = 0; i < nums.length; i++) {
			for (int j = i + 1; j < nums.length; j++) {
				if (count[nums[i] + 100] > count[nums[j] + 100]) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}
				if (count[nums[i] + 100] == count[nums[j] + 100] && nums[j] > nums[i]) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}
			}
		}
		return nums;
	}

法二:HashMap+不用额外考虑负数的情况

与法一思想一致,就是使用的是HashMap,不用移动负数

 public int[] frequencySort2(int[] nums) {
		// 计算每个元素出现的频率
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int i : nums)
			map.put(i, map.getOrDefault(i, 0) + 1);
		// 进行排序
		for (int i = 0; i < nums.length; i++) {
			for (int j = i + 1; j < nums.length; j++) {
				if (map.get(nums[i]) > map.get(nums[j])) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}
				if (map.get(nums[i]) == map.get(nums[j]) && nums[j] > nums[i]) {
					int temp = nums[i];
					nums[i] = nums[j];
					nums[j] = temp;
				}

			}

		}
		return nums;
	}

法三:HashMap+Arrays.sort()自定义排序

sort(T[] a, Comparator<? super T> c) 根据指定的比较器所指定的顺序对指定的对象数组进行排序。

有个麻烦的地方在于:我们需要先将int型nums转为一个Integer型的数组,然后对Integer型数组进行排序之和,又要将其转为Int型。为什么呢???因为比较的是对象!!!对象!!!写了半天总是错的,原来要转型。

public int[] frequencySort3(int[] nums) {
		Integer[] array = new Integer[nums.length];
		for (int i = 0; i < array.length; i++) {
			array[i] = (Integer) nums[i];
		}
		System.out.println(Arrays.toString(array));
		// 计算每个元素出现的频率
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int i : nums)
			map.put(i, map.getOrDefault(i, 0) + 1);
		// 进行排序
		//如果频率相同,就按照数值降序;如果频率不同,就按照频率大小升序排列
		Arrays.sort(array, new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				if (map.get(o1).equals(map.get(o2))) {
					return o2 - o1;
				}
				return (int) map.get(o1) - map.get(o2);
			}
		});
		//最后还要转回Int型
		for (int i = 0; i < array.length; i++) {
			nums[i] = (int) array[i];
		}
		return nums;
	}

之前写的时候,没有进行转换,所以一直报错,一直用不起,后来知道要转型。
借鉴下面的讲解:
在这里插入图片描述
总之,虽然代码还是比较长,但是学到了Arrays.sort()自定义排序,还是可以了

法四:Lambda表达式

λ表达式由三部分组成:参数列表,箭头(->),以及一个表达式或语句块。

参考
Lambda表达式入门
打扰了,看不懂,第一次接触,以后来日方长呀Lambda!

// Lambda
public int[] frequencySort4(int[] nums) {
	HashMap<Integer, Integer> map = new HashMap<>();
	List<Integer> list = new ArrayList<Integer>();
	for (int i : nums) {
		list.add(i);
		map.put(i, map.getOrDefault(i, 0) + 1);
	}
	list.sort((a, b) -> {
		int temp1 = map.get(a);
		int temp2 = map.get(b);
		if (temp1 == temp2) {
			return b - a;
		}
		return temp1 - temp2;
	});
	return list.stream().mapToInt(Integer::intValue).toArray();
}

做题反思

个人觉得,法一最好!法一简单易懂,就是自己想的话,可能就想不出来,会绕半天。
我也是不太熟悉,但是经过这道题,看到很多知识点,见多识广了!
继续加油
end.

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值