offer5
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。
题目可以利用快速排序第一步来做,先选取首位的值,将小于该值的放在左边,大于等于该值的放在右边,如果该值的位置正好是k,那么该值连同左边的值就是最小的k个,如果位置小于k,那么在右边继续执行,如果大于k,那么在左边继续执行,时间复杂度平均是O(N)。
代码:
int FindPos(int *a, int low, int high)
{
int k=a[low];
int i,j;
i=low;
j=high;
while (i<j)
{
while (j>i && a[j]>=k)
j--;
a[i]=a[j];
while (i<j && a[i]<k)
i++;
a[j]=a[i];
}
a[i]=k;
return i;
}
void Find(int *a, int low, int high, int key)
{
if (low<=high)
{
int pos=FindPos(a, low, high);
if (pos+1==key)
{
int i=0;
while (i<=pos)
{
printf("%3d ",a[i]);
i++;
}
printf("\n");
}
if (pos+1<key)
Find(a, pos+1, high, key);
if (pos+1>key)
Find(a, low, pos-1, key);
}
}
还有另外一种思路,类似动态规划
首先我从头开始拿出k个值来,保存好,然后从数组读入一个新的值,如果新值比 k个值中最大值要小,那么就替换掉最大值,否则不替换,直到数组中所有数据全部读取完。k比较小时可以采用数组,k比较大值采用最大堆存储,首位就是k中的最大值,更新最大值也很方便,复杂度是O(logk)。
offer29
输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
左右开始,然后找到左边第一个偶数和右边第一个奇数,直到左右相遇。奇偶判断可以采用位运算,最位为1那么就是奇数,否则为偶数。
代码:
void Reorder(int *a, int low, int high)
{
if (!a || low>=high || low<0 || high<0)
return;
while (low<high)
{
while (low<high && a[low]%2)
low++;
while (low<high && a[high]%2==0)
high--;
if (low<high)
{
swap(a[low], a[high]);
low++;
high--;
}
}
}