排序类型题目

1. 215.数组中第K个最大元素(medium)

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例:
 输入: [3,2,1,5,6,4] 和 k = 2
 输出: 5

本题有三种方法:

  • 使用Java自带的api对数组进行排序
    public int findKthLargest(int[] nums, int k) {
    		Arrays.sort(nums);
    		return nums[nums.length - k];
    }
    
  • 通过构建小顶堆的方式, 维持堆的元素个数为k个, 则最后一个元素记为第k大元素
    关于PriorityQueue的说明,请看
    public int findKthLargest1(int[] nums, int k) {
    	PriorityQueue<Integer> queue = new PriorityQueue<Integer>();// 小顶堆
    	for (int num : nums) {
    		queue.add(num);
    		if (queue.size() > k)//维护小顶堆,使其元素个数为k个
    			queue.poll();//将小于第k大元素之前的元素都弹出队列
    	}
    	return queue.peek();//堆顶即为所求
    }
    
  • 使用快速排序对数组进行排序
    public int findKthLargest2(int[] nums, int k) {
    	k = nums.length - k;
    	int low = 0, high = nums.length - 1;
    	quickSort(nums, low, high);
    	return nums[k];
    }
    
    public void quickSort(int[] nums, int low, int high) {
    	if (low < high) {
    		int pivotpos = partition(nums, low, high);
    		quickSort(nums, low, pivotpos - 1);
    		quickSort(nums, pivotpos + 1, high);
    	}
    }
    
    private int partition(int[] nums, int low, int high) {
    	int pivot = nums[low];
    	while (low < high) {
    		while (low < high && nums[high] > pivot)
    			high -= 1;
    		nums[low] = nums[high];
    		while (low < high && nums[low] < pivot)
    			low += 1;
    		nums[high] = nums[low];
    	}
    	nums[low] = pivot;
    	return low;
    }
    

2. 347 前k个高频元素(medium)

给定一个非空的整数数组, 放回其中出现频率前k高的元素
示例:
 输入: nums = [1,1,1,2,2,3], k = 2
 输出: [1,2]

  • 思路:
    • 首先使用map将数组元素进行处理, key为元素, value为出现次数
    • 创建一个数组(每个位置视为一个桶, 用于存储出现频率相同的元素),
      数组(桶)下标表示出现次数, 把不同元素都放入数组(桶)中
    • 从后向前遍历桶, 最先得到的k个元素即为所求
	public static int[] topKFrequent(int[] nums, int k) {
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int num : nums) {
			map.put(num, map.getOrDefault(num, 0) + 1);
		}

		List[] bucket = new ArrayList[nums.length + 1];// 设置桶, 下标为出现次数, 存储的是出现频率相同的元素
		for (int key : map.keySet()) {
			Integer times = map.get(key);
			if (bucket[times] == null) {
				bucket[times] = new ArrayList();
			}
			bucket[times].add(key);
		}

		ArrayList<Integer> topK = new ArrayList<Integer>();
		for (int i = bucket.length - 1; i >= 0 && topK.size() < k; i--) {
			List tmpList = bucket[i];
			if (tmpList == null)
				continue;
			if (tmpList.size() < k - topK.size())
				topK.addAll(tmpList);
			else
				topK.addAll(tmpList.subList(0, k - topK.size()));// 求list的子list, 包含startIndex,不包含toIndex
		}

		int[] result = new int[topK.size()];
		for (int i = 0; i < topK.size(); i++) {
			result[i] = topK.get(i);
		}
		return result;
	}

3. 451 根据字符出现频率排序(medium)

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。
示例:
 输入:tree
 输出:eert
 解释:
  e出现两次,rt都只出现一次。
  因此e必须出现在rt之前。此外,eetr也是一个有效的答案。

  • 思路:
    • 创建map,以字符为key,出现次数为value;Java中可使用map.getOrDefault(c,0)方法,为key对应value为空时设置默认值
    • 创建桶,每个桶中存放出现次数相同的元素,其中出现次数即为桶的下标
    • 最后从后向前对桶进行遍历即可
	public static String frequencySort(String s) {
		Map<Character, Integer> map = new HashMap<>();
		for (char c : s.toCharArray())
			map.put(c, map.getOrDefault(c, 0) + 1);

		List<Character>[] lists = new ArrayList[s.length() + 1];
		for (Character c : map.keySet()) {
			int index = map.get(c);
			lists[index] = lists[index] == null ? new ArrayList<>() : lists[index];
			lists[index].add(c);
		}
		StringBuffer str = new StringBuffer();
		for (int i = lists.length - 1; i >= 0; i--) {
			List<Character> list = lists[i];
			if (list == null)
				continue;
			for (Character c : list)
				for (int j = 0; j < i; j++)
					str.append(c);
		}

		return str.toString();
	}

4. 颜色分类(medium)

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
 示例:
  输入: [2,0,2,1,1,0]
  输出: [0,0,1,1,2,2]

  • 思路:
    • 使用三个指针,p0初始化为0,p1初始化为nums.length-1,curr初始化为0
    • while curr<=p2
      • 若 nums[curr] = 0 :交换第 curr个 和 第p0个 元素,并将指针都向右移。
      • 若 nums[curr] = 2 :交换第 curr个和第 p2个元素,并将 p2指针左移 。
      • 若 nums[curr] = 1 :将指针curr右移。
class Solution {
    public void sortColors(int[] nums) {
        int p1=0,curr=0,p2=nums.length-1;
        while(curr<=p2){
            if(nums[curr]==0){
                swap(nums,p1++,curr++);
            }else if(nums[curr]==2){
                swap(nums,p2--,curr);
            }else{
                curr++;
            }
        }
    }

    public void swap(int[] nums,int index1,int index2){
        int tmp=nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=tmp;
    }
}
  • 复杂度分析:
    • 时间复杂度:由于对整个数组进行了遍历,时间复杂度为O(N)
    • 空间复杂度:由于只使用了常数空间,空间复杂度为O(1)

参考:https://github.com/CyC2018/CS-Notes

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值