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

60 篇文章 3 订阅

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~


T:

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

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

我的解法:

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

  1. 比较count 与 array.length/2的大小,如果前者大于后者,直接返回array[0]元素;
  2. 即使前者不大于后者,说明这个array[0]不是要寻找的目标元素,此时,记下共有多少与array[0]不同的元素存在(这些元素都在新数组tempArray中),标记为newLength,把tempArray中的元素覆盖在array数组上,继续以上操作;
  3. 继续以上操作的情况分为两种,一种是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;
	    }
	}

更高效的解法

首先看一个规律:

给定一个数组: a r r a y = [ a ( 1 ) , . . . , a ( j ) , a ( j + 1 ) , . . . , a ( n ) ] 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(1),...,a(j)] [ a ( j + 1 ) , . . . , a ( n ) ] [a(j+1), ... , a(n)] [a(j+1),...,a(n)]
设想:如果在 [ a ( 1 ) , . . . , a ( j ) ] [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;
	    }
	}

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值