zoukankan      html  css  js  c++  java
  • 51-【巧解】统计无序数组各元素出现的次数--时间复杂度O(n),空间复杂度O(1)

    一、问题描述
    【题型一】
    一个长度大小为n的数组,数组中的每个元素的取值范围在[1,n],且为正整数。
    问:如何在时间复杂度为O(n),空间复杂度为O(1)的条件下,统计数组中不同元素出现的次数。

    【题型二】
    在一个长度为n的数组里的所有数字都在0-n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
    【例如】
    如果输入长度为7的数组(2,3,1,0,2,5,3),那么对应的输出是重复的数字2或者3

    二、解题思路
    【题型一】
        数组按序扫描,通过当前元素的值作为下标,找到下一个元素。最后得到的数组中,下标(因为下标从0开始的,故输出时需要+1)为数组中出现的元素,每个下标对应的值取反输出即是该元素出现的频率。
        若当前元素小于0,
            则跳过;
        若当前元素大于0,
            则判断其作为下标索引到的元素是否大于0,
                若大于0,则索引到的元素赋值给当前元素,索引到的元素置为-1;
                若小于0,则索引到的元素自减1,当前元素置为0;

        用正数/负数来区分a[i]上是原来的值,还是用于计数的值
        随便举个例子,比如 { 2, 5, 5, 2, 3 }
        看到第一个是 2,即2有1个,所以先将这个“1”保存到a[2-1]的位置上。但a[2-1]有有效数呀,咋办?移动一下就行。假设我不用负数,而是用中括号来表示计数,步骤依次是
        { 2, 5, 5, 2, 3 }
        5, [1], 5, 2, 3
        3, [1], 5, 2, [1]
        5, [1], [1], 2, [1]
        [0], [1], [1], 2, [2]
        [0], [2], [1], [0], [2]

        结果是 1有0个, 2有2个, 3有1个, 4有0个, 5有2个

        此类以值做下标的方法适用条件:

        正整数
        取值范围[1,n]
        n个数
    【题型二】
    思路一:排序 -- 时间复杂度O(nlogn)
    思路二:哈希表 -- 时间复杂度O(1) 空间复杂度O(n)
    思路三:值为下标 -- 时间复杂度O(n) 空间复杂度O(1)

    思路三:以2,3,1,0,2,5,3为例
    1)数组第0号位置为2,2!=0,将0号位置的2与2号位置的1交换,变成 1,3,2,0,2,5,3
    2)数组第0号位置为1,1!=0,将0号位置的1与1号位置的3交换,变成 3,1,2,0,2,5,3
    3)数组第0号位置为3,3!=0,将0号位置的3与3号位置的0交换,变成 0,1,2,3,2,5,3
    4)数组第0号位置为0,0==0,游标右移至第1号位置,1==1,继续右移,直到第4号位置
    5)数组第4号位置为2, 2!=4, 2==array[2],说明2重复了,输出2,算法结束

    思路三前提条件:
    1)数组中数字范围为[0,n-1]
    2)数组长度为n

    三、算法代码
    【题型一】n个正整数 -- [1,n] 找重复
    #include <stdio.h>
    #include <stdlib.h>
    /*******************************
    Author:tmw
    date:2018-3-17
    ********************************/
    int* mark_times_appear(int* array, int len)
    {
    if(array==NULL || len<0) return NULL;
    int index = 0;
    int i = 0;
    while(i<len)
    {
    /**当前位为正数有效位,则执行交换**/
    while( array[i] > 0 )
    {
    index = array[i];

    /**待交换的位置上的元素是有效值的情况:
    交换,并将当前待交换的元素下的值改成负数计数值
    **/
    if(array[index-1]>0) /**数组下标从0开始**/
    {
    array[i] = array[index-1];
    array[index-1] = -1;
    }
    /**待交换的位置上的元素是负数的情况:
    说明该元素出现过一次了,负数计数需要减减来更新记录
    **/
    else/**若需要返回出现两次的元素,可以直接在这里做返回**/
    {
    //return array[i];
    array[i] = 0;
    array[index-1]--;
    }
    }
    /**当前位为负数,紧接着判断下一位**/
    i++;
    }
    return array;
    }
    【题型二】n个数[0,n] 找重复
    /**************************************************
    author:tmw
    date:2018-8-22
    **************************************************/
    #include <stdio.h>
    #include <stdlib.h>

    #define swap(a,b,t) (t=a,a=b,b=t)
    /** findDuplicatedNumber 找到任意一个重复的元素并输出
    * @param int* array -- 存数字的数组
    * @param int array_len -- 数组长度
    **/
    int findDuplicatedNumber( int* array, int array_len )
    {
    /**入参判断**/
    if( array == NULL || array_len <= 0 )
    return -1;
    int i;
    /**这一步可省略:验证数组内的元素满足给定条件:元素取值[0,n-1],长度为n**/
    for( i=0; i<array_len; i++ )
    {
    if( array[i] < 0 || array[i] > array_len-1 )
    return -1;
    }

    /**主算法**/
    int temp=0;
    for( i=0; i<array_len; i++ )
    {
    while( array[i] != i )
    {
    if( array[i] != array[array[i]] )
    swap(array[i], array[array[i]], temp);
    else
    return array[i];
    }
    }
    return -1; //没找着,返回-1
    }
    四、测试代码及结果
    【题型一】的测试结果

    int main()
    {
    printf("测试代码! ");

    int* array;
    int i;
    array = (int*)malloc(5*sizeof(int));
    printf("请输入5个数组元素: ");
    for( i=0;i<5;i++ )
    scanf("%d",&array[i]);
    array = mark_times_apear(array,5);

    for( i=0;i<5;i++ )
    printf("%d ",array[i]);

    return 0;
    }


     

    梦想还是要有的,万一实现了呢~~~ヾ(◍°∇°◍)ノ゙~~~
    ————————————————
    版权声明:本文为CSDN博主「qiki_tang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qiki_tangmingwei/article/details/80109822

  • 相关阅读:
    WebService通过SOAP头进行身份验证
    【笔记】NIOS II spi详解
    【笔记】关于NIOS II PIO的几个问题
    【笔记】NIOS II Interval Timer Core详解
    【原创】基于NIOS II SPI的ads8321驱动
    【笔记】MATLAB一些常用函数
    【原创】解决on_chip_memory过小的问题,解决Unable to reach errno ...的问题
    【原创】基于FPGA的等精度测频方法(学习实验)
    【原创】等效采样状态机控制工程(测试通过,待完善说明书)
    【原创】基于NIOS II的ADS1256 SPI驱动
  • 原文地址:https://www.cnblogs.com/ExMan/p/14763901.html
Copyright © 2011-2022 走看看