看题目:

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

我的直接思路:

用map计数,简单直接,遍历一次数组,用hashmap记录,key为int值,value为出现次数;

第二次再用map.entrySet找出有没value大于数组长度一般的entry,有的话返回它的key。

时间复杂度也是2n而已,这个方法时间复杂度是O(n)空间复杂度也是O(n)

代码实现:

/*方法1
蛮力,遍历一次,用一个map来记录
第二次遍历把出现次数大于length/2的那个值找出来
*/ public int MoreThanHalfNum_Solution(int [] array) {
int targetCount = array.length / 2; //key为数组中的值,value为出现的次数
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int temp : array) {
if(map.get(temp) == null)map.put(temp, 1);
else map.put(temp, map.get(temp) + 1);
}
Set<Entry<Integer,Integer>> entrySet = map.entrySet();
for(Entry<Integer,Integer> entry : entrySet) {
if(entry.getValue() > targetCount)return entry.getKey();
}
return 0;
}

方法2:中位数

如果数组是排好序的,就好解决了:
  如果排好序,然后又存在这样的数字的话,那么它的值肯定和数组中间那个值是一样的!!(比如:1,2,2,2,3;或2,2,2,3,4;或2,3,4,4,4等等)
 
所以我们只需要排序后,一次遍历,访问每个元素都和中间值比较,只要相等计数器就加一,遍历完后如果计数器大于数组长度一半就返回那个中间元素就好。
 
排序最快是O(Nlogn),然后加上遍历是O(n),空间复杂度是O(1)
 
代码里直接用的是Arrays的sort方法,它的实现没记错是O(Nlogn)的快排。
看代码:
/*方法2
排序后中位数法
如果有个数字出现的次数大于数组长度的一半,那么这个数组排序后,它的中位数一定是这个数字
*/ public int MoreThanHalfNum_Solution(int [] array) {
Arrays.sort(array);
int count = 0, middleNum = array[array.length / 2];
for(int temp : array) {
if(temp == middleNum)count++;
}
if(count > array.length / 2)return middleNum;
else return 0;
}

方法3:——快排思路

方法2中,我们排序是为了找出中位数,那么如果可以更快地找出中位数就不用排序了。

借鉴快速排序算法,其中的Partition()方法是一个最重要的方法,该方法返回一个index,能够保证index位置的数是已排序完成的,在index左边的数都比index所在的数小,在index右边的数都比index所在的数大。那么本题就可以利用这样的思路来解。

通过Partition()返回index,如果index==mid,那么就表明找到了数组的中位数如果index<mid,表明中位数在[index+1,end]之间;如果index>mid,表明中位数在[start,index-1]之间。直到最后求得index==mid循环结束。

 
说白了就是找中位数这一步,我们不选择直接排序数组,而是用快排的Partition方法
 
该算法的时间复杂度为O(n),空间复杂度为O(1)
 
看代码:
/*方法3
利用快排的思想
*/ public int MoreThanHalfNum_Solution(int [] array) {
if(array.length <= 0)return 0; int begin = 0, end = array.length - 1, middle = array.length / 2;
int partition = partition(array, begin, end); while(partition != middle) {
if(partition > middle) {//中位数在partition的左边
partition = partition(array, begin, partition - 1);
} else {//中位数在partition右边
partition = partition(array, partition + 1, end);
}
} //找出中位数了,看这个中位数出现的次数是否符合要求
int count = 0, middleKey = array[middle];
for(int temp : array) {
if(temp == middleKey)count++;
} if(count > array.length / 2)return array[middle];
else return 0;
} //这个方法是以第一个元素为基准,然后进行划分,划分后比基准元素小的数字都在它左边,比它大的数字都在它右边
返回划分后,这个元素的新index//
private int partition(int[] a, int begin, int end) {
int key = a[begin]; int i = begin, j = end;
while(i < j) {
while(i < j && a[j] >= key)j--;
while(i < j && a[i] <= key)i++;
swap(a, i, j);
}
swap(a, begin, i);
return i;
} //交换数字函数,传入数组还有要交换的两个数字的index//
private void swap(int[] a, int first, int second) {
int temp = a[first];
a[first] = a[second];
a[second] = temp;
}
方法4——阵地攻守思想
第一个数字作为第一个士兵,守阵地;count = 1;
遇到相同元素,count++;
遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,同时count更新为1.
到最后还留在阵地上的士兵,有可能是主元素。
再加一次循环,记录这个士兵的个数看是否大于数组一般即可。
 
