剑指offer排序题目汇总
剑指 Offer 40. 最小的k个数
题目
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
代码
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
sort(arr.begin(), arr.end());
return vector<int>({arr.begin(), arr.begin() + k});
}
};
剑指 Offer 41. 数据流中的中位数
题目
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例 1:
输入:
[“MedianFinder”,“addNum”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
示例 2:
输入: [“MedianFinder”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]
限制:
最多会对 addNum、findMedian 进行 50000 次调用。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof
代码
二分插入有序数据流,查找时取值即可
class MedianFinder {
public:
/** initialize your data structure here. */
int a[50005];
int n=0;
MedianFinder() {
}
void addNum(int num) {
if(n==0){
a[0] = num;
n++;
return;
}else{
int start = 0, end = n-1;
int mid;
while(start <= end){
mid = start + (end - start) / 2;
if(a[mid] <= num){
start = mid + 1;
}else{
end = mid - 1;
}
}
if(a[mid] <= num){
mid++;
}
for(int i=n; i > mid; i--){
a[i] = a[i-1];
}
a[mid] = num;
n++;
}
}
void print(){
for(int i=0; i < n; i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
double findMedian() {
//print();
if(n % 2){
return a[n / 2];
}else{
return (a[n / 2 -1] + a[n / 2]) * 1.0 / 2;
}
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
剑指 Offer 51. 数组中的逆序对
题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
解析
比较暴力的做法是用两个for循环去嵌套,但是这样会超时,较好的做法是运用排序,在排序的过程中求逆序对
代码
归并排序求逆序对
int res;
void msort(int* SR, int* TR1, int s, int t, int numsSize);
int reversePairs(int* nums, int numsSize){
if(numsSize == 0){
return 0;
}
res=0;
int* TR1 = (int*)calloc(numsSize, sizeof(int));
msort(nums, TR1, 0, numsSize-1, numsSize);
return res;
}
void msort(int* SR, int* TR1, int s, int t, int numsSize){
if(s == t){
TR1[s] = SR[s];
return;
}else{
int mid = s + (t - s) / 2;
msort(SR, TR1, s, mid, numsSize);
msort(SR, TR1, mid+1, t, numsSize);
int m = mid;
int i=s, j=m+1, k=0;
if (s >= t) {
return 0;
}
while(i<=m && j <= t){
if(SR[i] <= SR[j]){
TR1[k++]=SR[i];
res += (j-(m+1));
i++;
}else{
TR1[k++]=SR[j];
j++;
}
}
while(i<=m){
TR1[k++] = SR[i++];
res += (j-(m+1));
}
while(j<=t){
TR1[k++] = SR[j++];
}
for(int i=0; i < k; i++){
SR[i+s] = TR1[i];
}
}
}
剑指 Offer 45. 把数组排成最小的数
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: “102”
示例 2:
输入: [3,30,34,5,9]
输出: “3033459”
提示:
0 < nums.length <= 100
说明:
输出结果可能非常大,所以你需要返回一个字符串而不是整数 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof
代码
这里我们使用快排,只不过排序的条件换成了左加右和右加左的比较
class Solution {
public:
int Partition(vector<string> &L, int low, int high){
string pivotkey = L[low];
while(low < high){
while(low < high && pivotkey + L[high] <= L[high]+pivotkey){
high--;
}
string tmp;
tmp = L[low];
L[low] = L[high];
L[high] = tmp;
while(low < high && pivotkey + L[low] >= L[low] + pivotkey){
low++;
}
tmp = L[low];
L[low] = L[high];
L[high] = tmp;
}
return low;
}
void QSort(vector<string> &L, int low, int high){
if(low < high){
int pivotloc = Partition(L, low, high);
QSort(L, low, pivotloc-1);
QSort(L, pivotloc+1, high);
}
}
string minNumber(vector<int>& nums) {
vector<string> L;
for(auto n:nums){
L.push_back(to_string(n));
}
QSort(L, 0, nums.size()-1);
string ans="";
for(auto l:L){
ans += l;
cout<<l<<endl;
}
return ans;
}
};
剑指 Offer 61. 扑克牌中的顺子
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5]
输出: True
示例 2:
输入: [0,0,1,2,5]
输出: True
限制:
数组长度为 5
数组的数取值为 [0, 13] .
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof
代码
因为只有5张牌,并且0可以替代任何数值,所以只要最大值和最小值的差值小于5并且没有重复值即可
class Solution {
public:
bool isStraight(vector<int>& nums) {
int j=0, minn = 14, maxn = -1;
set<int> s;
for(int i=0; i < nums.size(); i++){
if(!nums[i]){
j++;
}else if(!s.count(nums[i])){
s.insert(nums[i]);
minn = min(minn, nums[i]);
maxn = max(maxn, nums[i]);
}else{
return false;
}
}
return maxn - minn < 5;
}
};