最近看了好多数据结构文章,可是数据结构拾遗系列迟迟憋不出,主要缘由是不少数据结构其实很是偏门,不只平常很难遇到,学起来还涉及不少数学模型,很难有快速的理解方法。git
本着女排“短平快”的精神,先更新下剑指offer题解系列。github
众所周知,《剑指offer》是一本“好书”。面试
为何这么说?由于在面试老鸟眼里,它里面罗列的算法题在面试中出现的频率是很是很是高的。有多高,以我目前很少的面试来看,在全部遇到的算法体中,本书算法题出现的几率大概是60%,也就是10道题有6题是书中原题,若是把变种题目算上,那么这个出现几率能到达90%。算法
若是你是个算法菜鸡(和我同样),那么最推荐的是先把剑指offer的题目搞明白。后端
对于剑指offer题解这个系列,个人写做思路是,对于看过文章的读者,可以作到:数组
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。因为数字2在数组中出现了5次,超过数组长度的一半,所以输出2。若是不存在则输出0。安全
该方法改变了原数组。bash
首先要获得一个推论,那就是一旦有数字大于数组的一半,那么排序后的数组的中位数确定是这个数字,那么咱们就先找出这个数字。微信
这种算法是受快速排序算法的启发。在随机快速排序算法中,咱们如今数组中随机选择一个数字,而后调整数组中数字的顺序,使得比选中的数字小的数字都排在它的左边,比选中的数字大的数字都排在它的右边。若是这个选中的数字的下标恰好是n/2,那么这个数字就是数组的中位数。若是它的下标大于n/2,那么中位数应该位于它的左边,咱们能够接着在它的左边部分的数组中查找。若是它的下标小于n/2,那么中位数应该位于它的右边,咱们能够接着在它的右边部分的数组中查找。这是一个典型的递归过程数据结构
找到这个数字后,再判断他是否符合条件(大于数组的一半),由于颇有可能他是数组中出现次数最多的,可是未必大于数组的一半。
详细细节见代码注释。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array.length<=0) {
return 0;
}
int start = 0;
int length = array.length;
int end = length-1;
// 右移1位,至关于除2,效率更高
int middle = length>>1;
// 当前位置
int index = Partition(array,start,end);
// 直到取到中位数,才是结果
while(index!=middle){
if(index>middle){
index = Partition(array,start,index-1);
}
else{
index = Partition(array,index+1,end);
}
}
int result = array[middle];
// 须要统计该数字个数,必需要大于数组长度的一半才能算
int times = 0;
for(int i=0;i<length;i++){
if(result==array[i]){
times++;
}
}
if(times*2 <= length){
result = 0;
}
return result;
}
// 快排中的每次排序实现,返回的是交换后start位置,也就是index一直改变的位置
private int Partition(int[] array,int start,int end){
// 取平均值不必定是整数,因此必须除2取整,不能右移
int flag = (array[start]+array[end])/2;
while(start<end){
while(array[end]>flag){
end--;
}
swap(array,start,end);
while(array[start]<=flag){
start++;
}
swap(array,start,end);
}
return start;
}
private void swap(int[] array, int num1, int num2){
int temp = array[num1];
array[num1] = array[num2];
array[num2] = temp;
}
}
复制代码
该方法不改变原数组。
若是有符合条件的数字,则它出现的次数比其余全部数字出现的次数和还要多。 在遍历数组时保存两个值:
遍历下一个数字时,若它与以前保存的数字相同,则次数加1,不然次数减1;若次数为0,则保存下一个数字,并将次数置为1。
遍历结束后,所保存的数字即为所求。
以后,还要再判断它是否符合大于数组的一半。
详细细节见代码注释。
public int MoreThanHalfNum_Solution(int [] array) {
int length = array.length;
// 检测数组是否为空
if (length == 0){
return 0;
}
// 初始化result和times参数
int result = array[0];
int times = 1;
//遍历数组(因为初始化过,因此直接从第二个数字开始)
for(int i=1;i<length;i++){
// 次数为0时写入下一个数字并将次数置1
if(times == 0){
result = array[i];
times = 1;
}
// 数字相同,加1
else if(array[i] == result){
times++;
}
// 数字不一样,减1
else{
times--;
}
}
// 须要统计该数字个数,必需要大于数组长度的一半才能算
times = 0;
for(int i=0;i<length;i++){
if(result==array[i]){
times++;
}
}
if(times*2 <= length){
result = 0;
}
return result;
}
复制代码
将数组中的数字依次遍历,并写入hashmap中,hashmap的值是该数字出现的次数,并在每次循环中判断是否该数次数大于数组的一半,如有直接返回数字,不然遍历完数组返回0。
思路简单,代码略。
三种方法时间复杂度都是O(n)
我是一名后端开发。主要关注后端开发,数据安全,爬虫等方向。微信:yangzd1102
Github:@qqxx6661
我的博客:
若是文章对你有帮助,不妨收藏起来并转发给您的朋友们~