(首先,关于Honor Code,我咨询过了Help Center,分享课后练习的思考题的想法是可以的(注意不是代码),但要标明引用,引用格式来源于https://guides.lib.monash.edu/citing-referencing/apa-university-course-materials。)

北京大学(Producer). (2019) . 计算导论与C语言基础[Coursera] . Retrieved from https://www.coursera.org/learn/jisuanji-biancheng/programming/eWlOp/shu-zu-ying-yong-lian-xi

题目1:循环移动

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

  给定一组整数,要求利用数组把这组数保存起来,再利用实现对数组中的数循环移动。假定共有n个整数,则要使前面各数顺序向后移m个位置,并使最后m各数变为最前面的m各数。

  注意,不要用先输出后m个数,再输出前n-m个数的方法实现,也不要用两个数组的方式实现。

  要求只用一个数组的方式实现,一定要保证在输出结果时,输出的顺序和数组中数的顺序是一致的。

输入

  输入有两行:第一行包含一个正整数n和一个正整数m,第二行包含n个正整数。每两个正整数中间用一个空格分开。

输出

  输出有一行:经过循环移动后数组中整数的顺序依次输出,每两个整数之间用空格分隔。

样例输入

11 4
15 3 76 67 84 87 13 67 45 34 45

样例输出

67 45 34 45 15 3 76 67 84 87 13

提示

  这是一道经典的算法问题,在企业面试里出现概率很高。除了循环m次每次移动一个数以外(这样需要对数组操作m*n次),你还能想到更高效的算法吗(只用操作3*n次)?依然要求不使用额外数组,在原数组上移位之后顺序输出。

想法:

  思路1:

    其实最简单的想法,比循环m次每次移动一个数,更容易想到的方法就是扩大存储数的数组大小,但这个时候,就要操作$2n-m$次,空间复杂度就要变成$O(m+n)$,当$m$很大的时候就很不划算了。

  思路2:

    其实关键的问题在于我们移动位置的时候,没有空位,所以一个想法就是制造一个空位,在存储数的数组最后加一位,然后每次对空位操作,将空位前$m+1$的数移过来,直到数组第0位为空位。(说实话,程序编出来,尝试了几组数据可行,感觉也是可行,但证明的时候,就不行了。)


题目2:中位数

注意: 总时间限制: 2000ms 内存限制: 65536kB

描述

  中位数定义:一组数据按从小到大的顺序依次排列,处在中间位置的一个数或最中间两个数据的平均值(如果这组数的个数为奇数,则中位数为位于中间位置的那个数;如果这组数的个数为偶数,则中位数是位于中间位置的两个数的平均值).

  给出一组无序整数,求出中位数,如果求最中间两个数的平均数,向下取整即可(不需要使用浮点数)

输入

  该程序包含多组测试数据,每一组测试数据的第一行为N,代表该组测试数据包含的数据个数,1 <= N <= 15000.

  接着N行为N个数据的输入,N=0时结束输入

输出

  输出中位数,每一组测试数据输出一行

样例输入

4
10
30
20
40
3
40
30
50
4
1
2
3
4
0

样例输出

25
40
2

提示

  这是也一道经典的算法问题,在企业面试里出现概率很高,是“找到第K大的数”的变种。先排序再找中位数自然是很直接的做法,但排序本身很慢。我们只想找到第n/2大的数,对于其他数的顺序我们并不关心。那么怎么在不排序的前提下找到第n/2大的数呢?

想法

  我们直接讨论“找到第K大的数”。

  思路1:

    咨询了一下NOI银牌(目前),金牌(必定)选手#YZZX_hhr#,他跟我说这个问题其实等价于找“K个最大的数”,所以一个比较显然的算法,就是每次对整个数组访问一遍,找到最大的数,然后挑出来。然后从挑出来的数中找到最小的(这个可以通过一个变量,存储当前挑出来的数中最小的来实现)。时间复杂度在$O(kn)$,当$k$比较大的时候,比如$k>log(n)$时,就不如排序了。

  思路2:

    也是hhr给的想法,二分,先扫一遍,找到最大,最小,然后二分,显然时间复杂度$O(n*log(n))$,跟排序差不多。

  思路3:

    据hhr所言,这个有线性算法,但非常复杂,叫严格线性快速选择,据说有相关论文,没找到。


题目3:校门外的树

注意: 总时间限制: 1000ms 内存限制: 65536kB

描述

  某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

  马路上有一些区域要用来建地铁,这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入

  输入的第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

输出

  输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

样例输入

第一组
500 3
150 300
100 200
470 471
第二组

500 3
100 200
150 160
180 190

样例输出

第一组
298
第二组

400

提示

  由于数据范围不大(L<=10000),我们可以使用一个10001长度的数组来记录每一个坐标上有没有树。但想象一下如果数据范围很大,比如下面这个情况,你怎么办呢?

输入

 
5000000 3
1500000 3000000
1000000 2000000
4700000 4700001

输出

2999998
 
 想法:
  这道题就很经典了。
  思路1:
    其实我最开始的想法是线段树。。。后来想想没必要那么复杂。
  思路2:
    其实这道题的一个改进就是,原本用一个长度为L的数组记录每个位置被访问(就是被区间覆盖的次数),每次给定区间,不仅要遍历每一个元素,而且还占空间,所以这里我们使用差分法,就是构建一个新的数组,其中每一项是原本那个长度为L的数组的对应项减去前一项的值。这个时候给定区间后,只要在起点+1,在终点后一位-1就行了。注意,此时如果想从新数组恢复到原数组,只要一个for循环,边遍历边累加,每个位置累加的值就是原数组对应项的值。
  思路3:
    思路2还有一个问题就是如果L太大,并且区间的覆盖很稀疏,这个时候不仅浪费,而且可能开不了这么大的数组,所以一个优化就是:先读进所有的区间,然后进行离散,即对0,L,和所有区间的起点,终点进行升序排序,然后将他们重新对应新的数字(如1,5,2000 -> 1,2,3),这个时候只要至多$2M+2$的空间就够了,然后统计的时候,复原即可。
 
 
 

[Coursera][计算导论与C语言基础][Week 10]对于“数组应用练习”课后习题的思考题的一些想法的更多相关文章

  1. Coursera课程笔记----计算导论与C语言基础----Week 10

    C程序中的数组(Week 10) 一维数组 数组的定义 类型 数组名[常量表达式] int sheep[10] 定义数组时,[]内必须为常量表达式 可以用const int 可以在main函数前,#d ...

  2. Coursera课程笔记----计算导论与C语言基础----Week 6

    理性认识C程序 导论(Week 6) 明确学习进度 讲课内容 感性➡️理性➡️函数➡️指针等 作业练习 初级阶段 ➡️正常作业练习 C语言的由来 程序设计语言的分类 低级语言之机器语言 0010101 ...

  3. Coursera课程笔记----计算导论与C语言基础----Week 8

    C语言中的运算成分(Week 8) 赋值运算符 "="赋值运算符 给赋值号左边的变量赋予数值 在变量定义的同时可以为变量赋初值 要点一:两面类型不同 若=两边的类型不一致,赋值时要 ...

  4. Coursera课程笔记----计算导论与C语言基础----Week 7

    C语言中的数据成分(Week7) 内存 把内存想象成长带,带子上有许多方格,每个方格有8位(8bit) 2^10 = 1024 1B = 8 b 1KB = 1024Byte MB.GB.TB.PB- ...

  5. Coursera课程笔记----计算导论与C语言基础----Week 4

    感性认识计算机程序(Week 4) 引入 编程序 = 给计算机设计好运行步骤 程序 = 人们用来告诉计算机应该做什么的东西 问题➡️该告诉计算机什么?用什么形式告诉? 如果要创造一门"程序设 ...

  6. Coursera课程笔记----计算导论与C语言基础----Week 2

    计算机的历史与未来(Week 2) 计算机历史 早期计算机:手工计算器➡️机械计算器➡️计算机原型 现代计算机:电子管计算机➡️晶体管计算机➡️集成电路计算机➡️超大规模集成电路 早期的手工计算辅助工 ...

  7. Coursera课程笔记----计算导论与C语言基础----Week 1

    计算机的基本原理(Week 1) 第一次数学危机 公元前500年,毕达哥拉斯学派,他们相信数是万物的本源:一切数均可表示成整数或者整数之比 然而毕达哥拉斯证明了勾股定理,某些直角三角形的三边比不能用整 ...

  8. Coursera课程笔记----计算导论与C语言基础----Week 9

    C语言中的控制成分(Week 9) 计算机程序的基本结构 任何具有单入口单出口的程序,都可以用顺序结构.分支结构.循环结构来表达 分支语句 在执行if语句前,先对表达式求解 if()内可以是任意的数值 ...

  9. Coursera课程笔记----计算导论与C语言基础----Week 3

    存储程序式计算机 冯·诺伊曼式计算机 "关于EDVAC的报告草案" 组成:控制器(协调工作).运算器(算数&逻辑运算).存储器(存储操作信息和中间结果).输入设备.输出设备 ...

随机推荐

  1. RocketMQ 主从同步若干问题答疑

    目录 1.初识主从同步 2.提出问题 3.原理探究 3.1 RocketMQ主从读写分离机制 3.2 消息消费进度同步机制 4.总结 温馨提示:建议参考代码RocketMQ4.4版本,4.5版本引入了 ...

  2. 『题解』洛谷P2357 守墓人

    Portal Portal1: Luogu Description 在一个荒凉的墓地上有一个令人尊敬的守墓人,他看守的墓地从来没有被盗过, 所以人们很放心的把自己的先人的墓安顿在他那守墓人能看好这片墓 ...

  3. 基于docker实现redis高可用集群

    基于docker实现redis高可用集群 yls 2019-9-20 简介 基于docker和docker-compose 使用redis集群和sentinel集群,达到redis高可用,为缓存做铺垫 ...

  4. 提交代码到github托管

    廖雪峰官网:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000,感觉初学很棒的一个地 ...

  5. (二)初识NumPy库(数组的操作和运算)

    本章主要介绍的是ndarray数组的操作和运算! 一. ndarray数组的操作: 操作是指对数组的索引和切片.索引是指获取数组中特定位置元素的过程:切片是指获取数组中元素子集的过程. 1.一维数组的 ...

  6. 使用Topshelf组件 一步一步创建 Windows 服务

    我们先来介绍一下使用它的好处,以下论述参考自其他大神. topshelf是创建windows服务的一种方式,相比原生实现ServiceBase.Install.Installer更为简单方便, 我们只 ...

  7. lqb 基础练习 十进制转十六进制

    基础练习 十进制转十六进制 时间限制:1.0s   内存限制:512.0MB     问题描述 十六进制数是在程序设计时经常要使用到的一种整数的表示方式.它有0,1,2,3,4,5,6,7,8,9,A ...

  8. linux/CentOS的安装(萌新版)

    一.CentOS的下载 1.官网下载网址:https://www.centos.org/ 2.下载具体步骤(2019年9月): 1.浏览器输入官方网址 2.点击网页的橙色按钮进入到下一界面 3.此时会 ...

  9. 阿里云ECS搭建kubernetes1.11

    环境信息 说明 1.使用kubeadm安装集群 虚拟机信息 hostname memory cpu disk role node1.com 4G 2C vda20G vdb20G master nod ...

  10. tcp和udp的网络编程(发送消息及回复)

    一.UDP  无连接的  高效的  基于数据报的  不可靠 的连接 主要的应用场景: 需要资源少,网络情况稳定的内网,或者对于丢包不敏感的应用,比如 DHCP 就是基于 UDP 协议的.不需要一对一沟 ...