day1~day8
选择题
选择题1
描述
以下不正确的定义语句是( )
`A: double x[5] = {2.0, 4.0, 6.0, 8.0, 10.0};
B: char c2[] = {'\x10', '\xa', '\8'};
C: char c1[] = {'1','2','3','4','5'};
D: int y[5+3]={0, 1, 3, 5, 7, 9};`
解析:
我在vs2013中测试,选项B的定义是可以编译运行的,此时编译器会将'\8'当成'8',但原题显然不是这个意思。在c语言的定义中,\ddd表示一个八进制的数字,而d的范围是0~7,因此'\8'错误。
正确答案:
B
选择题2
描述
test.c 文件中包括如下语句,文件中定义的四个变量中,是指针类型的变量为【多选】( )
#define INT_PTR int*
typedef int* int_ptr;
INT_PTR a, b;
int_ptr c, d;
A: a B: b C: c D: d
解析:
因为#define是宏定义,仅仅是直接替换,INT_PTR a, b; 进行宏替换后代码是这样的:int *a, b;这里的int *是a的类型,b的 类型是int,故此次b只是int类型。而typedef是把该类型定义一个别名,别名是一个独立的类型了,使用这个类型创建的变
量都是这个类型的。
正确答案:
ACD
选择题3
描述
对于下面的说法,正确的是( )
`A: 对于 struct X{short s;int i;char c;},sizeof(X)等于sizeof(s) + sizeof(i) + sizeof(c)
B: 对于某个double变量 a,可以使用 a == 0.0 来判断其是否为零
C: 初始化方式 char a[14] = "Hello, world!"; 和char a[14]; a = "Hello, world!";的效果相同
D: 以上说法都不对`
解析:
A选项,没有考虑内存对齐。B选项,考察double类型的比较,由于浮点数存在误差,不能直接判断两个数是否相等,通常 采用比较两数之差的绝对值是否小于一个很小的数字(具体的可自己设定这样一个数,作为误差)来确定是否等。C选项,a为数组首地址是一个指针常量不能改变。
浮点点数在一般情况下确实不能直接比较,如下
int main()
{
double b = 5.41;
double a = 5.31 + 0.1;
if (a==b)
printf("YES");
else
{
printf("NO");
printf("%.20lf\n", a);
printf("%.20lf\n", b);
}
return 0;
}
结果输出NO,因为5.41,5.31和0.1在编译器中都不是精确存储的,存在误差。
但有些浮点数是可以精确存储,如下
int main()
{
double c = 5.25;
double d = 5.125 + 0.125;
if (c == d)
printf("YES\n");
else
{
printf("%.20lf\n", c);
printf("%.20lf\n", d);
}
return 0;
}
结果输出YES
正确答案:
D
选择题4
对于代码段,下面描述正确的是( )
t=0;
while(printf("*"))
{
t++;
if (t<3)
break;
}
A: 其中循环控制表达式与0等价 B: 其中循环控制表达式与'0'等价
C: 其中循环控制表达式是不合法的 D: 以上说法都不对
答案
B
选择题5
5、我们知道C语言的 break 语句只能跳出离它最近的一层循环,可是有时候我们需要跳出多层循环,下列跳出多层循环的做法正确的是【多选】( )
A: 将程序写成函数用return结束函数,便可跳出循环
B: 修改外层循环条件例如
for( int i = 0 ; i < MAX1 ; i ++ )
{
for( int j = 0 ; j < MAX2 ; j ++ )
{
if( condition )
{
i = MAX1;
break;
}
}
}
C: 在外层循环设置判断条件例如
for( ; symbol != 1 && condition2 ; )
{
for( ; symbol != 1 && condition3 ; )
{
if( condition1 )
symbol = 1 ;
}
}
D: 在外层循环后面加入break例如
for( ; condition2 ; )
{
for( ; condition3 ; )
{
if( condition1 )
symbol = 1 ;
}
if(symbol == 1 )
break ;
}
答案
ABCD
选择题6
在c语言中,一个函数不写返回值类型,默认的返回类型是( )
A: int B: char C: void D: 都不是
答案
A
选择题7
已知 i,j 都是整型变量,下列表达式中,与下标引用 X[i][j] 不等效的是【多选】( )
A: *(X[i]+j) B: *(X+i)[j] C: *(X+i+j) D: *(*(X+i)+j)
解析
(本题应注意B选项)本题考查的是二维数组的元素访问,A选项是 正确的,X[i]就是第i行的数组名,数组名表示首元素的地址,X[i]表示第i行的第一个元素的地址,+j后就是第i行下标为j的元素的地址,整体解引用就是X[i][j],A正确。B选项因为[]的优先级高于*,所以代码相当于**((x+i)+j),X+i+j后就越界了,并不代表X[i][j],所以错误。C选项也明显不对,X是二维数组的数组名,数组名相当于第一行的地址,X+i+j,跳过了i+j行,就越界了,C错误。D选项是标准的指针形式访问二位数组的一个元素。
答案
BC
编程题
编程题1
尼科彻斯定理_牛客题霸_牛客网 (nowcoder.com)
描述
验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。
例如:
1^3=1
2^3=3+5
3^3=7+9+11
4^3=13+15+17+19
输入一个正整数m(m≤100),将m的立方写成m个连续奇数之和的形式输出。
数据范围:1≤m≤100
进阶:时间复杂度:O(m) ,空间复杂度:O(1)
输入描述:
输入一个int整数
输出描述:
输出分解后的string
解析
等差数列求和公式 Sn=n(a1+an)/2 m * (m - 1) / 2
等差数列第n项公式 an=a1+(n-1)d 1 + ((m * (m - 1) / 2) + 1 - 1) * 2
最终得到m的立方的表达式起始奇数: m * (m - 1) + 1
答案
#include <stdio.h>
int main()
{
int m;
while(~scanf("%d", &m)){
int start = m * (m - 1) + 1;//找到对应m^3的起始奇数
char buf[10240] = {0};
//sprintf(buf, format, ...) 与printf用法类似,格式化字符串但是不用于打印而是放到一个buf中
sprintf(buf, "%d", start);//先将起始奇数转换成为字符串存入buf中
for (int i = 1; i < m; i++) {
//然后将紧随随后的m-1个奇数数字转换为字符串,按照指定格式放入buf中
//%s+%d, 要求先有一个字符串,然后是+符号,然后是个数字的格式,对应是buf原先的数据,和奇数
sprintf(buf, "%s+%d", buf, start+=2);
}
printf("%s\n", buf);
} r
eturn 0;
}
编程题2
旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com)
描述
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤n≤10000,数组中任意元素的值: 0≤val≤10000
要求:空间复杂度:O(1) ,时间复杂度:O(logn)
示例1
输入:
[3,4,5,1,2]
复制
返回值:
1
复制
示例2
输入:
[3,100,200,3]
复制
返回值:
3
解析
暴力破解:遍历数组找出最小值即可
更优思想:采用二分查找,这个题主要分析三种旋转情况 [1, 2, 3, 4, 5],使用中间值与右端进行比较。
中间大于右边 [3, 4, 5, 1, 2],这种情况下,最小数一定在右边;则left = middle + 1
中间等于右边 [1, 0, 1, 1, 1], 这个是[0, 1, 1, 1, 1] 旋转过来的,这时候需要缩小范围 right--;,注意不能是
left++,因为是非降序数组,所以要缩小右边范围,把较小值向右推,符合我们的判断规则。
中间小于右边 [5, 1, 2, 3, 4], 这种情况下,最小数字则在左半边;则right = middle
答案
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen ) {
// write code here
int left,right,mid;
left=0,right=rotateArrayLen-1;
while(left<=right)
{
mid=(left+right)/2;
if(left==right)
return rotateArray[mid];
else if(rotateArray[mid]<rotateArray[right])
right=mid;
else if(rotateArray[mid]==rotateArray[right])
right--;
else
left=mid+1;
}
return -1;
}
编程题3
描述
集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例1
输入:nums = [1,2,2,4]
输出:[2,3]
示例 2
输入:nums = [1,1]
输出:[1,2]
解析
使用标记的方式就可以找出重复的数字,数组中出现过哪个数字就把对应数字作为下标在对应位置1,表示已经标记出现过,如果哪个数据对应位已经置1,则表示就是重复的数字。有了重复的数字,拿 [1, n] 的总和减去去掉重复数据的数组总和就是丢失的数据。 其实使用标记法时出现的数字对应位每次 ++ ,则最后出现0次的就是丢失,出现2次的就是重复的,这样的方式也可以,不过需要多次遍历。
答案
int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
int* ret=(int*)malloc(sizeof(int)*2);
int repeat,sum1=0,sum2=0;
int* flag=(int*)calloc(numsSize+1,sizeof(int));//此处numsSize要加1,否则后面会越界
//遍历数组,将数字在flag中对应的下标的0赋为1,找到重复的数字
for(int i=0;i<numsSize;i++)
{
flag[nums[i]]++;
if(flag[nums[i]]==2)
{
repeat=nums[i];
}
sum1+=i+1;
sum2+=nums[i];
}
ret[0]=repeat;
ret[1]=repeat+(sum1-sum2);
free(flag);
*returnSize=2;
return ret;
}
编程题4
面试题 05.06. 整数转换 - 力扣(Leetcode)
描述
整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。
示例1:
输入:A = 29 (或者0b11101), B = 15(或者0b01111)
输出:2
示例2:
输入:A = 1,B = 2
输出:2
A,B范围在[-2147483648, 2147483647]之间
答案
int get_bin_count(int num) {
int count = 0;
for (int i = 0; i < 32; i++) {
if ((num>>i) & 1)
count++;
}
return count;
}
int convertInteger(int A, int B){
return get_bin_count(A^B);
}
注意:力扣规定了移位操作符不能改变符号位,因此若使用1向左移去判断,则有一位会漏掉即INT_MIN,但可以通过使用unsigned int型去移位解决,unsigned int型没有符号位。也可以使用n&(n-1)去计算count,但这样也会有一个问题,力扣规定了INT_MIN不能减一,因此当n为INT_MIN时程序会报错,但可以通过将n转换为unsigned int解决,但同样要注意,当unsigned int型的数为0时不能减一。经过测试,这些问题在vs2013上都不存在。
编程题5
747. 至少是其他数字两倍的最大数 - 力扣(Leetcode)
描述
给你一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。
请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。
示例 1
输入:nums = [3,6,1,0]
输出:1
解释:6 是最大的整数,对于数组中的其他整数,6 至少是数组中其他元素的两倍。6 的下标是 1 ,所以返回 1 。
示例 2
输入:nums = [1,2,3,4]
输出:-1
解释:4 没有超过 3 的两倍大,所以返回 -1 。
示例 3
输入:nums = [1]
输出:0
解释:因为不存在其他数字,所以认为现有数字 1 至少是其他数字的两倍
解析
暴力破解:双重循环遍历数组,对每个元素判断是否是其他元素的两倍。或者先遍历一遍找出最大值,然后遍历一 遍判断是否是其他数字二倍。
更优思想:一次遍历找出最大的数字和次大的数字,判断最大的数字是否是次大数字2倍即可。
答案
int dominantIndex(int* nums, int numsSize)
{
if (numsSize == 1) return 0;//特殊情况只有一个元素则特殊处理
int max, sec, idx;
//先对最大和次大进行选择赋值,注意max和sec不能随意赋初值,因为有可能你赋予的初值就是最大值
//因此要使用数组中的数据进行初值赋予。
if (nums[0] > nums[1])
{
max = nums[0];
idx = 0;
sec = nums[1];
}
else
{
max = nums[1];
idx = 1;
sec = nums[0];
}
for(int i = 2; i < numsSize; i++)
{
if (nums[i] > max)
{ //当前元素大于max,则意味着要替换
sec = max; //先将原先最大的保存到sec中,则他就是次大的
max = nums[i]; //再将最大的放到max中
idx = i; //保存max值的下标
}
else if (nums[i] > sec)
{
//避免刚好nums[0]就是最大的情况,因为不切换最大而导致次大无法判断情况
sec = nums[i];
}
}
if(max >= sec * 2)
{
return idx;
}
return - 1;
}
编程题6
747. 至少是其他数字两倍的最大数 - 力扣(Leetcode)
描述
给你一个整数数组 nums ,其中总是存在唯一的 一个最大整数 。
请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回最大元素的下标 ,否则返回 -1 。
示例 1
输入:nums = [3,6,1,0]
输出:1
解释:6 是最大的整数,对于数组中的其他整数,6 至少是数组中其他元素的两倍。6 的下标是 1 ,所以返回 1 。
示例 2
输入:nums = [1,2,3,4]
输出:-1
解释:4 没有超过 3 的两倍大,所以返回 -1 。
示例 3
输入:nums = [1]
输出:0
解释:因为不存在其他数字,所以认为现有数字 1 至少是其他数字的两倍。
解析
一个数组中有一个数字出现次数大于 n/2 ,从第 0 个字符开始,假设它就是最多的那个数字,遇到相同的数字则计数 +1 , 遇到不同的则计数 -1 ,其实就是互相消耗,等到计数为 0 的时候,表示本次互拼完毕,从下一个字符重新开始互拼,但是归根结底出现次数大于 n/2 的这个数字数量更多,因此也是最后保留的字符。
答案
int majorityElement(int* nums, int numsSize){
int count = 1;
int tmp = nums[0];
for (int i = 1; i < numsSize; i++){
if (tmp == nums[i]){//与保存的字符相同则计数+1
count++;
} else {//与保存的字符不同则计数-1
count--;
//计数为0表示有可能保存的字符不是最多的字符,换下一个
if (count == 0) tmp = nums[i + 1];
}
}
return tmp;
}