数据结构与算法应用(三):Majority Number

题目
No.1 Majority Number
Given an array of integers, the majority number is the number that occurs more than half of the size of the array. Find it.
(给定一个整型数组,找到一个数,它在数组中的出现次数大于数组元素个数的二分之一)
样例For [1, 1, 1, 1, 2, 2, 2], return 1
挑战 Expand O(n) time and O(1) space

分析:我们也许会想到先进行排序,在(n+1)/2位置的数即为要找的数,这样最小的时间复杂度为O(Nlog2N);如果进行hash,数字的范围又未知。

思路:出现的次数超过数组长度的一半,表明这个数字出现的次数比其他数字出现的次数的总和还多。所以我们可以考虑每次删除两个不同的数,那么在剩下的数中,待找数字出现的次数仍然超过总数的一半。通过不断重复这个过程,不断排除掉其他数字,最终剩下的都为同一个数字,即为要找的数字。

package test;
import java.util.ArrayList;
/**
 * 
 * @author 风的流向
 * 
 */
public class Solution {
    /**
     * @param nums
     *            : a list of integers
     * @return: find a majority number
     */
    public int majorityNumber(ArrayList<Integer> nums) {
        // 出现次数超过数组长度
        int end = nums.size() - 1;// 最后一个元素的下标
        for (int i = 1; i <= end; i++) {
            if (nums.get(0) != nums.get(i)) {// 如果找到和第一个元素不相等元素,则删除它们两个
                 nums.remove(i); 
                     nums.remove(0);
                end = end - 2;// 最后一个元素前进两位
                i = 1;// 开始指针指向首元素
            }
        }
        return nums.get(0);
    }
}

【附:开课吧算法讨论组参考答案】
http://www.douban.com/group/topic/67690689/

解法一:O(n)时间复杂度,O(n)空间复杂度
第一种解法为采用Hash表的办法(Hash表在工作中出现的概率非常高!大家一定要熟练运用),Hash表的key是数组中的元素,而value就是这个元素对应的出现次数。
执行过程如下:利用循环依次读取数组中的数字,插入到Hash表中,插入过程中如果发现已存在该值,则对该数字对应的value进行累加1操作,如果为发现Hash表中不存在这个数字,则插入这个数字和它对应的value,value赋值1。而后判断Hash表中的计数器是否满足条件,此过程的时间复杂度为O(n),空间复杂度是O(n)。

提升:常见的Hash表的实现所占用的空间为原始数据的2倍左右,如将一个长度为n的int数组插入到Hash表中需要占用约2*n的单位空间。而Hash的实现往往是考虑冲突概率和空间占用率的一个折中,叫兽有一种Hash的简易实现方法能够在可接受的冲突率下达到1.2倍的空间占用,如有兴趣可以在后面的专题中安排讨论

参考代码

def majorityNumber(self,nums): 
	n = round(len(nums)/2.0) 
	nd = {} 
	for x in nums: 
		if x in nd: 
			nd[x] += 1 
		else: 
			nd[x] = 1 
		if nd[x] >= n: 
			return x 

解法二:O(nlogn)时间复杂度,O(1)空间复杂度
第二种解法为首先对数组进行排序(导致时间复杂度为O(nlogn)),而后遍历数组,并统计相邻两个数字为相等的情况下连续发生的长度,如果这个长度满足条件,则此数字为所求结果。

参考代码

int majorityNumber(vector<int> nums) { 
	// write your code here 
	std::sort(nums.begin(), nums.end()); 
	int count = 1; 
	int previousNum = nums[0]; 

	for (int i = 1; i < nums.size(); i++) 
	{ 
		if (previousNum == nums[i]) 
			count++; 
		else if (count > nums.size() / 2) 
			return previousNum; 
		else 
		{ 
			previousNum = nums[i]; 
			count = 1; 
		} 
	} 
	return previousNum; 
} 

解法三:
定义两个指针preIndex,postIndex,代表数组中两个元素的下标,初始化为0,1。
利用循环,比较两个指针所指向的值,如果相等,则postIndex后移一步,如果不相等,则preIndex和postIndex同时后移两步,表示‘删除’两个元素。循环结束后,返回preIndex所指向的元素。

参考代码:

/** 
* @param nums: a list of integers 
* @return: find a majority number 
*/ 
public int majorityNumber(ArrayList<Integer> nums) { 
	// write your code 
	int preIndex = 0; //定义两个位置 
	int postIndex = 1; 
	while(postIndex < nums.size() - 1){ 
		//如果不相等,两个位置同时向后移动两步 
		if (nums.get(preIndex) != nums.get(postIndex)){ 
			preIndex += 2; 
			postIndex += 2; 
		}else{ 
			//后面的位置向后移动一步 
			postIndex += 1; 
		} 
	} 
	return nums.get(preIndex); 
} 

推荐学习内容:
时间复杂度与空间复杂度:
http://baike.baidu.com/view/7527.htm?fr=aladdin
哈希表
http://baike.baidu.com/view/329976.htm?fr=aladdin

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值