//75
public void sortColors(int[] nums) {
//l是放2的地方,s是放0的地方
//我们要做的就是
//把后面的0放到前面(s<index)所以s++,index++
//把前面的2放在后面(l>index)所以后面放完了,循环结束
int l=nums.length-1;
int s=0;
int index=0;
while(index<=l){
if(nums[index]==0){
swap(nums,index,s);
s++;
index++;
}
else if(nums[index]==1){
index++;
}else if(nums[index]==2){
swap(nums,index,l);
l--;
}
}
}
public void swap(int[] nums,int i,int j){
int sw=nums[i];
nums[i]=nums[j];
nums[j]=sw;
}
//88 合并两个数组,顺序排放
/*输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]*/
//合并一个数组,nums1的后面是可以被覆盖的,也就是
//把nums2的元素按大小顺序放到nums1里
//结束条件就是nums2全部放进去了,nums1被放满了
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i=m-1;
int j=n-1;
int k=m+n-1;//从后面开始放
while(i>=0&&j>=0){
//两个数组里都有数的时候,选最大的放里面
nums1[k--]=(nums1[i]>nums2[j]?nums1[i--]:nums2[j--]);
}
while(j>=0) {
//nums2还有没放完的直接放,
//nums1不会有没放完的因为nums1的数已经在nums1里不可能没放完
nums1[k--]=nums2[j--];
}
}
//215
public int findKthLargest(int[] nums, int k){
Arrays.sort(nums);//sort是把数组从小到大排列
return nums[nums.length-K];//第一大的数下标就是nums的长度减去1
}
//347 非空数组返回其中频率前K高的元素
public List<Integer> toKFrequent(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个元素
PriorityQueue<Integer> pq=new PriorityQueue<>(new Comparator<Integer>() {
//PriorityQueue优先队列,每次取出的元素都是队列中权值最小的
//元素大小评判可以通过构造时传入的比较器
public int compare(Integer a, Integer b) {
return map.get(a)-map.get(b);//返回正数,系统会识别前者大于后者
}
});
for(Integer key:map.keySet()) {
//keySet() 方法可以与 for-each 循环一起使用,用来遍历迭代 HashMap 中的所有键。
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;
}
//451 输入:"tree"输出: "eert"
//用哈希表存储每个字符出现的次数,
//再通过一个大顶堆根据出现次数排序,
//不断取出堆顶元素,使用StringBuffer不断append即可。
public String frequencySort(String s) {
int[] letters =new int[128];
for(char c:s.toCharArray()) letters[c]++;
//把s.toCharArray()中的每个字符char c拿出来,强转为int[c]对应加一,就是统计了频率
PriorityQueue<Character> heap = new PriorityQueue<>(128, (a, b) -> Integer.compare(letters[b], letters[a]));
StringBuilder res = new StringBuilder();//大顶堆
for(int i=0;i<letters.length;++i) {
if(letters[i]!=0) {
heap.offer((char)i);
}
}
while(!heap.isEmpty()) {
char c=heap.poll();//取出栈顶元素
while (letters[c]-- >0) {//append多少个取决于频率
res.append(c);
}
}
return res.toString();
}
//692,给非空的单词列表,返回前k个出现次数最多的单词
/*
* 1,用map计算每个单词的频率
* 2,添加到大小为k的小根堆
* 3,弹出k次
* 4,反转结果*/
public List<String> topKFrequent(String[] words, int k){
Map<String, Integer> map=new HashMap();
for(String word:words) {
map.put(word, map.getOrDefault(word,0)+1);
//getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
}
//控制O(NlogK)的关键在于堆的大小只能限定到k这么大,要用最小堆实现。
PriorityQueue<String> queue=new PriorityQueue<>(k, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
if(map.get(s1).equals(map.get(s2))) {//这两个词的频率一样
return s2.compareTo(s1);//s2比s1长度长就返回正数,频率一样返回哪个都可
}
return map.get(s1).compareTo(map.get(s2));//频率不一样按频率大的大,小顶堆
//(a,b)->a.compareTo(b)小顶堆
//(a,b)->b.compareTo(a)大顶堆
}
});
for(String key:map.keySet()) {//获取map对象的所有key值
if(queue.size()<k) {
queue.add(key);
}else if(queue.comparator().compare(key, queue.peek())>0) {
//小根堆peek出的是堆内最小值,调用自定义comparator比较器比较,大于0说明map内的值更大
queue.poll();
queue.add(key);
}
}
String[] res=new String[k];
for(int i=k-1;i>=0;i--) {
res[i]=queue.poll();//小顶堆取出的都是堆内最小值
}
return Arrays.asList(res);//返回由指定数组支持的固定大小的列表
}
//373,查找最小的k对数字
//暴力法:大顶堆
public List<List<Integer>> kSmallestPairs(int[] nums1,int[] nums2,int k){
List<List<Integer>> res=new ArrayList<>();
k=Math.min(k, nums1.length*nums2.length);
if(k==0) return res;
Queue<int[]> Q=new PriorityQueue<>(k,(o1,o2)->o2[0]+o2[1]-o1[0]-o1[1]);
//返回正数比较器会返回前者大于后者,大顶堆
for(int e1:nums1)
for(int e2:nums2) {
if(Q.size()<k) {
Q.offer(new int[] {e1,e2});
}else if(e1+e2<=Q.peek()[0]+Q.peek()[1]) {//大顶堆取出的是都是堆内最大值
Q.poll();
Q.offer(new int[] {e1,e2});
}
}
while(k-->0) {//当Q内还有值时
int[] e=Q.poll();
res.add(0,Arrays.asList(e[0],e[1]));
}
return res;
}
//方法2:记录nums1[i]在nums2中当前的候选元素
public List<List<Integer>> kSmallestPairs2(int[] nums1,int[] nums2,int k){
List<List<Integer>> res=new ArrayList<>();
k=Math.min(k, nums1.length*nums2.length);
int[] ptrs=new int[nums1.length];
//prts[i]=j表示nums1[i]此时的候选元素时nums2[j]
while(k-->0) {
int minIndex=-1,min=0x7fffffff;//integer的最大值
for(int i=0;i<nums1.length;i++) {
//在nums[i]的每个候选中挑选出最小的,此处可以用小顶堆快速找到,从而实现优化
if(ptrs[i]<nums2.length&&nums1[i]+nums2[ptrs[i]]<min) {
minIndex=i;
min=nums1[i]+nums2[ptrs[i]];
}
}
res.add(Arrays.asList(nums1[minIndex],nums2[ptrs[minIndex]]));
ptrs[minIndex]++;
}
return res;
}
//373
public List<List<Integer>> kSmallestPairs3(int[] nums1,int[] nums2,int k){
List<List<Integer>> res=new ArrayList<>();
k=Math.min(k, nums1.length*nums2.length);
if(k==0) return res;
Queue<Node> Q=new PriorityQueue<>(nums1.length,
(o1,o2)->o1.v+nums2[o1.idx]-o2.v-nums2[o2.idx]);
for(int i=0;i<nums1.length;i++) {
Q.offer(new Node(nums1[i],0));
}
while(k-->0) {
res.add(Arrays.asList(Q.peek().v,nums2[Q.peek().idx]));
Q.peek().idx++;
if(Q.peek().idx==nums2.length)
Q.poll();
else
Q.offer(Q.poll());//因为Q.peek().idx更新了,需要把堆顶Node取出后再重新
for(int i=0;i<nums1.length;i++) {
Q.offer(new Node(nums1[i],0));
}
}
return null;
}
//378
//有序矩阵中第k小的元素
//给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
//请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
//由题目给出的性质可知,这个矩阵的每一行均为一个有序数组。问题即转化为从这n个有序数组中找到第k大的数,可以想到利用归并排序的做法,归并到第k个数即可停止。n个数组归并需要用小根堆维护,以优化时间复杂度。
public static int kthSmallest(int[][] matrix, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
return a[0] - b[0];
}
});
int n = matrix.length;//矩阵有几行
for (int i = 0; i < n; i++) {
pq.offer(new int[]{matrix[i][0], i, 0});//先把左端最小的值加入最小堆,一共三个
//后面的i和0用于记录加入数组中的矩阵值的位置
}
for (int i = 0; i < k - 1; i++) {//一共弹出k次最小值
int[] now = pq.poll();//弹出最小堆的最小值,now[0]是值,now[1],now[2]是数在矩阵中的位置
System.out.println(now[1]);
if (now[2] != n - 1) {//如果这一行没有被弹完,把这一行的下一位加入最小堆,now[2]是弹出来的数的纵坐标
pq.offer(new int[]{matrix[now[1]][now[2] + 1], now[1], now[2] + 1});
}
}
return pq.poll()[0];
}