[经典面试题]统计数组

【题目】

给定数组A,大小为n,数组元素为1到n的数字,不过有的数字出现了多次,有的数字没有出现。请给出算法和程序,统计哪些数字没有出现,哪些数字出现了多少次。能够在O(n)的时间复杂度,O(1)的空间复杂度要求下完成么?

【分析】

我们知道原数组是没有排序的。如果排序了,很简单的。O(1)的空间含义,可以使用变量,但不能开辟数组或者map等来计数。

这个题目,很直接的解法就是两层遍历,O(n^2)的复杂度,O(1)的空间。空间满足了,但是时间没有。

很多类似的题目,都会用XOR的方法,大家仔细想一下,这个题目,可以么?或者这个题目和可以用XOR的题目的差异在哪儿?最直接的就是,每一个数字的重复的次数是不同的。

还有就是以空间换时间的方法,例如用hash map或者数组来计数。时间满足了,但是空间没有满足。

那怎样才能有时间复杂度O(n),空间复杂度O(1)的算法呢?不能开辟新的空间,那么只剩下,重复利用数组A。那么该如何利用数组A呢?

(1)首先,我们介绍一种三次遍历数组的方法,我们都考虑数组从0开始:

第一次遍历:对于每一个A[i] = A[i] * n
第二次遍历:对于每一个i,A[A[i]/n]++
第三次遍历:对于每一个i,A[i] % n就是出现次数

A[i]应该出现在A中的A[i]位置,乘以n、再除以n,很容易的来回变换;第二次遍历,对于A[i]本来所在的位置不断增1,但绝对不对超出n的,那每一个i出现的次数,就是A[i]对n取余。

(2)还有一种两次遍历的方法,也是上面的思路:题目中数组是1到n,为了方便算法考虑,以及数组存储方便,我们考虑0-n-1,结果是相同的。 考虑A[i],现在位置是i,如果采用A来计数,它的位置应该是A[i] % n,找到计数位置,该如何处理这个位置呢?加1么? 显然不可以,这里有一个技巧,就是加n,有两个原因

加n可以保证A[i] % n是不变的
A数组,最后每一个元素表示为A[i] = x + k*n,其中x<n,并且k就是我们要统计的频率。

这样,大家也能够明白,为什么A[i]在A中的位置,表示为A[i] % n了吧。

【代码】

#include <iostream>
#include <malloc.h>
#include <stdio.h>
using namespace std;
//统计数组重复元素个数
void ArrayNumCount(int array[],int n){
    int i;
    if(n <= 0 || array == NULL){
        return;
    }
    for(i = 0;i < n;i++){
        array[i] *= n;
    }
    for(i = 0;i < n;i++){
        array[array[i]/n]++;
    }
    for(i = 0;i < n;i++){
        array[i] %= n;
    }
    //输出
    //array[0]存储值为n的个数
    int element;
    for(i = 0;i < n;i++){

        if(i == 0){
            element = n;
        }
        else{
            element = i;
        }
        printf("Element:%d Count:%d\n",element,array[i]);
    }
}

int main() {
    int array[] = {2,3,1,2,4,3,5,3,5,8};
    ArrayNumCount(array,10);
    return 0;
}

代码2:

#include <iostream>
#include <malloc.h>
#include <stdio.h>
using namespace std;
//统计数组重复元素个数
void ArrayNumCount(int array[],int n){
    int i;
    if(n <= 0 || array == NULL){
        return;
    }
    for(i = 0;i < n;i++){
        array[array[i]%n]+=n;
    }
    //输出
    //array[0]存储值为n的个数
    int element,count;
    for(i = 0;i < n;i++){
        count = array[i] / n;
        element = i;
        if(i == 0){
            element = n;
        }
        printf("Element:%d Count:%d\n",element,count);
    }
}

int main() {
    int array[] = {2,3,1,2,4,3,5,3,5,8,11};
    ArrayNumCount(array,11);
    return 0;
}
时间: 2025-01-21 14:05:08

[经典面试题]统计数组的相关文章

[经典面试题][百度]数组A中任意两个相邻元素大小相差1,在其中查找某个数。

题目 数组A中任意两个相邻元素大小相差1,现给定这样的数组A和目标整数t,找出t在数组A中的位置.如数组:[1,2,3,4,3,4,5,6,5],找到4在数组中的位置. 思路 这道题目最差时间复杂度也是O(N),所以重点在于能不能找到一种尽可能减少比较次数的方法. 如数组:[1,2,3,4,3,4,5,6,5],找到4在数组中的位置.4和1比较,差为3,那么即使最好情况(递增或者递减),4也就是在a[3]的位置,可以跳过a[1]a[2].这样在特定数组(目标值和a[1]相差很大)的情况下或许可以

