求助c语言基础题目的两道题(要解释)



实现一个函数,可以左旋字符串中的k个字符。

不可能把a直接放到f上,因为会覆盖掉f,所以需要另找一块空间。

第一步:找一块空间放a;

第二步:把a后面的元素分别都向前移一位;(知道总元素个数,用下标做到)

第三步:在原本放f的位置上放a;

//每次左旋一个字符: //把所有元素都向前移了一步,数据不会覆盖、丢失:

假设对abcdef进行左旋两个字符:

2. 把两个字符后面的字符也逆序:bafedc

3. 把整个字符串逆序:cdefab,即实现了左旋两个字符

这是经典的方法:三步翻转法——对前一部分进行逆序,后一部分逆序,整个字符串再逆序

//逆序k个字符,第k个字符的下标是k-1,则第k个字符的地址是str+k-1 //第k+1个字符的下标是k,则第k个字符的地址是str+k //若输入的k过大就会导致越界,则对k进行取模处理: //若k=10,而只有6个字符,因为前6次左旋后逆序又变成自己原来的字符串的顺序,所以k%len k %= len;//此时左旋10个字符和左旋4个字符是一样的

写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

就是判断s2是不是s1旋转得来的:

即把s1先左旋转1个判断是否相等,s1先左旋转2个判断是否相等,s1先左旋转3个判断是否相等……旋转、判断;旋转、判断……把所有旋转的结果可能性都判断一下,若都不相等则就不是旋转得来的。
注意:共有5个字符时,左旋转5个和左旋转0个是一个意思。

//每次左旋一个字符:

长度不同、大小写不同则都会返回0,不是旋转得到的。

对AABCD字符串旋转是想得到它旋转之后的可能性。
则可以用一种快捷的方法:
(在AABCD后面追加上一个AABCD)这个新的字符串里就包含了AABCD所有旋转的可能性:
即思路:自己给自己追加一个自己,看是否为它包含的字符串,如果是就是旋转得来的。

注意:用strcat()函数追加自己的时候,可能会有bug:

当追加到\0的时候,把a赋值给\0,即\0已经被该成a了,没有\0了,则这个追加是不会停下来的。追加的时候是把源数据拷贝放到目标中,而此时源和目标的空间会有重叠。自己把自己的结束标志给断送了,会导致问题,所以不用strcat自己给自己追加。

有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。

要求:时间复杂度小于O(N);

查找某个元素——若遍历二维数组,若数组有n个元素,
则最坏情况下找n次,即时间复杂度为O(N),而题目要求时间复杂度小于n。

时间复杂度小于O(N)的算法:

把要找的元素如7与右上角的元素相比,要么去掉一行要么去掉一列。

若要找的元素是k=2,比右上角的3小,因为3是一列中最小的元素,所以去掉一列;
若要找的元素是k=7,比右上角的3大,因为3是一行中最大的元素,所以去掉一行;7比在剩下的元素中右上角的6还要大,则又去掉一行;7与剩下元素中右上角的9小,则在这一行中查找7,(因为9已经是剩下元素所在列中最小的元素)去掉一列;8比7大说明还在8的左边,去掉一列;7与7相等则找到;如果7还找不到则结果就是找不到。

虽然封装了函数,但是找到的下标是自己打印的,这不是好的解决办法。

解决办法:用函数查找,用函数带回或返回找不到。

但是return不能直接带回两个值。

//数组中合理的坐标不可能是-1和-1 //传x和y的地址,则在函数中所求的下标就可以通过这两个地址放到x、y中

既可以带进函数两个值:3和3,在函数中使用;又可以在函数结束的时候带回值——这种设计是返回型参数(输出型参数),用指针修改,把数值带回去。


会发现右上角元素和左下角元素都满足查找的特点:
右上角元素:一行中最大,一列中最小;
左下角元素:一列中最小,一列中最大。
而左上角元素和右下角元素不行。


有如下宏定义和结构定义:

//pointer为malloc开辟的一个(……)里的结构体大小,由上述计算简写为:

下面代码的结果是( )(在VS环境下)

//定义了一个位段式的结构体: //意思是结构体指针指向了数组puc,把字符数组强制类型转换为struct tagPIM*这样一个在结构体指针赋给pstPimData //即pstPimData指针指向了4个字符类型元素的数组 //但是由于pstPimData是结构体指针类型,这个结构体大小是一个2字节大小的 //则pstPimData这个位段式的结构体指针最多能访问2个字节

%x——打印十六进制,%02x是打印2位十六进制。

在一个字节内部是从低位向高位使用的,所以先使用低位存数字。

作为一个指针,什么类型的指针,就访问多少空间。

下面代码的结果是:( )

//这个联合体的大小必须是4的倍数,14不是,则浪费2个字节为16

