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
出现两次,r
和t
都只出现一次。
因此e
必须出现在r
和t
之前。此外,eetr
也是一个有效的答案。
- 思路:
- 创建map,以字符为key,出现次数为value;Java中可使用
map.getOrDefault(c,0)
方法,为key对应value为空时设置默认值 - 创建桶,每个桶中存放出现次数相同的元素,其中出现次数即为桶的下标
- 最后从后向前对桶进行遍历即可
- 创建map,以字符为key,出现次数为value;Java中可使用
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)