您的位置:首页 > Web前端

《剑指offer》——数组中出现次数超过一半的数字

2015-11-27 17:14 381 查看
我的解法

更高效的解法

T:

题目描述

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

如果用暴力搜索,那就太没意思了,所有的问题都可以用枚举法解决。

我的解法:

把当前array数组的第0号元素,即array[0],与后面的作比较,如果相等,计数器count ++;否则,就把不同的元素放在一个新数组tempArray中,等这一轮遍历完之后:

比较count 与 array.length/2的大小,如果前者大于后者,直接返回array[0]元素;

即使前者不大于后者,说明这个array[0]不是要寻找的目标元素,此时,记下共有多少与array[0]不同的元素存在(这些元素都在新数组tempArray中),标记为newLength,把tempArray中的元素覆盖在array数组上,继续以上操作;

继续以上操作的情况分为两种,一种是array数组中根本就不存在目标元素,此时,有newLength = 0;如果存在,就会从while循环的判断条件跳出。

code:

/**
* T: 数组中出现次数超过一半的数字
*
* 题目描述
* 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
* 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,
* 超过数组长度的一半,因此输出2。如果不存在则输出0。
*
* date: 2015.11.27
* @author SSS
*
*/
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if (array.length == 0 || array == null) {
return 0;
}
int targetNum = 0;

int newLength = array.length;
int []tempArray = new int[array.length];

// 统计每个数字在数组中的个数
int count = 0;
int curNum = array[0];
while (count <= array.length / 2) {
// 说明数组已到最后
if (newLength == 0) {
break;
}

int k = 0;
count = 0;
//每次都用array数组的第0号元素与后面的相比,把不同的元素放在新数组tempArray中
for (int i = 0; i < newLength; i++) {
if (array[0] != array[i]) {
tempArray[k++] = array[i];
} else {
count ++;
}
}
curNum = array[0];
newLength = k;
for (int i = 0; i < newLength; i++) {
array[i] = tempArray[i];
}
}
// 这种情况下,不是经由while退出的,而是因为找不到此类元素而退出的,要返回0
if (count <= array.length / 2) {
targetNum = 0;
} else {
targetNum = curNum;
}

return targetNum;
}
}


更高效的解法

首先看一个规律:

给定一个数组:array=[a(1),...,a(j),a(j+1),...,a(n)]array = [a(1), ... , a(j) , a(j+1), ... , a(n)]

将数组分为两部分: [a(1),...,a(j)][a(1), ... , a(j)] 和 [a(j+1),...,a(n)][a(j+1), ... , a(n)]

设想:如果在 [a(1),...,a(j)][a(1), ... , a(j)] 部分中,如果某个元素正好只占一半,单考虑这部分数组,该元素是不会成为目标元素的,那么可以继续寻找下一部分数组中能超过一半的元素。

而本代码的思想也是如此,设定初始元素,看其在一部分数组中占有的比例,当比例达到一半时,就抛弃,相当于前半部分不曾有过,把下一个元素设定为主对比元素,重复此步骤。

以上讲解也说不清楚,看代码,比较简单:

code:

/**
* T: 数组中出现次数超过一半的数字
*
* 题目描述
* 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
* 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,
* 超过数组长度的一半,因此输出2。如果不存在则输出0。
*
* date: 2015.11.27  18:49
* @author SSS
*
*/
public class Solution {
/**
* 解题的另一种方式,时间复杂度O(n)
* @param array
* @return
*/
public int MoreThanHalfNum_Solution(int [] array) {
int targetNum = 0;
if (array.length == 0 || array == null) {
return 0;
}

//当前num元素的计数
int count = 1;
int num = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] == num) {
count ++;
} else {
count --;
}
// 小于零,则说明array[i]之前的元素中,没有一个元素的个数超过了半数,
// 顶多是一半,或者更少,这个时候就要从后面的元素重新开始找
if (count < 0) {
num = array[i];
count = 1;
}
}

int numCount = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == num) {
numCount ++;
}
}
if (numCount <= array.length / 2) {
return 0;
} else {
targetNum = num;
}

return targetNum;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: