和排序相关的问题
1.回顾常见排序算法
直接插入排序
代码
public void insertSort(int[] array){
for(int i=0;i<array.length;i++){ //i从第二个元素开始排
int tem = array[i];
int j=i-1;
while (j>=0 && tem<array[j]){
array[j+1]=array[j];
j--;
}
array[++j]=tem;
}
}
希尔排序
代码
public void shellSort(int[] array){
for(int gas=array.length/2;gas>0;gas=gas/2){
for(int k=0;k<gas;k++){
for(int i=k;i<array.length;i+=gas){ //对每组进行直接插入排序
int tem = array[i];
int j = i - gas;
while (j>=0 && tem < array[j]){
array[j+gas] = array[j];
j -= gas;
}
array[j+gas] = tem;
}
}
}
}
冒泡排序
代码
public void bubbleSort(int[] array){
for(int i=0;i<array.length;i++){
boolean flag = true;
for(int j=0;j<array.length-1-i;j++){
if(array[j+1]<array[j]){
int tem = array[j+1];
array[j+1] = array[j];
array[j] = tem;
flag = false;
}
}
}
}
选择排序
代码
public void selectSort(int[] array){
for(int i=0;i<array.length;i++){
for(int j=i+1;j<array.length;j++){
if(array[j]<array[i]){
int tem = array[i];
array[i] = array[j];
array[j] = tem;
}
}
}
}
快速排序
代码
public void quickSort(int[]array,int left,int right){
if(right<=left)return;
int low = left,high = right;
int pivot = array[low];
while (low<high){
while (low<high && array[high]>=pivot)high--;
array[low]=array[high];
while (low<high && array[low]<=pivot) low++;
array[high]=array[low];
}
array[low]=pivot;
quickSort(array,left,low-1);
quickSort(array,low+1,right);
}
归并排序
代码
public void merge(int[] array,int left,int mid,int right){
int[] tem = new int[right-left+1];
int k = 0;
int i=left,j=mid+1;
while (k<tem.length && i<=mid && j<=right){
if(array[i]<array[j]){
tem[k++]=array[i++];
}else tem[k++]=array[j++];
}
while (i<=mid)tem[k++]=array[i++];
while (j<=right)tem[k++]=array[j++];
k = 0;
while (k<tem.length){
array[left++]=tem[k++];
}
}
public void mergeSort(int[] array,int left,int right){
if(right>left){
int mid = (left+right)/2;
mergeSort(array,left,mid);
mergeSort(array,mid+1,right);
merge(array,left,mid,right);
}
}
2.排序相关问题
215. 数组中第K大的元素
问题描述
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
思路
可以使用快速排序的思路,快排时首先是寻找pivot的位置,通过pivot的位置将数组分成了两部分,左边小于pivot,右边大于pivot。当pivot的位置在nums.length-k
时,该位置的元素就是第k大的元素。
代码
class Solution {
public int findKthLargest(int[] nums, int k) {
int left = 0,right = nums.length-1;
int target = nums.length - k; //第k大的数所在位置
while (left<=right){
int mid = partition(nums,left,right);
if(mid == target)return nums[mid];
else if(mid>target){
right = mid-1;
}else left = mid+1;
}
return -1;
}
public int partition(int[] array,int left,int right){
int pivot = array[left];
while (left<right){
while (left<right && array[right]>=pivot)right--;
array[left]=array[right];
while (left<right && array[left]<=pivot)left++;
array[right]=array[left];
}
array[left]=pivot;
return left;
}
}
347. Top K Frequent Elements (Medium)
问题描述
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
思路
方法一:首先统计数组中的元素出现的频率,然后在频率数组中找寻前k个大小的元素。问题转换为类似215题中的情况。为了方便,代码中直接使用sort()API对其进行排序。
方法二:将频率数组一个个放进小顶堆中,每次放入堆中都会按照按照小顶堆的存放顺序。然后只存放k个元素,每次只要比堆顶大,就放入该元素,直到该元素存放满前k个大小的元素。
代码
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> hashMap = new HashMap<>();
for (int num : nums) {
hashMap.put(num, hashMap.getOrDefault(num, 0)+1);
}
Set<Map.Entry<Integer, Integer>> entries = hashMap.entrySet();
Iterator<Map.Entry<Integer, Integer>> iterator = entries.iterator();
ArrayList<int[]> list = new ArrayList<int[]>();
while (iterator.hasNext()){
Map.Entry<Integer, Integer> next = iterator.next();
list.add(new int[]{next.getKey(),next.getValue()});
}
list.sort(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return Integer.compare(o2[1],o1[1]);
}
});
int[] result = new int[k];
for(int i=0;i<k;i++){
result[i]=list.get(i)[0];
}
return result;
}
}
代码二
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> hashMap = new HashMap<>();
for (int num : nums) {
hashMap.put(num, hashMap.getOrDefault(num, 0)+1);
}
Set<Map.Entry<Integer, Integer>> entries = hashMap.entrySet();
//小根堆
PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return Integer.compare(o1[1],o2[1]);
}
});
for (Map.Entry<Integer, Integer> entry:entries){
int key = entry.getKey();
int value = entry.getValue();
if(queue.size() == k){
if(queue.peek()[1]<value){
//poll()每次把堆顶元素删除(把小的数删除,留下就是大的数)
//最终栈顶存放第k大的数
queue.poll();
queue.offer(new int[]{key,value});
}
}else queue.offer(new int[]{key,value});
}
int[] result = new int[k];
for(int i=0;i<k;i++){
result[i]=queue.poll()[0];
}
return result;
}
}
75. Sort Colors (Medium)
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
思路
方法一:快速排序
方法二:由于只有三个数0,1,2,可以用一个单指针依次排0,1,将它们放在适当的地方,这样3也自然放在了适当位置。
代码(方法二)
class Solution {
public void sortColors(int[] nums) {
int p=0;
for(int i=0;i<nums.length;i++){
if(nums[i]==0){
int tem = nums[p];
nums[p] = nums[i];
nums[i] = tem;
p++;
}
}
for(int i=p;i<nums.length;i++){ //从p的位置重新开始遍历
if(nums[i]==1){
int tem = nums[p];
nums[p] = nums[i];
nums[i] = tem;
p++;
}
}
}
}