• C语言学习(二)


          今天在程序员面试题中,碰到一个有意思的题目:数组a[N],存放了1至N-1个数,其中某个数重复一次,现在要求找出重复的数字且程序时间复杂度必须为O(N)。乍一看,如果不计时间复杂度和空间复杂度程序比较容易编写,但是考虑时间和空间复杂度,笔者首先想到的是用“哨兵”的经典方法。程序如下:

     1 /************************************************************************/
     2 /* 功能:数组a[N],存放了1至N-1个数其中某个数重复一次,找出被重复的数字.时间复杂度必须为o(N)
     3 /* 作者:ZL
     4 /* 日期:2018-04-08   14:38                                                                 
     5 /************************************************************************/
     6 
     7 #include <stdio.h>
     8 
     9 
    10 int do_dup(int a[],int n);
    11 
    12 int main(void)
    13 {
    14     int a[5]={1,2,3,2,4};
    15     int data=0;
    16     int n=5;
    17     int i;
    18     data=do_dup(a,n);
    19     printf("data=%d
    ",data);
    20     for (i=0;i<5;i++)
    21     {
    22         printf("%d
    ",a[i]);
    23     }
    24 
    25     
    26 }
    27 
    28 
    29 int do_dup(int a[],int n)
    30 {
    31     int temp;
    32     while(a[0]!=a[a[0]]) //a[0] 用作“哨兵”
    33     {
    34         temp=a[0];
    35         a[0]=a[temp];
    36         a[temp]=temp;
    37     }
    38     return a[0];
    39    
    40 
    41 }

    程序在VC++6.0运行的结果如下图所示:

             从结果中可以看出找到了数组重复数字,时间复杂也为O(N),却改变了数组原本的值,所以程序还需要改进,笔者借鉴网友提供的思路,用数学中假金条思想,将1到N-1个数看做是重量不同的金条,其中有一个是重复的,现在我们生产出1到N-1个不同重量,无重复的金条,然后将两组金条的重量加和,相减求出重量的差值,在用第1到N-1中最大的数(N-1)减去差值,就求出了需要找到重复数字。

             例如:{1,2,3,3,4}这五个数,可以看做是{1,2,3,4}这四个数中插入了3这个数字,按照上述描述,我们产生{1,2,3,4,5}这五个数,可以看做是{1,2,3,4}中插入了5这个数字,将两组数加和,求出差值2,在用5减去2求得重复数字3。改进后的程序如下所示:

     1 /************************************************************************/
     2 /* 功能:数组a[N],存放了1至N-1个数其中某个数重复一次,找出被重复的数字.时间复杂度必须为o(N)
     3 /* 作者:ZL
     4 /* 日期:2018-04-08   14:38                                                                 
     5 /************************************************************************/
     6 
     7 #include <stdio.h>
     8 
     9 
    10 int do_dup(int a[],int n);
    11 
    12 int main(void)
    13 {
    14     int a[5]={1,2,3,2,4};
    15     int data=0;
    16     int n=5;
    17     int i;
    18     data=do_dup(a,n);
    19     printf("data=%d
    ",data);
    20     for (i=0;i<5;i++)
    21     {
    22         printf("%d
    ",a[i]);
    23     }
    24 
    25     
    26 }
    27 
    28 
    29 int do_dup(int a[],int n)
    30 {
    31    int sum1=0,sum2=0;
    32     int j;
    33     for (j=0;j<n;j++)
    34     {
    35         sum1+=(j+1);
    36         sum2+=a[j];
    37     }
    38     return n-(sum1-sum2);
    39    
    40 
    41 }

    程序在VC++6.0运行的结果如下图所示:

    改进后的程序,没有破坏原来的数组值,比上一个程序好。

  • 相关阅读:
    1289 大鱼吃小鱼
    install ios开发环境
    Xcode_5
    嵌入式学习_AD学习篇
    课务IOS概述_1
    动态规划入门(2):01背包问题
    Python记之薄暮笔记
    线段树进阶:权值线段树
    动态规划入门(1):最长递增子序列
    python记之Hello world!
  • 原文地址:https://www.cnblogs.com/xuelanga000/p/8757701.html
Copyright © 2020-2023  润新知