文章目录
🌕 前言:关于C刷题
🤙关于C的学习出了看视频以外,那就是刷题了,朋友们,你们有没有过这样的感觉,在网上看了视频过后感觉自己什么都听懂了,但就是写题和做项目时无从下手,或者就是因为某个细节一直错一直改,那背后的原因是什么呢?四个字——题刷少了,这里新一建议去
Leetcode
看看,那里的题库资源很丰富,并且在全球都有广泛涉猎。不仅如此,这里还有 课程 + 刷题 + 面经 + 求职 + 讨论区分享解题思路,用过的人都说好😜
👉除此之外,我的建议是初学者从简单题
开始练习,因为简单题是一切题的基础,一切的困难题都是从简单题衍生而来的,每天刷那么2~3题,后期再慢慢刷中等题,困难题,经过一段时间后会有很不错的提升
此外,在我们有一定的提升之后,我们便可以去刷剑指offer
了,在这里预祝各位大学生以及初学者都拿到自己满意的offer!💖
第一题:旋转数组的最小数字
👇👇👇
做题链接戳这里:JZ11.旋转数组的最小数字
🍂 题目描述
有一个长度为 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)
🍂示例
输入:[3,4,5,1,2]
返回值:1
示例2
输入:[3,100,200,3]
返回值:3
🍃题解
这道题有点清奇,首先它是部分有序数组,而且要求时间复杂度O(log n),且空间复杂度为O(1),意思说我们不能直接遍历数组找最小值,那该怎么办呢?我们查找有序数组最高效的方法是什么?——那当然是我们的二分查找,但是这和普通的二分查找又有所区别,我们需要找到它的规律:我们拿mid值与右值进行比较:
- 中间大于右边 [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 = 0;
int right = rotateArrayLen - 1;
int mid = 0;
while (left < right){
mid = left + (right - left) / 2;
if (rotateArray[mid] > rotateArray[right]) {
left = mid + 1;
}
else if (rotateArray[mid] == rotateArray[right]) {
right--;
}
else {
right = mid;
}
}
return rotateArray[left];
}
第二题:错误的集合
👇👇👇
做题链接戳这里:645.错误的集合
🍂 题目描述
集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
🍂示例
输入:nums = [1,2,2,4]
输出:[2,3]
示例2
输入:nums = [1,1]
输出:[1,2]
🍂提示
● 2 <= nums.length <= 104
● 1 <= nums[i] <= 104
🍃题解
我们如果只需要找到缺失的数字,那不就很简单了,我们根据题设可以直接用1-n的数字减去整个数组即可,但这道题怪就怪在它为什么要放一个重复数字在其中,那样我们的刚开始的设想也不能实现了,那么到底该怎么办呢?我们想题设为什么要只放1-n的数字,不随便放数字,题目的突破点就在于此,问题在于:1-n的数字可以当做我们的下标,从而就找到了题解,我们可以自己定义一个全为0的数组,然后将目标数组作为下标,即可排除我们的重复数字
int* findErrorNums(int* nums, int numsSize, int* returnSize) {
*returnSize = 2;
int* ret = (int*)calloc(numsSize + 1, sizeof(int));
int* answer = (int*)calloc(2, sizeof(int));
int old_size = 0, new_size = 0;
for (int i = 0; i < numsSize; i++)
{
if (ret[nums[i]] == 1)
{
answer[0] = nums[i];
}
ret[nums[i]] = 1;
old_size += nums[i];
new_size += i + 1;
}
answer[1] = new_size - (old_size - answer[0]);
return answer;
}
第三题:密码检查
👇👇👇
做题链接戳这里:OR141.密码检查
🍂 题目描述
小明同学最近开发了一个网站,在用户注册账户的时候,需要设置账户的密码,为了加强账户的安全性,小明对密码强度有一定要求:
-
密码只能由大写字母,小写字母,数字构成;
-
密码不能以数字开头;
-
密码中至少出现大写字母,小写字母和数字这三种字符类型中的两种;
-
密码长度至少为8
现在小明受到了n个密码,他想请你写程序判断这些密码中哪些是合适的,哪些是不合法的。
输入描述:
输入一个数n,接下来有n(n≤100)行,每行一个字符串,表示一个密码,输入保证字符串中只出现大写字母,小写字母和数字,字符串长度不超过100。
输出描述:
输入n行,如果密码合法,输出YES,不合法输出NO
🍂示例
输入:1
CdKfIfsiBgohWsydFYlMVRrGUpMALbmygeXdNpTmWkfyiZIKPtiflcgppuR
输出:YES
🍃题解
这里我们就需要注意了,我们需要用字符数组来存储字符串,然后1-3条很简单直接判断即可,第四条我们需要遍历我们的字符串,用四个变量将每种元素的值存储下来,然后最后一步比较即可
#include <string.h>
int main()
{
int n = 0;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
{
char password[100] = { 0 };
int upper = 0, lower = 0, digit = 0, other = 0;
scanf("%s", password);
if (strlen(password) < 8)
{
printf("NO\n");
continue;
}
if (password[0] >= '0' && password[0] <= '9')
{
printf("NO\n");
continue;
}
char* ptr = password;
while (*ptr != '\0')
{
if (*ptr >= 'a' && *ptr <= 'z')
{
lower++;
}
else if (*ptr >= 'A' && *ptr <= 'Z')
{
upper++;
}
else if (*ptr >= '0' && *ptr <= '9')
{
digit++;
}
else other++;
ptr++;
}
if (other > 0)
{
printf("NO\n");
}
if ((upper > 0) + (lower > 0) + (digit > 0) < 2)
{
printf("NO\n");
continue;
}
printf("YES\n");
}
}
return 0;
}
🚀今日份客观题
🍂 ONE.题目描述
有如下定义语句,则正确的输入语句是【多选】( )
int b;
char c[10];
A: scanf(“%d%s”,&b,&c); B: scanf(“%d%s”,&b,c);
C: scanf(“%d%s”,b,c); D: scanf(“%d%s”,b,&c);
🍃题解
正确答案:AB
&c
和c
两个地址值是一样的,程序的效果相同,也没错,但同时也必须把变量b的地址给scanf,故CD错误,AB正确。
本题易错点在于漏选C,因此要牢记&c 跟 c是一样的。
🍂 TWO.题目描述
对于下面的说法,正确的是( )
A: 对于 struct X{short s;int i;char c;},sizeof(X)等于sizeof(s) + sizeof(i) + sizeof©
B: 对于某个double变量 a,可以使用 a == 0.0 来判断其是否为零
C: 初始化方式 char a[14] = “Hello, world!”; 和char a[14]; a = “Hello, world!”;的效果相同
D: 以上说法都不正确
🍃题解
A选项,没有考虑内存对齐。B选项,考察double类型的比较,由于浮点数存在误差,不能直接判断两个数是否相等,通常采 用比较两数之差的绝对值是否小于一个很小的数字(具体的可自己设定这样一个数,作为误差)来确定是否相等。C选项,a 为数组首地址是常量不能改变,所以A,B,C都是错的,选择D
本题易错在于错选B,没考虑浮点数在内存中的存储有差异
🍂 THREE.题目描述
以下程序的输出结果为( )
#include <stdio.h>
int i;
void prt()
{
for (i = 5; i < 8; i++)
printf("%c", '*');
printf("\t");
}
int main()
{
for (i = 5; i <= 8; i++)
prt();
return 0;
}
A: *** B: *** *** *** *** C: *** *** D: * * *
🍃题解
答案解析: 正确答案:A 全局变量i,在main()中修改为5,第一次在prt()中执行循环输出三次’*',i被修改为8,回到main()中第二次调用prt() 时,i<8为假,循环结束没输出,执行一次print(“\t”),再次回到主函数后i++变为9,i<=8为假,循环结束;
本题易错在于错选B,没考虑 i 是个全局变量
🍂 FOUR.题目描述
int main() {
int a=3;
printf(“%d\n”,(a+=a-=a*a)); return 0;
}
A: -6 B: 12 C: 0 D: -12
🍃题解
答案解析: 正确答案:C 给定条件表达式(M)?(a++):(a–)。 (表达式1)? (表达式2): (表达式3)为三目运算符。 计算规则为:先判断表达式1是否为真,若为真,则计算表达式2,并将表达式2的结果作为整个表达式最终的结果,表达式3 不计算;否则,表达式3的结果为最终结果,表达式2不计算。 在此表达式中,若M=0,为假,计算a–; 若M≠0,为真,计 算a++; 若要求与M等价,则要满足M取0时为假,取非0数值时为真。 c选项中:假定M取0,则M表示假,当M是0时,表达式 M!=0不成立,为假,计算a–; 当M取非0数值时,M为真,表达式M!=0成立,为真,计算a++; 符合题意,选C
本题易错在于错选B,首先a* a = 9 ,a = a - 9; a = -6;最后 a = a + -6 = -12;
🍂 FIVE.题目描述
1、设变量已正确定义,以下不能统计出一行中输入字符个数(不包含回车符)的程序段是( )
A: n=0;while(ch=getchar()!=‘\n’)n++;
B: n=0;while(getchar()!=‘\n’)n++;
C: for(n=0;getchar()!=‘\n’;n++);
D: n=0;for(ch=getchar();ch!=‘\n’;n++);
🍃题解
答案解析: 正确答案:D 对于for循环,其中第一项初始化表达式只执行一次,因此ch只从输入流中取一个字符,之后就再不会取字符,因此会死循环