这个方法也是主要因为考虑到:题目中要找的数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现的次数的和还要多。,那么肯定最后留下来的是那个出现超过一半的。
 
该方法时间复杂度O(N),空间复杂度O(1)
 
 
实现的时候就维护两个变量:一个是数组中的一个数字,一个是次数。

当我们遍历到下一个数字的时候,

如果下一个数字和当前我们保存的数字相同,则次数加 1;

如果和当前我们保存的数字不同,则次数减 1;

当次数减到 0 的时候,我们将保存的数字改为当前遍历所处的位置,并将次数更改为 1。

看代码:

/*方法4
阵地攻守思想,其实和牛客上面那个什么“用户分形叶”的思路一样的,不同实现而已
*/
public int MoreThanHalfNum_Solution(int [] array) {
//int count = 1;
int count = 0;//这里我们设初始的count为0好了,因为利用java的foreach语法是要从第一个key开始遍历的,那么就是碰到第一个开始,设为1
int key = array[0];
for(int temp : array) {
if(temp == key)count++;
else if(count > 0)count--;
else {//count==0的情况,这个时候把key换成现在这个元素,并把count设为1,意思是这是第一次碰到这个元素
key = temp;
count = 1;
}
} //判断这个得到的key是不是符合要求
int count2 = 0;
for(int temp : array) {
if(temp == key)count2++;
}
if(count2 > array.length / 2)return key;
else return 0;
}

剑指Offer——数组中出现次数超过一半的数字——一题多解的更多相关文章

  1. python剑指offer数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  2. 剑指offer——数组中出现次数超过一半的数字(c++)

    题目描述数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如 ...

  3. 剑指Offer——数组中出现次数超过一半的数字

    题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2 ...

  4. 用js刷剑指offer(数组中出现次数超过一半的数字)

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  5. 剑指Offer-28.数组中出现次数超过一半的数字(C++/Java)

    题目: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如 ...

  6. 剑指offer--11.数组中出现次数超过一半的数字

    unique(), count()函数好用 ---------------------------------------------------------------------- 时间限制:1秒 ...

  7. 1-剑指offer: 数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  8. 剑指offer-数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  9. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

随机推荐

  1. 使用Visual Studio进行单元测试-Part4

    本文主要介绍Visual Studio(2012+)单元测试框架的一些技巧: 如何模拟类的构造函数 优化代码,便于测试 一.如何模拟类的构造函数 1.1 被测代码 基础代码,IShape分别有Rect ...

  2. 洛谷【P1898】缘分计算

    我对模拟的理解:http://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.luogu.org/problemnew/show/P189 ...

  3. JSP介绍(3)---JSP表单处理

    GET方法: GET方法将请求的编码信息添加在网址后面,网址与编码信息通过"?"号分隔.如下所示: http://www.runoob.com/hello?key1=value1& ...

  4. 对象流demo1----

    对象流demo1: package com.etc.test; import java.io.BufferedInputStream; import java.io.BufferedOutputStr ...

  5. Android Studio的Android Monitor窗口中把标签拉出来之后放不回去的解决方法

    不小心把下图方框中的logcat标签拖出来之后, 就变成了图2的浮动窗口,发现logcat标签怎么也弄不回原来窗口中的位置中. 其实解决方法很简单,只要拖住下图浮动窗口中红框位置的logcat标签,然 ...

  6. ADO.NET 对象

    (一)OleDbConnection 使用COM组件链接 (二)ADO.NET 对对数据库访问做了优化: 1.SqlConnection 用于建立和Sql Server服务器连接的类,表示打开数据库 ...

  7. 【Java】Java程序员面试宝典(第三版)第5章----Java程序设计基本概念

    1.static静态变量,在次级作用域也可以被修改. 2.k++ + k++.第一个自加实际上只有在与计算+k++时补增.详情P36的题目. 3.Java数据类型从低到高分为(byte short c ...

  8. MySQL的变量--系统变量、状态变量

    MySQL的变量分为以下两种:1)系统变量:配置MySQL服务器的运行环境,可以用show variables查看2)状态变量:监控MySQL服务器的运行状态,可以用show status查看 一.系 ...

  9. ASPX 关闭子窗口后自动更新父窗口

    Response.Write("<script language:javascript>javascript:window.close();</script>&quo ...

  10. Hadoop 1.2.1 MapReduce 例子

    自学hadoop真的很困难,主要是hadoop版本太混乱了,各个版本之间兼容性并不算太好.更主要的是网上的很多MapReduce的Java例子不写import!!!只写类名!!!偏偏Hadoop中有很 ...