数组中超过出现次数一半的数字 【微软面试100题 第七十四题】

问题要求:

  数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

  参考资料:编程之美2.3 寻找发帖水王

问题分析:

  方法1 对数组排序,然后顺次查找其中最多的;

  方法2 对数组排序,最中间一个肯定为要找的数字,时间复杂度O(NlogN);

  方法3 每次消去数组中两个不同的数,最后剩下的肯定为要找的数字,时间复杂度O(N).

  方法3代码1如下,以下是图解代码1

代码实现:

//代码1#include <stdio.h>

int Find(int* ID, int N);

int main(void)
{
    int ID[30] = {5,6,7,1,2,1,2,1,2,3,3,4,3,2,1,3,2,1,2,1,3,1,1,1,1,1};
    printf("水王id: %d\n",Find(ID,30));
    return 0;
}
int Find(int* ID, int N)
{
    int candidate;
    int nTimes, i;
    for(i = nTimes = 0; i < N; i++)
    {
        if(nTimes == 0)
        {
             candidate = ID[i], nTimes = 1;
        }
        else
        {
            if(candidate == ID[i])
                nTimes++;
            else
                nTimes--;

        }

    }
    return candidate;
}

扩展问题1:

  如果改为该数字长度为数组长度的一半,又该如何求?

问题分析:

  先消掉3个不同的id,再使用代码1的方法求解。因为消除3个不同id时,水王id最多消除一个,则,这样之后水王id个数就大于总数的一半了,就变成原问题了。

代码实现:

  

#include <stdio.h>

int Find(int* ID, int N);

int main(void)
{
    int ID[6] = {2,1,2,1,3,1};
    printf("水王id: %d\n",Find(ID,6));
    return 0;
}
int Find(int* ID, int N)
{
    int candidate;
    int nTimes = 0, i;
    int flag = 0;
    int del[3];
    del[0] = ID[0];
    for(i = 1; i < N; i++)
    {
        if((ID[i] != del[0]) && (flag == 0))
        {
            del[1] = ID[i];
            flag = 1;
            continue;
        }
        if((ID[i] != del[0]) && (ID[i] != del[1]) && (flag == 1))
        {
            flag = 2;
            continue;
        }
        if(nTimes == 0)
        {
             candidate = ID[i], nTimes = 1;
        }
        else
        {
            if(candidate == ID[i])
                nTimes++;
            else
                nTimes--;

        }

    }
    return candidate;
}

扩展问题2:

  如果数组中的3个数字个数都分别超过了数组长度的1/4,又该如何查出它们?

问题分析:

  每次绑定三个id,同时加减。


代码实现:

#include <stdio.h>

void Find(int* ID, int N);

int main(void)
{
    int ID[] = {5,6,7,1,2,1,2,1,2,3,3,4,3,2,1,3,2,1,2,1,3};
    Find(ID,21);
    return 0;
}
void Find(int* ID, int N)
{
    int nTimes[3], i;
    int candidate[3];
    nTimes[0]=nTimes[1]=nTimes[2]=0;
    candidate[0]=candidate[1]=candidate[2]=-1;
    for(i = 0; i < N; i++)
    {
        if(ID[i]==candidate[0])//这几个并列的思想很重要,好好想想
        {
             nTimes[0]++;
        }
        else if(ID[i]==candidate[1])
        {
             nTimes[1]++;
        }
        else if(ID[i]==candidate[2])
        {
             nTimes[2]++;
        }
        else if(nTimes[0]==0)
        {
             nTimes[0]=1;
             candidate[0]=ID[i];
        }
        else if(nTimes[1]==0)
        {
             nTimes[1]=1;
             candidate[1]=ID[i];
        }
        else if(nTimes[2]==0)
        {
             nTimes[2]=1;
             candidate[2]=ID[i];
        }
        else//新的id和已选的三个id不同的时候,让已选的三个id同时-1
        {
             nTimes[0]--;
             nTimes[1]--;
             nTimes[2]--;
         }
    }
    printf("id:   %d %d %d\n",candidate[0],candidate[1],candidate[2]);
    printf("times:%d %d %d\n",nTimes[0],nTimes[1],nTimes[2]);
    return;
}
时间: 2024-10-13 19:46:02

