课堂作业——找1

题目:

  给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数。

要求:

  写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数。例如 f(12) = 5;

  在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少?

设计思想:

(解法一)

  开始想到了一个最简单的方法来计算f(N),那就是从1开始遍历,直到N结束,把其中每一个数中含有“1”的个数加起来,结果就是从1到N所有“1”的个数的和。这个方法很简单,但算法的实现效率是个大问题,如果N很大,则需要很长的运算时间才能得到计算结果。

(解法二)

  找了一些资料,发现这也是编程之美里的一道题,得到一点启发。首先列出一些数字的情况,来找到其中隐藏的规律:

一位数: f(0)=0、f(1)=1、f(2~9)=1

两位数(以位数是3的为例,[十位]+[个位]):

f(13)=4+2=6、f(23)=10+3=13 …… f(93)=10+10=20

通过分析发现,个位数出现1 的个数和个位数字与十位数有关:如果N的个位数大于等于1 ,则个位出现1的个数为十位数的数字加1;如果N的个位数的数字小于1,则个位出现1的个数为十位数的数字。十位出现1的次数:如果十位数字等于1,则十位出现1的个数为个位数字加1;如果十位数大于1,则十位出现1的个数为10次。

三位数([百位]+[十位]+[个位]):

f(103)=4+10+11=25、f(113)=14+14+12=40、f(123)=24+20+13=57……

f(193)=94+20+20=134、f(203)=100+20+21……

同理分析四位数、五位数……

(1)

源代码:

#include<iostream.h>
int f(int n)
{
    int i,unit,decade;
    int count=0;
    for(i=1;i<=n;i++)
    {
        decade=i;
        while(decade!=0)
        {
            unit=decade%10;
            decade=decade/10;
            if(unit==1)
            {
                count++;
            }
        }
    }
    return count;
}

void main()
{
    int n,count;
    cout<<"Please input N: ";
    cin>>n;
    count=f(n);
    cout<<"From 1 to "<<n<<",there are "<<count<<" ones."<<endl;
}

运行结果:

(2)

源代码:

#include <iostream>
#include <cstdio>
using namespace std;

int f(int n)
{
    int factor=1;
    int count=0;
    int high=0;
    int current=0;
    int low=0;
    while(n/factor)
    {
        low=n%factor;
        current=n/factor%10;
        high=n/factor/10;
        switch(current)
        {
            case 0:
            count+=high*factor;
            break;
            case 1:
            count+=high*factor+low+1;
            break;
            default:
            count+=(high+1)*factor;
            break;
        }
        factor*=10;
    }
    return count;
}
int main()
{
    int n ;
    while(scanf("%d",&n)!=EOF)
    {
        cout<<f(n)<<endl;
    }
    return 0;
}

运行结果:

总结:

  如果只要求实现基本功能,那实际并不是很难,关键在于当N变得很大时,遍历绝对不是一个好方法,那么就要找到其中隐藏的规律,就像小学奥数一样,在一列数字中,把每个情况都拆开,然后分析,找到隐含的规律。在发现d过程可能要列举很多情况才能发现,也才能肯定最先找到的规律是否正确。不是到确认为止,还要继续扩展,四位数、五位数、六位数……甚至更大,再者就是不确定的N,需要它具有任意性、通用性,而不是单单的特殊的一个数字,类似“abcde”。

  最近老师给的题目都来自《编程之美》里面,题目很典型,主要都是讲究思路和算法,有机会要看看这本书。

时间: 2024-11-08 20:45:41

课堂作业——找1的相关文章

课堂作业找水王2

找水王2: 超级水王没有了.统计结果表明,有3个发帖很多的ID ,他们的发帖数目都超过了帖子总数目N的1/4.你能从发帖ID列表中快速找出他们ID吗? 设计思想: 和上一次的思路同源,如果每次删除四个不同的ID(不管是否包含发帖数目超过总数1/4的ID),那么,在剩下的ID列表中,原先发帖比例大于1/4的ID所占比例仍然大于1/4,可以通过不断重复这个过程,把ID列表中的ID总数降低(转化为更小的问题),从而得到问题的答案. 代码实现: package test1; public class F

