敲七

来源:互联网 发布:我的世界拔刀剑js 编辑:程序博客网 时间:2024/06/10 11:31
敲七:
    写一个程序, 打印从1到N之间的所有能被7整除和所有包含数字'7'的数.
    例如: 给定20, 输出7, 14, 17

解题思路一:
    最直观的方法, 循环遍历1到N 的每一个数, 判断是否能够被7整除或包含数字'7'.很容易写出如下代码:
    while( i<=N )    {        if( N % 7 == 0 || contain7( N ) )            print( "%d ", i );     }


但该解题方法存在大量的除法和模运算(contain7函数), 而且需要遍历每一个元素). 那么对该解法的优化肯定是在如和避免测试1到N之间的每一个数, 直接打印出符合条件的数.

解题思路二:
    通过分析, 可以将题目的要求细化为两个: a. 能被7整除的数; b. 包含数字'7'的数.
如果我们能够获得1到N中符合这两个条件的数, 并将它们分别存放在两个数组中, 然后通过归并即可获得题目所需要的结果数组.
    对于要求a. 能被7整除的数相对而言较简单, 对于1到N中可以被7整除的数的个数为N/7, 那么可以立刻写出获得满足要求a的字数组multiple[]的代码:
    int * multiple = (int*)malloc( sizeof(int) * (N/7) );    multiple[0] = 7;    for( i=1; i<=N/7; i++)    {        multiple[i] = multiple[i-1] + 7;    }



对于要求b. 包含数字'7'的数要困难些.

分析:

         位数为一的N最多只包含一个含'7'的数字: 7

         位数为2位的N, 含7的数有 7, 17, 27, 37, 47, 57, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 87, 97 共19个数; 我们把位数为2的数包含'7'的数分成三组:
              7                              -->位数为1的N 所包含的含'7'的数
             17, 27, 37, 47, 57, 67, 87, 97        -->由位数为1的含'7'的数构成: ( i*10 + 7) : i不等于7
              和70, 71, 72, 73, 74, 75, 76, 77, 78, 79           -->最高位为'7'的数: ( 7*10 + {0,1, ..., 9})

        位数为3为的N, 含7的数有 7, 17, 27, 37, 47, 57, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 87, 97, 107, 117, 127, ..., 700, 701, 702, 703, ..., 799, 807, 817, ..., 987, 997共271个数; 我们也把位数为3的包含'7'的数分成三组:
             7, 17, 27, 37, 47, 57, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 87, 97           -->位数为2的N 所包含的含'7'的数
             107, 117, 127, 137, ..., 697, 807, 817, ..., 907, 917, ..., 997               -->由位数为2的含'7'的数构成: ( i*100 + { 7, 17,..., 97}) : i属于[1到9] 但 i不等于7
              和 701, 702, 703, ..., 799                    -->最高位为'7'的数: ( 7*100 + {0,1,2,..., 99} )

    由上面的分析,可以得出位数为i位的N包含的数字'7'的数字集合可依据位数为i-1位的数来构造. 假设array[i]表示包含数字'7'的i位的数字集合,
    array[i][j] = { array[i-1] }
U { k*(10的i-1次方) + array[i-1];   k<7 }
U { 7*(10的i-1次方) + [0,1, ..., (10的i-1次方)-1] }
U { k*(10的i-1次方) + array[i-1]; 7< k<10 }

依据上面的状态转移方程, 可以得到如下的核心代码(该代码将打印所有位数小于等于I位的含'7'的数):
   
base = 10;       array[1] = { 7 };    //位数为1为的N, 只有7for( i=2; i<I; i++)    //I为N的位数{        array[i] = array[i-1]; //->位数为(i-1)的N 所包含的含'7'的数        for( j=1; j<10;j++)        {            //最高位为'7'的数: ( 7*(10的i-1次方)+{0,...,(10的i-1次方)减1} )            if( j== 7 )            {                for( k=0; k<base-1; k++ )                    array[i].back_insert( 7*base + k );             }            else            {               //->由位数为(i-1)的含'7'的数构成: ( i*(10的i-1次方) + array[i-1]) : // i属于[1到9] 但 i不等于7               for( m=0; m<array[i-1].size; m++ )                     array[i].back_insert( j*base + array[i-1][m] );            }        }        base *= 10; }

   最后将multiple与array[I]归并便为题意所求结果数组.

   其实在<<编程之美>>有一道题2.4: 1的数目和本题中求1到N中包含'7'的数的个数非常相似, 都是采用自底向上的动态规划的思想来实现的.


附: 完整代码