数组中超过出现次数一半的数字 【微软面试100题 第七十四题】的相关文章

【编程题目】数组中超过出现次数超过一半的数字 ☆

74.数组中超过出现次数超过一半的数字(数组)题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字. 思路:分治算法 两两一对 相同留下一个 不同扔掉 多出来的数字单独对比 /* 74.数组中超过出现次数超过一半的数字(数组) 题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字. */ //思路:分治算法 两两一对 相同留下一个 不同扔掉 多出来的数字单独对比 #include <stdio.h> #include <stdlib.h> int fin

调整数组顺序使奇数位于偶数前面 【微软面试100题 第五十四题】

题目要求: 输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 要求时间复杂度为O(n). 参考资料:剑指offer第14题. 题目分析: 使用两个指针,pBegin和pEnd,pBegin从开头往后遍历,pEnd从结尾往前遍历,当pBegin遇到偶数和pEnd遇到奇数时,交换两个数,然后继续遍历,直到pBegin>pEnd,则结束. 代码实现: #include <iostream> using namespace std; void

链表和数组的区别在哪里 【微软面试100题 第七十八题】

题目要求: 链表和数组的区别在哪里? 题目分析: 数组静态分配内存,链表动态分配内存: 数组预先定义长度,链表预先无需管理长度: 数组在内存中连续,链表可能连续: 数组元素在栈区,链表元素在堆区: 数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n): 数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1): 数组相对更省空间,存储一个元素链表还需要存储一个next指针: 数组排序相对比链表简单.

【leetcode 简单】 第七十四题 缺失数字

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数. 示例 1: 输入: [3,0,1] 输出: 2 示例 2: 输入: [9,6,4,2,3,5,7,0,1] 输出: 8 说明: 你的算法应具有线性时间复杂度.你能否仅使用额外常数空间来实现? class Solution: def missingNumber(self, nums): """ :type nums: List[int] :rtype: int 等

数字在排序数组中出现的次数

题目:统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 程序实现: import java.util.Scanner; public class Test38 { public static void main(String[] args) { /**  * 初始化数组,测试数据可以多种途径初始化  */   Scanner in = new Scanner(System.in); /*int[] a = 

【剑指offer】Q38:数字在数组中出现的次数

与折半查找是同一个模式,不同的是,在这里不在查找某个确定的值,而是查找确定值所在的上下边界. def getBounder(data, k, start, end, low_bound = False): if end < start : return -1 while start <= end: mid = ( start + end ) >> 1 if data[ mid ] > k: end = mid - 1 elif data[ mid ] < k: star

九度oj 题目1349:数字在排序数组中出现的次数

题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n,表示数组的大小.1<=n <= 10^6. 第二行有n个整数,表示数组元素,每个元素均为int. 第三行有1个整数m,表示接下来有m次查询.1<=m<=10^3. 下面有m行,每行有一个整数k,表示要查询的数. 输出: 对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数. 样例输入: 8 1 2 3 3 3 3 4 5 1 3 样例输出: 4 使用库函数即可解决

数字在排序数组中出现的次数(剑指offer)利用快排思想(O(logn))

数字在排序数组中出现的次数 参与人数:1216时间限制:1秒空间限制:32768K 通过比例:28.43% 最佳记录:0 ms|0K(来自 ) 题目描述 统计一个数字在排序数组中出现的次数. 题意:首先数组是个已经排列的有序递增序列!统计一个数出现的次数,相当于在有序的序列里插入一个数,那么我只要确定插入的位置,利用快排的思想,也可以说是二分,如果在数组中找到k,那么左右拓展边界就可以确定,该数在数组中出现的次数了. 一些特殊情况可以特判!比如k小于数组最小数,或者大于数组最大数: class

剑指offer 面试题38—数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 解法一:O(n) 顺序遍历 解法二:O(logn) 用二分查找,分别找出第一个3,和最后一个3的位置,然后计算个数. #include <stdio.h> int GetFirstK(int* data,int length,int k,int start,int end) { if(start > end) return -1; int m