课堂作业-找水王2

1.题目要求: 随着论坛的发展,管理员发现水王没有了,但是统计结果表明, 有三个发帖很多的ID.据统计他们的发帖数量超过了1/4,你能从发帖列表中快速找到他们吗? 2.设计思路: 因为三个小水王的ID在所有发帖ID中均超过1/4,所以初始化水王的时候可以用4个ID相比.如果所有ID序列排列在1-4的四个ID中出现相同ID名,那么就可以利用一个包含三个元素的数组初始化小水王ID:如果所有ID序列排列在1-4中无重复ID名,则在排列在4-8中寻找是否存在重复的ID名.以此循环直到找到在4个ID中出现

课堂作业——找水军

题目: 思路: 编程之美的扩展了这个问题,在求解找出一个“水王”的基础上进行补充分析,之前遍历数组的时候只用保存两个值:一个是数组中的ID,一个是它对应出现的次数.而这次需要找出3个ID(即输出3个结果),就需要另开辟新的数组来分别保存.首先保存前3个ID,每当遍历下一个ID的时候,先要判断下一个和当前保存的这3个ID是否有相同的,若有相同的则此ID对应的次数加1:若不同则次数减1.再判断如果有ID次数为零,就用下一个ID把它替换,并把次数设为1.与之前不同的是,可能会出现次数都不为0的情况,这

课堂作业——找“小水王”

一.程序要求 三人行设计了一个灌水论坛.信息学院的学生都喜欢在上面交流灌水,传说在论坛上有一个“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子.坊间风闻该“水王”发帖数目超过了帖子数目的一半. 如果你有一张当前论坛的帖子(包括回帖)列表,其中帖子的作者的ID也在其中,你能快速的找到这个传说中的水王吗? 二.程序设计思想

课堂作业——找水王

题目: 三人行设计了一个灌水论坛.信息学院的学生都喜欢在上面交流灌水,传说在论坛上有一个“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子.坊间风闻该“水王”发帖数目超过了帖子数目的一半.如果你有一张当前论坛的帖子(包括回帖)列表,其中帖子的作者的ID也在其中,你能快速的找到这个传说中的水王吗? 设计思路: (1)输入发帖ID记录表 (2)从第一个ID开始,与后续的发帖ID进行比较,若相同计数器则加一,否则减一.若计数器的数值被减为零,则重新选取当前ID开始记录比较. (3)输出结果 源代码

软件工程概论课堂作业3

题目:返回一个整数数组中最大子数组的和 要求: 输入一个一维整形数组,数组里有正数也有负数. 一维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 设计思想: 用户自定义数组长度并依次输入数组元素,设一个全局变量初始化为零的数组a[N],N=10000: 1.因为该数组首尾相接可视作一个环,那么我们需要在一个合适的位置断开,把数组元素展成一条笔直的带子. (1).设用户自定义数组长度为m,输入数组各元素值a[1

软件工程课堂作业04

软件工程课堂作业04 源代码: 1 package jian; 2 import java.io.*; 3 import java.util.Scanner; 4 public class Point3D{ 5 public static int Lenght(int list[],int lenght) 6 { 7 int i,max; 8 max=list[0]; 9 for(i=1;i<=(lenght-1);i++) 10 { 11 if(list[i]>max) 12 { 13 ma

课堂作业及 动手动脑问题整理

课堂作业一 使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”. 程序: package com; public class Duixiang { public static void main(String[] args){ duixiang a=new duixiang(); a.out(); duixiang b=new duixiang(); b.out(); } } class duixiang{ stati

课堂作业数组最大和

题目: 输入一个一维整形数组,数组里有正数也有负数. 一维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 发表一篇博客文章讲述设计思想,出现的问题,可能的解决方案(多选).源代码.结果截图.总结. 设计思想: 1.设计思想: 首先设置两个变量,分别用来存储数组长度也就是number和结果result:然后再通过语句来询问用户需要的数组长度再设个动态数组用来让用户输入数组中的数字,将每一个数值都存放进数组对应位