案例4
荷兰国旗问题。只包含0,1,2的整数数组进行排序,要求使用交换、原地排序,而不是利用计数进行排序。
分析:本题主要过程与快排划分过程类似。时间复杂度O(N),空间复杂度O(1)。
如图,一次检查,为0,就和首位交换,然后0区吃一个数;为2,就和末位交换,然后2区吃一个数。检查到二区域位置,整个过程结束。
#include<iostream>
#include<vector>
using namespace std;
void out(vector<int> arr,int n){ //数组输出
for(int k=0;k<n;k++){
cout<<"arr["<<k<<"]:"<<arr[k]<<endl;
}
}
void sort(vector<int> &arr, int length){
int k=length-1;//后面数组位置记录点
int temp;
int j=0;//前面数组位置记录点
for(int i=0;i<=k;i++){//i为当前点
if(arr[i]==0){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
j++;
}
if(arr[i]==2){
temp=arr[i];
arr[i]=arr[k];
arr[k]=temp;
k--;
i--;//关键点!!!!与后面数组交换时,位置点保持不动
}
}
}
int main(){
int num;
vector<int>arr;
cout<<"荷兰国旗"<<endl;
int n = 0;//n表示输入个数
while (cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回车,终止
break;
}
sort(arr,n); //排序
out(arr,n); //输出数组
}
案例5
在行列都排行序的矩阵中找数
0 1 2 5
2 3 4 7
4 4 4 8
5 7 7 9
若k为7,返回true;若k为6,返回false。
若矩阵为(m*n),该题最优解可以做到时间复杂度O(m+n),额外空间复杂度O(1)。
方法,从右上角找。
看5,5大于3,向左;
看2,2小于3,向下;
以此方法,找。找到,true。找到越界,false。
#include<iostream>
#include<vector>
using namespace std;
bool sort(int **arr, int row,int line,int num){
int i=0;
int j=line-1;
while(i<row&&j>=0){
if(arr[i][j]>num){
j--;
}
else if(arr[i][j]<num){
i++;
}
else if(arr[i][j]==num){
cout<<i<<" "<<j;//若能找到,输出行列的位置
return true;
}
}
return false;
}
int main(){
cout<<"请输入二维数组长和宽"<<endl;
int row,line;//定义行列
cin>>row>>line;
int **arr=new int*[row]; //根据行数动态分配数组行大小
for(int i=0;i<row;i++){
arr[i]=new int[line];//根据列数动态分配数组列大小
}
cout<<"请输入二维数组"<<endl;
for(int i=0;i<row;i++)
for(int j=0;j<line;j++)
cin>>arr[i][j];
cout<<"输出二维数组"<<endl;
for(int i=0;i<row;i++){
for(int j=0;j<line;j++)
cout<<arr[i][j]<<" ";
cout<<endl;
}
cout<<"请输入需要找的数"<<endl;
int num;
cin>>num;
bool result=sort(arr,row,line,num);
if(result==true)
cout<<"TRUE"<<endl;
else
cout<<"FALSE"<<endl;
}
案例6
需要排序的最短子数组长度
1 5 4 3 2 6 7
返回4,因为只有5 4 3 2需要排序。
该题最优解可以做到时间复杂度O(N),额外空间复杂度O(1)。
方法:从左向右遍历整个数组。
首先,从左向右遍历,记录最大值,只关系右边数比左边数小的这种情况。然后记录发生这种情况的最右位置。对此题,max=7,最右位置=2。
下从右往左遍历,记录最小值,和比其大的情况的最左位置。对此题,最左为5,min=1。最左最右位置中间的数就是需要排序的最短子数组
#include<iostream>
#include<vector>
using namespace std;
void search(vector<int>arr, int length,int &max,int &right){
for(int i=1;i<length;i++){//从左向右遍历,寻找需排序数组的右边界
if(arr[i]>=max)
max=arr[i];
else
right=i;
}
}
void search2(vector<int>arr, int length,int &min,int &left){
for(int i=length-2;i>=0;i--){//从右向左遍历,寻找需排序数组的左边界
if(arr[i]<=min)
min=arr[i];
else
left=i;
}
}
int main(){
int num;
vector<int>arr;
int n = 0;//n表示输入个数
while(cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回车,终止
break;
}
int max=arr[0];
int min=arr[n-1];
int left=20;
int right=20; //左右边界初始值,任意给定,只要两个数相同,说明不需要排序
search(arr,n,max,right);//寻找需排序数组的右边界
search2(arr,n,min,left);//寻找需排序数组的左边界
if(left==right)
cout<<"不需要排序";
else
cout<<right-left+1;
}
案例7
给定一个整形数组arr,返回如果排序之后,相邻两数的最大差值。
例如:
1 2 3 4 7 8 9
最大是3,4 7之间
该题最优解可以做到时间复杂度O(N),额外空间复杂度O(N)。
思想来自桶排序。
解:随机数组
7 9 3 4 2 1 8
遍历一遍,得到min=1,max=9
总共7个数,分成7个桶。
不用考虑同一个桶的相邻数,只用考虑桶之间的相邻数。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int sort(vector<int>arr, int n){
vector<vector<int>> B(n+1);//定义一个二维数组,用于记录每个桶的数,每个桶放两个值,最大值和最小值
int max,min,i,j,maxGap;
float k;
for(i=1,max=min=arr[0];i<n;i++){//记录数组最大值和最小值
if(arr[i]>max)
max=arr[i];
if(arr[i]<min)
min=arr[i];
}
float gap=1.0*(max-min)/n; //gap用来区分放入哪个木桶中,即桶的大小
for(i=0;i<n;i++){
k=(arr[i]-min)/gap;//很关键!!!先计算出值,在赋值给j(j为int型,四舍五入)
j=k;
if(B[j].empty()){ //若为空,该值同时赋给最大值和最小值
B[j].push_back(arr[i]);
B[j].push_back(arr[i]);
}
else{
if(B[j][0]>arr[i])
B[j][0]=arr[i];//刷新最小值
if(B[j][1]<arr[i])
B[j][1]=arr[i];//刷新最大值
}
}
for(i=j=0,maxGap=0;i<n;i=j)
{
while(B[i].empty())
i++;//若下个桶为空,就继续向下走
max=B[i][1];
j=i+1;
if(j<n+1)
{
while(B[j].empty())
j++;
if(j>=n+1)
break;
min=B[j][0];
if(min-max>maxGap)
maxGap=min-max;
}
}
return maxGap;//输出结果
}
int main(){
int num;
vector<int>arr;
int n = 0;//n表示输入个数
while(cin >> num){
arr.push_back(num);
n++;
if(cin.get() == '\n') //遇到回车,终止
break;
}
int a=sort(arr,n);//计数排序
cout<<a;
}