剑指offer系列27之数组中超过一半的数字

要求

  • 时间限制:1秒
  • 空间限制:32768K
  • 热度指数:275777
  • 本题知识点: 数组

题目描述

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

思路

思路一:守阵地

采用攻守阵地的思想(来源于牛客网评论)。时间复杂度和空间复杂度都为 O ( n ) O(n) O(n)
首先设置第一个数字为士兵守阵地,count=1;往后遍历数组,如果遇到的值不等于当前的士兵,并且count不为0的情况下,count减一,即失去了一个阵地;而如果count为0(没有阵地可以失去了),则将当前值设置为士兵守阵地,并且将count置1;继续向后遍历直至遍历完。则最后剩下的士兵即有可能为要找的值。最后再遍历一遍数组即可确认。
这里可以确定的是如果有满足条件的值,那么一定会幸存下来,而如果没有满足条件的值,无法确定最后得到什么值。因此必须再遍历一次确认结果。即是通过两两抵消,如果样例给的数组确实有个数的次数超过一半,抵消到最后一定就是要求的那个数了。

python实现
# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if not numbers:
            return 0
        count = 1
        tmp = numbers[0]
        for i in range(len(numbers)-1):
            if numbers[i+1]==numbers[i]:
                count += 1
            elif count != 0:
                count -= 1
            elif count == 0:
                tmp = numbers[i+1]
                count = 1
        count = 0
        for i in range(len(numbers)):
            if numbers[i] == tmp:
                count += 1
        return tmp if 2*count>len(numbers) else 0
  • 运行时间:25ms
  • 占用内存:5624k
C++实现
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int length = numbers.size();
        int count = 1; int tmp = numbers[0];
        for (int i=0; i<length-1; i++){
            // 如果后一个值和当前值相等则表明守住了阵地count加一
            if (numbers[i+1] == numbers[i])
                count++;
            // 不想等没守住阵地;
            // 若count不为0继续减1
            else if (count != 0)
                count--;
            // 若count为0重置主人
            else if (count == 0){
                tmp = numbers[i+1];
                count = 1;
            }
        }
        // 判断tmp是否满足条件
        count = 0;
        for (int i=0; i<length; i++)
            if (numbers[i]==tmp)
                count++;
        if (count*2 <= length)
            tmp = 0;
        return tmp;
    }
};
  • 运行时间:3ms
  • 占用内存:476k
思路二:快排

该思路分为两步,即先用快排排序;排序后可知如果存在满足条件的值必在中间位置,然后即可再遍历一次数组统计候选值出现的次数做出最后判断。此种方法的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。主要是为了练习快排的思路。

python实现
# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if not numbers:
            return 0
        length = len(numbers)
        
        def quickSort(numbers, left, right):
            if left >= right: 
                return
            i, j, tmp = left, right, numbers[i]
            while i < j:
                while i<j and numbers[j]>=tmp:
                    j -= 1
                if (i < j):
                    numbers[i] = numbers[j]
                while i < j and numbers[i]<=tmp:
                    i += 1
                if i < j:
                    numbers[j] = numbers[i]
            numbers[i] = tmp
            quickSort(numbers, left, i-1)
            quickSort(numbers, i+1, right)
        
        candidate = numbers[length//2]
        count = 0
        for i in range(length):
            if candidate == numbers[i]:
                count += 1
        return candidate if count*2>length else 0
  • 运行时间:30ms
  • 占用内存:5856k
C++实现
class Solution {
public:
    void quickSort(vector<int> &numbers, int left, int right) {
        if (left >= right)
            return;
        int i = left; int j = right;
        int tmp = numbers[i];
        while (i < j){
            while (i<j && numbers[j]>=tmp) j--;
            if (i<j) numbers[i] = numbers[j];
            while (i<j && numbers[i]<=tmp) i++;
            if (i<j) numbers[j] = numbers[i];
        }
        numbers[i] = tmp;
        quickSort(numbers, left, i-1);
        quickSort(numbers, i+1, right);
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int length = numbers.size();
        if (length==0) return 0;
        quickSort(numbers, 0, length-1);
        // 如果存在满足条件的值一定是中间这个值
        int candidate = numbers[length/2];
        int count = 0;
        for (int i=0; i<length; i++)
            if (numbers[i] == candidate)
                count++;
        return 2*count>length?candidate:0;
    }
};
  • 运行时间:3ms
  • 占用内存:480k
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值