c语言 寒假刷题笔记1~8天(上)

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

  1. 对于代码段,下面描述正确的是( )

    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],使用中间值与右端进行比较。

  1. 中间大于右边 [3, 4, 5, 1, 2],这种情况下,最小数一定在右边;则left = middle + 1

  1. 中间等于右边 [1, 0, 1, 1, 1], 这个是[0, 1, 1, 1, 1] 旋转过来的,这时候需要缩小范围 right--;,注意不能是

left++,因为是非降序数组,所以要缩小右边范围,把较小值向右推,符合我们的判断规则。

  1. 中间小于右边 [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

645. 错误的集合 - 力扣(Leetcode)

描述

集合 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;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值