zoukankan      html  css  js  c++  java
  • 《剑指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: 
    ", 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.
    ");
        else
            printf("Failed.
    ");
    
        printf("Test for solution2: ");
        result = MoreThanHalfNum_Solution2(copy, length);
        if (result == expectedValue && g_bInputInvalid == expectedFlag)
            printf("Passed.
    ");
        else
            printf("Failed.
    ");
    
        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;
        }
    };
    牛客网提交代码
  • 相关阅读:
    ELK Packetbeat 部署指南
    ELK beats平台介绍
    ELK Packetbeat 部署指南(15th)
    什么是staging server
    elasticsearch学习一、安装和配置
    How To Use Logstash and Kibana To Centralize Logs On CentOS 6
    Java字节码(.class文件)格式详解(一)
    JVM之字节码——Class文件格式
    如何获得JVM执行过程中调用的方法名
    ELK beats通用配置说明(12th)
  • 原文地址:https://www.cnblogs.com/ZSY-blog/p/12628827.html
Copyright © 2011-2022 走看看