在X86下,小端字节序存储,有下列程序,输出结果是( )

因为联合体的成员共用同一块空间,即k和i共用同一块空间,k和i各占2个字节一样大。所以结构体对象a的空间是k的也可以是i的。s是联合体指针

0x39表示:十六进制的39;

0x38表示:十六进制的38。

当要把内存中的数据打印出来时,打印结构体对象a中的k成员,此时k变成一个短整型了,放的就是一个数字。当把它拿出来时就涉及了大小端字节序的问题。对于小端存储来讲,低字节内容放在低地址处,高字节内容放在高地址处。因为39作为它的低字节内容,放在低地址处,38作为高字节内容放在高地址处,即是0x38 39。(表示成十六进制)

放进去的数字是38 39,打印出的是39 38。

这里共用体,给i中放数据时把k也改了。

输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。

第一行包含两个正整数n, m,用空格分隔。n表示第二行第一个升序序列中数字的个数,m表示第三行第二个升序序列中数字的个数。

第二行包含n个整数,用空格分隔。

第三行包含m个整数,用空格分隔。

输出为一行,输出长度为n+m的升序序列,即长度为n的升序序列和长度为m的升序序列中的元素重新进行升序序列排列合并。

创建1个数组crr,1和2

1和2相比,1小,放在crr中;3和2相比,2小,2放进crr中;3和4相比,3小,3放进crr中;5和4相比,4小,则4放进crr中,5和6相比,5小,5被放入crr中;6和7相比,6小,6被放入crr中;6找完后brr数组已经找完了,此时把arr数组中剩下的元素直接放进去就可以了。

优化思路:可以不把合并起来的数字单独创建一个数组存起来,只要把它打印出来就可以了。

变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461),(14和61),(146和1),如果所有拆分后的乘积之和等于自身,则是一个Lily Number。

一行,5位数中的所有 Lily Number,每两个数之间间隔一个空格。

//需要产生10、100、1000、10000这样的4个数字(因为是5位数)

注意:pow()函数的返回值是double类型的,而%操作符的左右两边都必须是整数,所以需要对pow()函数的返回值进行强转。

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

如果一组数字中只有一个数字出现一次如5只出现一次(一个单身狗)
把所有数字异或在一起,1和1异或是0,2和2异或是0,3和3异或是0,4和4异或是0,0和5异或结果是5,此时可以找到。
但是如果是两个数字出现一次(两个单身狗)
把所有数字异或在一起,得到的结果就是5和6异或的结果,不能提出来5和6,就不能找到。
则:对数字进行分组,一定把5和6分在不同的组中。

1. 只出现1次的数字,分别到2个组中,一个组中有1个;
2. 每个组都满足,只有1个数字出现一次,其他数字是成对出现的。

在不知道数字是什么的情况下把两个单身狗找出来,分到不同的组中——把所有数字进行异或,这组数字异或的结果是5和6异或的结果,5:101;6:110;5^6 = 011是3,因为这两个数字不相同,所以这两个数字对应的二进制位肯定有不同位,异或的特点是相异为1,则看5异或6的结果这个数字哪一位为1,如果发现的二进制序列的最低位是1(只用找1个就可以),则所有数字中二进制序列中最低位为1的放一组,二进制序列中最低位为0的放一组,此时5和6必然放在不同的组中。这样的两个组再各自异或在一起。

假设发现5和6异或的结果倒数第二位为1,则就把倒数第二位为1的放在一组中,为0的放一组中,则这次分组结果就是:
二进制序列倒数第二位为0的: 
二进制序列倒数第二位为1的:

//——不相同的数字异或的结果肯定是非0,非0则二进制序列中肯定有1,通过这个位,这一位上的两个数字不相同就可以把5和6放在不同的组中 //计算ret的二进制中第几个位是1: //按照第pos位为1或0来分组: n^= arr[i];//不创建数组,异或的结果就是那个单身狗 //——不相同的数字异或的结果肯定是非0,非0则二进制序列中肯定有1,通过这个位,这一位上的两个数字不相同就可以把5和6放在不同的组中 //计算ret的二进制中第几个位是1: //按照第pos位为1或0来分组: n^= arr[i];//不创建数组,异或的结果就是那个单身狗 //因为ret已经是5和6异或的结果了

int (**p)[10] )(int *)中指针指向的数组有10个元素,每个元素都是函数指针,即数组是存放函数指针的数组。函数指针存放的数组的参数是int*,返回类型是int。

对数组名取地址取出的是数组的地址,数组的地址应该放到数组指针中,注意不应该放到整型指针等其他不匹配的指针中。

1、求100之内自然数中最大的能被17整除的数。

2、已知a,b,c都是1位整数,求当三位整数abc、cba的和为1333时a、b、c的值。

