Java-排序-leetcode刷题

  最近在刷LeetCode的算法题,今天学习了排序的高效方法:最小堆和桶排序法。

  题目描述:给定一个非空的整数数组,返回其中出现频率前 高的元素。 

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
1.最小堆法
思路:①借助哈希表来建立数字及其出现频次的映射
②维护一个元素数目为k的最小堆
③每次都将新元素与堆顶元素(堆中频率最小的元素)比较
④若新的元素比堆顶端的元素大,则弹出堆顶元素,将新元素添加进去
⑤最终,堆中k个元素即为前k个高频元素
class Solution{
	public List<Integer> topKFrequent(int[] nums,int k){
		//使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
		HashMap<Integer,Integer> map=new HashMap();
		for(int num:nums){
			if(map.containsKey(num)){
				//若已存在,值加一
				map.put(num,map.get(num)+1);
			}else{
				//若不存在,创建新的键值对
				map.put(num,1);
			}
		}
	}
	//遍历map,用优先队列最小堆保存频率最大的k个元素
	//建立小顶堆,若想建立大顶堆,则return map.get(b)-map.get(a)
	/*继承Comparator接口,必须重写compare 方法*/
	PriorityQueue<Integer> pq=new PriorityQueue<>(new Comparator<Integer>(){
		@Override
		public int compare(Integer a,Integer b){
			return map.get(a)-map.get(b);
		}
	)};
	//保存频率最大的k个元素,peek()方法:查看堆顶元素值
	for(Integer key:map.keySet()){
		if(pq.size()<k){
			pq.add(key);
		}else if(map.get(key)>map.get(pq.peek())){
			pq.remove();
			pq.add(key);
		}
	}
	//取出最小堆的元素
	List<Integer> res=new ArrayList<>();
	while(!pq.isEmpty()){
		res.add(pq.remove);
	}
	return res;
}

  tips:

PriorityQueue(优先级队列):按关键词有序排列,插入新数据会自动插入合适位置。默认小顶堆。重写可以改变其排列方式。
方法1:
	PriorityQueue<Integer> pq=new PriorityQueue<>(new Comparator<Integer>(){
		@Override
		public int compare(Integer a,Integer b){
			return map.get(b)-map.get(a);
		}
	)};

  方法2:调用Comparator,reverseOrder()方法

PriorityQueue<Integer> pq=new PriorityQueue<>(Comparator.reverseOrder());

  方法3:Lambda表达式:允许把函数作为一个方法的参数传递进方法。

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

  时间复杂度:O(nlogk),n表示数组的长度,遍历一遍复杂度为o(n);接着,遍历用于存储元素频率的map,若元素频率大于最小堆中顶部的元素,则将顶部的元素删除并将该元素 加入堆中,这里维护堆的数目为k,因此时间复杂度为O(nlogk)。

2.桶排序法

//基于桶排序求解「前 K 个高频元素」
class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res = new ArrayList();
        // 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
        HashMap<Integer,Integer> map = new HashMap();
        for(int num : nums){
            if (map.containsKey(num)) {
               map.put(num, map.get(num) + 1);
             } else {
                map.put(num, 1);
             }
        }
        
        //桶排序
        //将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
        List<Integer>[] list = new List[nums.length+1];
        for(int key : map.keySet()){
            // 获取出现的次数作为下标
            int i = map.get(key);
            if(list[i] == null){
               list[i] = new ArrayList();
            } 
            list[i].add(key);
        }
        
        // 倒序遍历数组获取出现顺序从大到小的排列
        for(int i = list.length - 1;i >= 0 && res.size() < k;i--){
            if(list[i] == null) continue;
            res.addAll(list[i]);
        }
        return res;
    }
}

  

 LeetCode-75按颜色排序

题目:

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

学习来的思路:1.设置两个指针r1,r2,分别代表当前r1记录左边小于1的当前位置,r2记录左边小于2 的当前位置。

2.如果左边比2小,那么就r2++,且交换数组的顺序(r2和i),若仍然小于1,r1++,继续交换(r2,r1)

(这个思路太大神了orz)

class Solution {
    public void sortColors(int[] nums) {
        int r1=-1,r2=-1;
        for(int i=0;i<nums.length;i++){
            if(nums[i]<2){
                r2++;
                swap(nums,i,r2);
                if(nums[r2]<1){
                    r1++;
                    swap(nums,r1,r2);
                }
            }
        }
    }
    void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

  

原文地址:https://www.cnblogs.com/zyycumt/p/13557951.html