/*  * problem description: * write a program to print the nubmers that contains digit '7' or  * mulitply of 7 from 1 to N. * for instance: * given N = 30 *  output: 7, 14, 17, 21, 27, 28 *//* * solution: *the most intuitionistic solution is testing number from 1 to N to  * see if the tested number fulfils the requirement, if fulfilled then print * otherwise skip it. * ********* *there are another sulotion. *we can divide the result array 7, 14, 17, 21, 27, 28 into two subarrays: * subarray of number contains '7': 7, 17, 27,.... * subarray of number that is multiple of number 7: 7, 14, 21, 28, .... * at the end, we merge the two subarray into one, at the meantime, eliminating * duplicated numbers. *  * author: Jun Shaw  2011/12/3 */#include <stdio.h>#include <string.h>#include <assert.h>#include <malloc.h>#include <stdlib.h>#define MAXLINE 200//计算n的位数int digits( int n ){int numdigits = 1;while( n/10 ){numdigits++;n /= 10;}return numdigits;}//计算1到n中, 包含数字'7'的数的个数int count( int n ){int numdigits = digits( n );int i,j,total,base,digit;int *baseNum = (int*)malloc(sizeof(int)*numdigits);bool flag;//count the number of k-digits number that contains '7' base = 1;baseNum[0] = 1;//1-digits number that contains '7'for( i=2; i<numdigits; i++ ) //2-digits number to (n-1)-digits number{base *= 10;baseNum[i-1] = baseNum[i-2]*9 + base; }base *= 10;total = 0;flag = false;//indicates weather digit '7' is showingfor( i=1; i<numdigits; i++ ){digit = n/base;n %= base;if( digit < 7 ){total += digit * baseNum[numdigits-i-1];}else if( digit == 7 ){total += digit * baseNum[numdigits-i-1] + n + 1;flag = true;break;}else{total += digit * baseNum[numdigits-i-1] + base - 1;}base /= 10;}if( !flag && n>=7 )total ++;free( baseNum );return total;}//归并,并去出重复的数字//调用着负责释放resultArrint mergeDelDuplicated( int **resultArr, const int *arrA, size_t sizeA, const int *arrB, size_t sizeB ){assert( arrA != NULL && arrB != NULL );int i,j,k;*resultArr = (int*) malloc( sizeof(int)*(sizeA+sizeB) );if( *resultArr == NULL )return -1;i=0, j=0, k=0;while( i<sizeA && j<sizeB ){if( arrA[i] <= arrB[j] ){//delete duplicated valueif( arrA[i] == arrB[j] )j++;(*resultArr)[k++] = arrA[i++];}else(*resultArr)[k++] = arrB[j++];}while( i<sizeA ){(*resultArr)[k++] = arrA[i++];}while( j<sizeB ){(*resultArr)[k++] = arrB[j++];}return k;}//敲七,打印符合条件的数void Print7RelatedNumber( int n ){int *multiple = (int*)malloc( sizeof(int)*(n/7) );int *digitseven = NULL;int sizeSeven;int base,curBase;int i,j,m,k,total;int numDigits;bool flag = true;//put nmuber that is multiple of 7 into subarray multiplemultiple[0] = 7;for( i=1; i<=n/7; i++ )multiple[i] = multiple[i-1] + 7;//get the digit number of nnumDigits = digits( n );//获取包含数字'7'的字数组//first, get the number of number that contains '7' rang 1 to nsizeSeven = count( n );digitseven = (int*) malloc( sizeof(int)*sizeSeven );digitseven[0] = 7;//一位数j=1;total=1;//两位数 到 numDigits位数的自底向上求解base = 1;for( k=2; flag && k<=numDigits; k++ ){base *= 10;for(m=1;flag && m<10;m++){ curBase = base*m; if( m==7 ){//等于7时for( i=0; flag && i<base; i++ ){if( curBase + i > n ){flag = false;break;}digitseven[j++] = curBase + i;}}else{//其它情况for( i=0; flag && i<total; i++ ){if( curBase + digitseven[i] > n ){ flag = false;break;}digitseven[j++] = curBase + digitseven[i];}}}total = j;}//归并,并去出重复的数字int *arr = NULL;total = mergeDelDuplicated( &arr, multiple, n/7, digitseven, sizeSeven );//打印for( i=0; i<total; i++ ){if( i%10 == 0 )printf( "\n" );printf( "%d\t", arr[i] );}free( arr );free( digitseven );free( multiple );}int main( ){Print7RelatedNumber(134);return 0;}



原创粉丝点击