3、计算并输出200-400之间不能被3整除的整数的和。

4、从键盘输入10个数,统计非负数的个数,并计算非负数的和

5、求100之内自然数中偶数之和。

6、输入5个数,求和并输出。要求编写求和的函数。

8、编写程序,将用户输入的字符串中所有的字符a用*代替,然后输出。

9、编写程序,将一个一维数组的元素逆序存放并输出。例如,原顺序为1,2,3,4,5,逆序后为5,4,3,2,1。

11、编程判断输入的整数的正负性和奇偶性。如果为正数,输出z;如果为负数,输出f;如果为偶数,输出o;如果为奇数,输出j

12、计算并输出1-200之间不能被5整除的整数的和。

14、输入5个数,求它们中最大值和平均值并输出。

15、输出所有200-400之间能被3整除且个位数字为6的整数

16、编写程序,将用户输入的字符串中所有的字符a去掉,然后输出剩余的字符。

17、计算并输出200-400之间不能被7整除的整数的和。

18.计算并输出200-400之间不能被5整除的整数的和

19、从键盘输入10个数,统计非正数的个数,并计算非正数的和

20、输入一串字符,将其中的大写字母变成对应的小写字母并输出。

21、打印所有的水仙花数。所谓水仙花数是指一个三位数,其各位数字的立方和等于该数。例如,153就是一个水仙花数,因为153=1*1*1+5*5*5+3*3*3。

22、一个皮球从100米高度自由落下,每次落地后反弹回原高度的一半,再落下,再反弹。求当它第10次落地时,共经过了多少米,第10次反弹多高?

23、输出所有0-200之间能被3整除且个位数字为6的整数。

24、输入一个正整数,输出它的阶乘。

25、编写程序,判断从键盘输入的字符中数字字符的个数、大写字母的个数、小写字母的个数及其它字符的个数,以*作为字符输入结束标志。

26、编写程序,使用循环结构输出下列图形:

27、输入一串字符,逆序输出。要求使用数组实现。

30、求两个正整数的最大公约数。

31、求100之内自然数中奇数之和。

32、输出所有200-400之间能被3整除且个位数字为7的整数。

【问题描述】Armstrong数具有如下特征:一个n位数等于其个位数的n次方之和。如:
【思路】看到此题我第一反应是用枚举法,给定m(10<=m<=99999),首先判断m的位数n,然后判断它是否等于各位数的n次方之和。

  • 定义函数int judgeEqual(int m,int n),其中m为给定的数,n为m的位数,用于判断m是否等于各位数的n次方之和。

【思路】1~9组成的最小三位数是123,最大的是987,由于要满足1:2:3的关系,最小的那个数应该不到于987/3=329。这样的话第一个数的变化范围是123~329,将这里面的数分别乘2、乘3,然后判断这三个数是否符合要求,即这三个数是否由1~9组成,而且各个数字不能相同。

  • 定义函数int judge(int n),用于判断整数n的各位数字是否相同,如果有想同的就返回0;否则返回1;
本来是想写个《C语言经典题目系列》,本系列包括一些经典算法题目,但由于时间问题,现在只是收集了不多题目且只做了一部分,就先发上来了。写此目的帮助一些学c语言的人入门及运用一些算法,由于水平有限错误在所难免及本来这些题目不是很难高手就不用看了,其中错误欢迎大家指正。
【问题描述】梯有N阶,上楼可以一步上一阶,也可以一步上二阶。编写一个程序,计算共有多少中不同的走法
【思路】看到此题目容易想到用递归的方法来做,因为递归是一种描述和解决结构自相似问题的基本算法,而N阶楼梯问题和N-1阶、N-2阶的结构完全相同。
     解决递归问题可以分为两个部分,第一部分是一些特殊(基础)情况,用直接法解,即始基;第二部分与原问题相似,可用类似的方法解决(即递归),但比原问题的规模要小。
  • N阶楼梯问题的始基是N==1、N==2两种情况;
  • 上楼可以一步上一阶,也可以一步上二阶,当上一阶时问题规模变为N-1,当上二阶时问题规模变为N-2,所以总的情况为count(n-1)+count(n-2)。

某寺庙里7个和尚:轮流挑水,为了和其他任务不能冲突,各人将有空天数列出如下表:
和尚1: 星期二,四;
和尚2: 星期一,六;
和尚3: 星期三,日;
和尚5: 星期一,四,六;
和尚6: 星期二,五;
和尚7: 星期三,六,日;
请将所有合理的挑水时间安排表
【思路】用回朔法求解(递归方式实现,当然也可以用迭代方式)。用结构体存储和尚的信息(空闲时间、是否已经挑过水标记)回朔法即每进行一步,都试图在当前部分解的基础上扩大该部分解。扩大时,首先检查扩大后是否违反了约束条件,若不违反,则扩大之,然后继续在此基础上按照类似的方法进行,直至成为完整解;若违反,则放弃该步以及它所能生成的部分解,然后按照类似的方法尝试其他可能的扩大方式,直到尝试了所有的扩大方式。  

