《剑指offer》第三十九题:数组中出现次数超过一半的数字

// 面试题39:数组中出现次数超过一半的数字
// 题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例
// 如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中
// 出现了5次,超过数组长度的一半,因此输出2。

#include <cstdio>
#include "Array.h"

bool g_bInputInvalid = false;

bool CheckInvalidArray(int* numbers, int length)  //检查是否有效输入
{
    g_bInputInvalid = false;
    if (numbers == nullptr || length <= 0)
        g_bInputInvalid = true;

    return g_bInputInvalid;
}

bool CheckMoreThanHalf(int* numbers, int length, int number)  //检查结果是否出现次数超过一半
{
    int times = 0;
    for (int i = 0; i < length; ++i)
    {
        if (numbers[i] == number)
            ++times;
    }

    bool isMoreThanHalf = true;
    if (times * 2 <= length)
    {
        g_bInputInvalid = true;
        isMoreThanHalf = false;
    }

    return isMoreThanHalf;
}

// ====================方法1====================
// 利用随机快速排序算法, 随机选一个数排序, 查看此数位置, 
// 如位于前半部分,则需要查找的数位于后半部分, 反之, 位于前半部分
int MoreThanHalfNum_Solution1(int* numbers, int length)
{
    if (CheckInvalidArray(numbers, length))
        return 0;

    int middle = length >> 1; //此处表示中位 = length/2
    int start = 0;
    int end = length - 1;
    int index = Partition(numbers, length, start, end); //随机快速排序算法
    while (index != middle) //如果随机选择的数刚好处于中位, 则跳出
    {
        if (index < middle) //位于前半部分
        {
            start = index + 1;
            index = Partition(numbers, length, start, end);
        }
        else //index > middle
        {
            end = index - 1;
            index = Partition(numbers, length, start, end);
        }
    }

    int result = numbers[index];
    if (!CheckMoreThanHalf(numbers, length, result))
        result = 0;

    return result;
}

// ====================方法2====================
// 从第一个数开始计算次数, 次数为0时换为当前数, 则寻找的数是最后times不为0的数
int MoreThanHalfNum_Solution2(int* numbers, int length)
{
    if (CheckInvalidArray(numbers, length))
        return 0;

    int times = 1;
    int result = numbers[0];
    for (int i = 1; i < length; ++i)
    {
        if (times == 0)
        {
            result = numbers[i];
            times = 1;
        }
        else if (result == numbers[i])
            ++times;
        else
            --times;
    }

    if (!CheckMoreThanHalf(numbers, length, result))
        result = 0;

    return result;
}
//Array.cpp
#include <stdlib.h>
#include "Array.h"
#include <exception>

// Random Partition
int RandomInRange(int min, int max)  //范围内随机选一个数字
{
    int random = rand() % (max - min + 1) + min;
    return random;
}

void Swap(int* num1, int* num2)
{
    int temp = *num1;
    *num1 = *num2;
    *num2 = temp;
}

int Partition(int data[], int length, int start, int end)
{
    if(data == nullptr || length <= 0 || start < 0 || end >= length)
        throw new std::exception("Invalid Parameters");

    int index = RandomInRange(start, end);
    Swap(&data[index], &data[end]);  //随机值放到最后

    int small = start - 1;  //small作为最小数字的索引一直把比随机值小的数字往前放
    for(index = start; index < end; ++ index)
    {
        if(data[index] < data[end])
        {
            ++ small;
            if(small != index)
                Swap(&data[index], &data[small]);
        }
    }

    ++ small;
    Swap(&data[small], &data[end]);  //把随机值放到比它小的数字后

    return small;
}
#pragma once

__declspec( dllexport ) int Partition(int data[], int length, int start, int end);
Array.h
// ====================测试代码====================
void Test(const char* testName, int* numbers, int length, int expectedValue, bool expectedFlag)
{
    if (testName != nullptr)
        printf("%s begins: \n", testName);

    int* copy = new int[length];
    for (int i = 0; i < length; ++i)
        copy[i] = numbers[i];

    printf("Test for solution1: ");
    int result = MoreThanHalfNum_Solution1(numbers, length);
    if (result == expectedValue && g_bInputInvalid == expectedFlag)
        printf("Passed.\n");
    else
        printf("Failed.\n");

    printf("Test for solution2: ");
    result = MoreThanHalfNum_Solution2(copy, length);
    if (result == expectedValue && g_bInputInvalid == expectedFlag)
        printf("Passed.\n");
    else
        printf("Failed.\n");

    delete[] copy;
}

// 存在出现次数超过数组长度一半的数字
void Test1()
{
    int numbers[] = { 1, 2, 3, 2, 2, 2, 5, 4, 2 };
    Test("Test1", numbers, sizeof(numbers) / sizeof(int), 2, false);
}

// 不存在出现次数超过数组长度一半的数字
void Test2()
{
    int numbers[] = { 1, 2, 3, 2, 4, 2, 5, 2, 3 };
    Test("Test2", numbers, sizeof(numbers) / sizeof(int), 0, true);
}

// 出现次数超过数组长度一半的数字都出现在数组的前半部分
void Test3()
{
    int numbers[] = { 2, 2, 2, 2, 2, 1, 3, 4, 5 };
    Test("Test3", numbers, sizeof(numbers) / sizeof(int), 2, false);
}

// 出现次数超过数组长度一半的数字都出现在数组的后半部分
void Test4()
{
    int numbers[] = { 1, 3, 4, 5, 2, 2, 2, 2, 2 };
    Test("Test4", numbers, sizeof(numbers) / sizeof(int), 2, false);
}

// 输入空指针
void Test5()
{
    int numbers[] = { 1 };
    Test("Test5", numbers, 1, 1, false);
}

// 输入空指针
void Test6()
{
    Test("Test6", nullptr, 0, 0, true);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();

    return 0;
}
测试代码

分析:第二种思路没有改变数组且想法清奇。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        
        int length = (int)numbers.size();
        
        if (numbers.empty())
            return 0;
        
        int times = 1;
        int result = numbers[0];
        for (int i = 1; i < length; ++i)
        {
            if (times == 0)
            {
                times = 1;
                result = numbers[i];
            }
            else if (result == numbers[i])
                ++times;
            else
                --times;
        }
        if (!CheckMoreTnanHalf(numbers, length, result))
            result = 0;
        
        return result;
    }
    bool CheckMoreTnanHalf(vector<int> numbers, int length, int result)
    {
        int times = 0;
        for (int i = 0; i < length; ++i)
        {
            if (numbers[i] == result)
                ++times;
        }
        bool isMoreTnanHalf = false;
        if (length < (times << 1))
            isMoreTnanHalf = true;
        return isMoreTnanHalf;
    }
};
牛客网提交代码

 

posted @ 2020-04-03 20:42  源周率  阅读(185)  评论(0编辑  收藏  举报