出现次数超过一半的数字

题目描述:数组中有一个数出现的次数超过了数组长度的一半,找出这个数。(数组是无序的)。

思路一:先排序。我们如果选择最快的排序算法,时间复杂度是O(log(N))。排序完了之后,一般思路是遍历,然后统计次数,但其实没有必要这么做。因为如果某个数在数组中出现的次数超过了一半,那么在已经排好序的数组索引的n/2就一定是要找的这个数。那么总的时间复杂度其实就是排序的时间复杂度,O(log(N))。

代码比较简单,不再展示,就是一个排序,然后输出。

思路二:散列表,以空间换取时间。把数组中的数当做散列表中的键,值为该键出现的次数。那么,利用散列表完成统计之后,直接遍历整个散列表,直接输出即可。

遍历一次需要的时间是O(N),而构造散列表需要O(N)的空间开销而且还要设计散列函数。有没有更好的方法呢?

思路三:每次删除两个不同的数。我们每次删除数组两个不同的数,不管是不是我们要查找的那个数,那么在剩下的数中,我们要查找的那个数仍然会超过剩余总数的一半。通过不断重复这个过程,最终会找到那个出现次数超过一半的数。这样一算,时间复杂度是O(N),而空间复杂度是O(1)。

那么我们如何能够最高效的删除两个数,完成遍历呢?

方法就是遍历数组的时候保存两个值,一个是temp,用来保存数组遍历到的某个数,另一个是count,用来保存当前数的出现次数初始化1。当遍历到下一个数的时候,可能有如下情况:

1.如果下一个数与之前的temp中保存的数相同 那么count++

2.如果下一个数与之前的temp中保存的数不同 那么count—

3.每当count=0,用temp保存下一个数,并把count设置为1

4.直到遍历完所有的数组。

public class MainB {
    /**
     * 通过不断地删除两个数,找到出现次数超过一半的数
     * 假设输入的是有效的数字
     * @param args
     */
	private static int findOneNumberByDel(int []a,int len){
		int temp =0;
		int count = 0;//用来计数
		for(int i=0;i<a.length;i++){
			if(count ==0 ){ //等于0代表前面的 所有数据恰好已经抵消
				temp = a[i];  //需要重来选择一个元素
				count++;
			}else{
				if(temp == a[i]){ //碰到的一样的
					count++;
				}else{  //碰到不一样的
					count--;
				}
			}
		}
		return temp;
	}
	public static void main(String[] args) {
	    int [] a = {0,1,2,1,1};
	    System.out.println(findOneNumberByDel(a, a.length));
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值