cCODE:来自一位网友,即用判断各位数字的积是否等于9!且各位数字的和是否等于45。)
【问题描述】编写一个c程序,利用如下的格里高利公式求п的值,直到最后一项的值小于10-6为止。
【思路】由公式可以看出,每次n的值都会改变,这实际上就是迭代。
在程序设计中,迭代是经常使用的一种算法。使用迭代算法时要注意三个问题:
  • 迭代的初始值,如本题中sum的初始值为1n的初始值为1
  • 迭代公式,这是迭代的关键,如果有几个迭代公式,要特别注意这些迭代的顺序。如i+=1sum+=n的次序不能交换。
  • 迭代终止条件。一般用一个表达式或者计数器来判断迭代式是否应该终止。
  • 【问题描述】编写一个c程序,把下列数组延长到第50项:
    【思路】由给定的数组元素可以看出偶数项是前一项的2倍,奇数项是前一项的2倍加1
    ,这是一中递推关系由前项推出后项,此题可以通过递推关系求解。
           递推解题和迭代解题是很相似的,递推是通过其他变量来演化,而迭代则是通过自身不断演化。递推法的运用也有三个关键:
    • 寻找递推关系。这是最重要的问题。递推关系有解析和非解析两种。解析递推关系是指能用一般数学公式描述的关系,也称递推公式。例如,本题的递推关系就是解析的。非解析递推关系是指不能用一般的数学公式描述的关系,这类关系的描述,也许本身就是一个过程。这类问题一般比较复杂,要结合其他的策略如分治法来解决。
    • 递推关系必须有始基,即最小子解(针对初始规模的子解的值),没有始基,递推计算就不能开始。例如本题a1=1就是始基。
    • 递推计算。即根据递推关系进行递推计算。递推计算可以由递归解析和非递归两种,递归计算是采用递归法,其形式是自顶向下,而非递归则是自底向上。本题是非递归的。
    解此题还须注意一点:数列的项必须定义为double型,因为延长到第50项如果定义为int or float型,数列的项会被截断即超过intfloat的表示范围。

    【问题描述】 用递归算法实现求一个数组中的最大元素。
    【思路】解决递归问题可以分为两个部分,第一部分是一些特殊(基础)情况,用直接法解,即始基;第二部分与原问题相似,可用类似的方法解决(即递归),但比原问题的规模要小。
         本题显然始基是a[0],关键是要找出递归关系,定义一个函数int max(int a[],int n),其中整型a[]是一个数组,n是数组长度减1,即数组最大有效元素的下标,因为c语言中数组元素下标是从0开始的。



    • 如果0==n,则a[0]就是最大的元素
    • 如果n>0,则先求出a[0]到a[n-1]的最大元素,然后与a[n]比较,较大者即为最大元素。其中a[0]到a[n-1]又可以用这种方式求,此时需要将a[0],a[1]...a[n-1]看成一个由n-1个元素构成的一维数组。
    • 【问题描述】自然数的拆分:任何一个大于1的自然数N,总可以拆分成若干个自然数之和,并且有多种拆分方法。例如自然数5,可以有如下一些拆分方法:

      自然数的拆分可以用回溯法。
      知识点回溯法解题时,对任一解的生产,一般采用逐步扩大解的方式。每进行一步,都试图在当前部分解的基础上扩大该部分解。扩大时,首先检查扩大后是否违反了约束条件,若不违反,则扩大之,然后继续在此基础上按照类似的方法进行,直至为完全解;若违反,则放弃该步以及它生成的部分解,然后按照类似的方法尝试其他可能的扩大方式,直到已经尝试了所有的扩大方式。
      回溯法解题通常包含以下三个步骤:
      • 针对所给问题,定义问题的解空间;如本题对5的拆分来说,1<=拆分的数<=5
      • 确定易于搜索的解空间结构;如本题对5的拆分来说,用x[]数组来存储解,每个数组元素的取值范围都是1<=拆分的数<=5,从1开始搜索直到5
      • 搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。如本题对5的拆分来说,为了避免重复,x>=x[j](i>j),如x[]={2,3}满足条件而x[]={3,2}就不满足条件不是可行解即无效。
      回溯法通常有两种实现方式,一种是递归的方式,另一种是迭代的方式。在此就用递归方式,当然迭代的方式也可以。  
/*用于标记和尚周内是否已经工作过,flag=0表示没挑过水,flag=1表示已经挑过水*/

我要回帖

更多关于 c语言基础题目 的文章

 

随机推荐