[经典面试题][网易]数组分割

[题目] 任意2N个正整数,从其中选出N个整数,使得选出的N个整数和同剩下的N个整数之和的差最小. [来源] 网易 [分析] 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略. 从2N个数中找N个元素,有三种可能:大于Sum/2,小于Sum/2以及等于Sum/2.而大于Sum/2与小于等于Sum/2没区别,故可以只考虑小于等于Sum/2的情况. 令S(k, i)表示前k个元素中任意i个元素的和的集合.显然: S(k, 1) = {A[i] | 1<= i <=

[经典面试题]排序数组中绝对值最小元素

[题目] 题目为: 有一个已经排序的数组(升序),数组中可能有正数.负数或0,求数组中元素的绝对值最小的数,要求,不能用顺序比较的方法(复杂度需要小于O(n)),可以使用任何语言实现 例如,数组{-20,-13,-4, 6, 77,200} ,绝对值最小的是-4. [分析] 给定数组是已经排好序的,且是升序,没有重复元素. 一个简单的思路,就是一次性遍历数组,求出数组的元素的绝对值的最小值,这样的时间复杂度为O(n). 但是,这样就浪费了题目的一个条件:数组是已经排好序的.所以,需要对原来的题目

PHP经典面试题集锦

 这篇文章主要介绍了PHP经典面试题集锦,搜集整理了常见的php面试题与相关的参考答案,供大家参考借鉴,需要的朋友可以参考下     本文较为详细的分析了PHP经典面试题.分享给大家供大家参考.具体如下: 做了一下网络上的php题目,不知不觉做到现在.....把答案贴出来,供参考之用. 1.用PHP打印出前一天的时间格式是2006-5-10 22:21:21(2分) ? 1 2 $a = date("Y-m-d H:i:s", strtotime("-1 day")

[经典面试题]子数组的最大乘积

题目 给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中的最大的一组,并写出算法的时间复杂度. 思路一 穷举法 我们把所有可能的(N-1)个数的组合找出来,分别计算它们的乘积,并比较大小.由于总共有N个(N-1)个数的组合,总的时间复杂度为O(N^2),但显然这不是最好的思路. 思路二 空间换时间 计算(N-1)个数的组合乘积,假设第i个(0<=i<=N-1)元素被排除在乘积之外(如下图). 设num[]为初试数组 Left[i]表示前i个元素(包括第i个

PHP经典面试题集锦_php技巧

本文较为详细的分析了PHP经典面试题.分享给大家供大家参考.具体如下: 做了一下网络上的php题目,不知不觉做到现在.....把答案贴出来,供参考之用. 1.用PHP打印出前一天的时间格式是2006-5-10 22:21:21(2分) $a = date("Y-m-d H:i:s", strtotime("-1 day")); print_r($a); 2.echo(),print(),print_r()的区别(3分) echo 和print不是一个函数,是一个语言

[经典面试题]二分查找问题汇总

[算法]二分查找算法 1.[给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1.] [题目] 给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1. [分析] 此题也就是求target在数组中第一次出现的位置.这里可能会有人想先直接用原始的二分查找,如果不存在直接返回-1, 如果存在,然后再顺序找到这个等于target值区间的最左位置,这样的话,最坏情况下的复杂度就是O(n)了,没有完全发挥出二

[经典面试题][字典树]字符串唯一前缀问题

题目 一个文件里面有如下字符串 cartefdxh cart carlkijfwe chdfwef cafkekfld ---- 要从文件中找出唯一能代表该字符串的前缀,然后如下输出 cartefdxh carte cart cart carlkijfwe carl chdfwef ch cafkekfld caf 以空格分隔--. 思路 用Trie树实现.为每个节点增加一个变量count,用来记录一共有几个字符串使用该字符.找节点计数为1的节点或者叶子节点. 代码 /*------------

[经典面试题]最大连续乘积

题目 给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8.也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的. 分析 最大乘积连续子串与最大乘积子序列不同,前者子串要求连续,后者子序列不要求连续.初看此题,自然会想到最大连续乘积问题类似于最大子数组和问题 思路一 穷举法 穷举子串的起点和终点. 代码一 /*------------------------------------