力扣算法题总结-数组部分(一)

//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];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值