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

(首先,关于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$的空间就够了,然后统计的时候,复原即可。

原文地址:https://www.cnblogs.com/raymondjiang/p/12026372.html

时间: 2024-10-16 01:52:03

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

Coursera_程序设计与算法_计算导论与C语言基础_数组应用练习

您也可以在我的个人博客中阅读此文章:跳转 编程题#1:求字母的个数 描述 在一个字符串中找出元音字母a,e,i,o,u出现的次数. 输入 输入一行字符串(字符串中可能有空格,请用gets(s)方法把一行字符串输入到字符数组s中),字符串长度小于80个字符. 输出 输出一行,依次输出a,e,i,o,u在输入字符串中出现的次数,整数之间用空格分隔. ##样例输入If so, you already have a Google Account. You can sign in on the right

C语言基础学习3:数组与指针

数组元素的指针就是数组元素的地址. 1.指向数组元素的指针 C语言规定数组名(不包括形参数组名,形参数组并不占据实际的内存单元)代表数组中的首元素(即序列为0的元素)的地址. int a[10]; int *p1,*p2; p1 = &a[0]; p2 = a; p1和p2指向同一个数组a[10]. 2.通过指针引用数组元素 按C语言的规定,如果指针变量p已指向数组中的一个元素,则p+1指向同一个数组中的下一个元素,而不是将p的值(地址)简单的加1. 如果p的初值为&a[0],则 (1)

问题 1018: C语言程序设计教程(第三版)课后习题6.8

/******************************************************************** @file Main.cpp @date 2017-05-12 @author Zoro_Tiger @brief 问题 1018: C语言程序设计教程(第三版)课后习题6.8 http://www.dotcpp.com/oj/problem1018.html *************************************************

问题 1041: C语言程序设计教程(第三版)课后习题9.8

/******************************************************************** @file Main.cpp @date 2017-05-28 22:02:55 @author Zoro_Tiger @brief 问题 1041: C语言程序设计教程(第三版)课后习题9.8 http://www.dotcpp.com/oj/problem1041.html ****************************************

问题 1040: C语言程序设计教程(第三版)课后习题9.6

/******************************************************************** @file Main.cpp @date 2017-05-28 21:57:02 @author Zoro_Tiger @brief 问题 1040: C语言程序设计教程(第三版)课后习题9.6 http://www.dotcpp.com/oj/problem1040.html ****************************************

问题 1042: C语言程序设计教程(第三版)课后习题9.10

/******************************************************************** @file Main.cpp @date 2017-05-28 22:10:10 @author Zoro_Tiger @brief 问题 1042: C语言程序设计教程(第三版)课后习题9.10 http://www.dotcpp.com/oj/problem1042.html ***************************************

问题 1023: C语言程序设计教程(第三版)课后习题7.2

/******************************************************************** @file Main.cpp @date 2017-05-20 22:05:39 @author Zoro_Tiger @brief 问题 1023: C语言程序设计教程(第三版)课后习题7.2 http://www.dotcpp.com/oj/problem1023.html ****************************************

问题 1008: C语言程序设计教程(第三版)课后习题5.6

/******************************************************************** @file Main.cpp @date 2017-5-8 @author Zoro_Tiger @brief 问题 1008: C语言程序设计教程(第三版)课后习题5.6 http://www.dotcpp.com/oj/problem1008.html ***************************************************

问题 1006: C语言程序设计教程(第三版)课后习题5.4

/******************************************************************** @file Main.cpp @date 2017-05-07 @author Zoro_Tiger @brief 问题 1006: C语言程序设计教程(第三版)课后习题5.4 http://www.dotcpp.com/oj/problem1006.html *************************************************