科软机试日常 - leetcode注意事项与C语言技巧


一、科软机试注意事项

  • 待完成的注释处写代码完成函数,main函数中的printf用于测试
  • 函数中不要加注释,否则会随机报错,你找半天都找不出哪里出错
  • 好好检查for循环和递归,死循环死递归直接卡2分钟把你心态搞崩
  • oi赛制,按照测试用例给分,一道题5个测试用例,一个用例5分,考试时不会告诉你提交的代码通过几个用例,只能自己调试
  • 只要时间复杂度不是太过分(指数级别),则一般能拿全分
  • 能不能加头文件,不好说,有人说能有人说不能,个人觉得只要在线编译能通过就能用

二、leetcode注意事项

1. returnSize和returnColumnSize

  • 如果返回值是一个一维数组的话,必定出现returnSize,它是一个int类型的指针,其指向的地址单元保存了数组中元素个数,*returnSize = 2表示返回值数组中元素的个数为2
  • 如果返回值是一个二维数组的话,就必定同时出现returnSize和returnColumnSizes,returnSize是一个一级指针,其指向的地址保存的内容是二维数组的行数,returnColumnSizes是一个一维指针数组,保存返回值中各行的一维数组中元素个数
  • returnColumnSize不能用memset赋值,而且用for循环赋值时(*returnColumnSizes)必须加括号
*returnSize = 3;	//二维数组行数为3
*returnColumnSizes = (int*)malloc(3*sizeof(int));	//需要3个单元来记录各行元素个数
(*returnColumnSizes)[0] = 2;	//二维数组第0行有2个元素
(*returnColumnSizes)[1] = 3;	//第1行有3个元素
(*returnColumnSizes)[2] = 4;	//第2行有4个元素

2. 其他注意事项

  • 一定要注意输入元素为NULL等情况,我经常在这里犯错
  • 链表最后一个节点的next指针置为NULL,否则会报错
  • 在循环中定义数组(静态),编译器不会重复创建这个数组,因此不用担心内存爆炸的问题
  • leetcode中返回的数组必须使用动态分配内存的数组,也就是必须要malloc
  • 在开始编码前要考虑到各种极端情况(如爆int),所以我默认都定义long long类型就不容易出错哈哈哈,或者习惯上把减法放在加法前面
  • 整数最大值为INT_MAX = 0x7FFFFFFF,最小值为INT_MIN = 0x80000000,学过计算机组成原理应该容易理解
  • 字符串一定要记得有’\0‘,反斜杠0
  • 全局变量必须在main函数中初始化,不要在外面初始化
  • 数组的拷贝:int* arr1 和arr2,拷贝arr2到arr1不是直接给arr1赋值(浅拷贝),而是将arr2的元素挨个赋值给arr1,或者用memcpy(arr1,arr2,sizeof(arr2)/sizeof(int))的方式
  • printf(“%d”,fmin(INT_MIN, INT_MAX));打印结果为0,因为fmim返回double类型

三、C语言小技巧

1. 数组初始化

将数组元素都置0

#include<string.h>
/*
注意别踩坑:
1.sizeof里面的数组只能是静态数组!!!
2.如果是用malloc分配内存的数组,malloc参数怎么写这里第三个参数就怎么写
3.稍不注意,直接buffer overflow
*/
int buf[255];
memset(buf, 0, sizeof(buf));//静态数组初始化

int* buf2 = (int*)malloc(255*sizeof(int));
memset(buf2,0,255*sizeof(int));//动态数组初始化	

坑2: memset是按照一个字节一个字节赋值的,赋值char类型的数据永远不会出错,但是如果赋值超过1个字节的数据则有可能出现读取错误,因此初始化非char类型数组时,只能赋值为0或-1


2. 功能强大的sprintf函数和sscanf函数

#include<stdio.h>
char str[200];
//sprintf和printf效果一样,只不过一个输出到控制台,一个输出到数组中
//结合两函数可以轻松实现进制转换与字符串与数字之间转换
//注意C语言没有二进制的格式化方法,转为2进制需要自己写了
sprintf(str,"%d",12345); //12345转为10进制字符串
sprintf(str,"%x",1234); //转16进制
sprintf(str,"%o",1234); //转8进制
sprintf(str,"%d",0b10000000);	//2进制转10进制

//sscanf函数和scanf效果一样,只不过一个是键盘读入数据一个是从字符串读入数据
int dest;
char* str= "123";

//sprintf是将第三个参数转换后送给第一个参数,sscanf参数是将第一个参数转换送送给第三个参数
//和scanf一样要加&,不然报错!!!
sscanf(str,"%d",&dest);

//二者区别就像printf和scanf的区别

感谢好友的补充:

  • 对于超出整型范围的字符串的字符串,sscanf会将该字符串转换为该整型类型的最大值或最小值

3. 快速排序库函数

  • 快速排序时间复杂度为 O ( n l o g 2 n ) O(nlog_2 n) O(nlog2n)
  • cmp比较函数需要自己写
#include<stdlib.h>

//cmp比较函数需要自己写!
/*
形参为void*的意思是能接收所有类型的数据
返回值将void*强制转换为(int*)然后*(int*)是指针指向的值
a - b是升序排序,b - a是降序排序
*/

/**
 *写成这样唯一不好的一点是:如果a-b的值超出int范围了
 *排序就会失败(改long long没用,qsort只接受返回值为
 *int类型的函数)
*/
int cmp(const void* a, const void* b){
    return *((int*)a) - *((int*)b);
}

//这样写就可以避免溢出问题,是一个完美的排序函数,降序只需要将大于号改成小于号
int cmp(const void* a,const void* b){
	return !(*(int*)a==*(int*)b) && *(int*)a > *(int*)b ? 1 : -1;
}

int arr[] = {-5,-3,6,0,0,-4,6,7,-9};
qsort(arr, len, sizeof(int), cmp);

#include <stdio.h>
#include<stdlib.h>

struct stu {
    int id;
    int score;
};

int cmp(struct stu* s1, struct stu* s2){
    if((*s1).score==(*s2).score){
        return (*s1).id-(*s2).id;
    }
    return (*s1).score - (*s2).score;
}

int main() {
    int n;
    struct stu* s;
    while (scanf("%d", &n) != EOF) {
        s = (struct stu*)malloc(n * sizeof(struct stu));
        int i, j;
        for (i = 0; i < n; i++)
            scanf("%d %d", &s[i].id, &s[i].score);
        qsort(s,n,sizeof(struct stu),cmp);
        for(i=0;i<n;i++){
            printf("%d %d\n",s[i].id,s[i].score);
        }
    }
    return 0;
}

4. 二分查找库函数

#include<stdio.h>
#include<stdlib.h> //bsearch函数是stdlib头文件中的函数

//和qsort的cmp一模一样
int cmp(const void* a, const void* b){
  return *(int*)a - *(int*)b;
}

/*
参数一:目标值的地址
参数二:数组首地址
参数三:要查找的长度
参数四:函数指针cmp
返回值:目标值的地址,用该地址减去数组首地址就是目标值的下标,若目标值不存在则返回NULL
注意:数组必须有序,刷力扣时尽量少用库函数,避免知其然而不知其所以然
*/
int main() {
  int nums[] = {123, 145, 512, 627, 800, 933,0};
  int key = 512;
  int len = 6;
  int* index = bsearch(&key,nums,len,sizeof(int),cmp);
  if(index)
    printf("%d\n",index-nums);
  return 0;
}
//自己写也很简单,不要太迷恋库函数
int search(int* nums, int numsSize, int target) {
	int left = 0, right = numsSize - 1;
	while(left<=right){
		int mid = (right-left)/2 + left;	//避免爆int
		if(nums[mid]==target)
			return mid;
		else if(nums[mid]>target)
			right = mid - 1;
		else
			left = mid + 1;
	}
	return -1;
}

5.哈希表

在leetcode中经常需要用到用到键值对索引的情况,但是C语言中并没有哈希表的数据结构,但是可以用数组下标来模拟

int hashTable[130];
memset(hashTable, 0, sizeof(hashTable);	//注意#include<string.h>
hashTable['A'] = 1;		//就像<'A', 1>键值对一样

6.栈

leetcode中dfs、括号匹配、中缀表达式转后缀表达式问题中经常需要使用到栈,但是C语言中没有栈这个数据结构,但是我们可以用数组来模拟

int stack[10005];	//容量尽可能定义大一点
int top = 0;		//栈顶元素
stack[top++] = 2;	//将2压入栈
int tmp = stack[--top];//弹栈

7.队列

leetcode中bfs等题目中需要用到队列,C语言中也没有队列这个数据结构,和栈一样,我们仍然可以用数组来模拟

int queue[10005];
int front = 0, rear = 0;
queue[rear++] = 2;	//入队
int tmp = queue[front++];//出队

8.其他

8.1 判断字符是否是数字

#include<ctype.h>
int isdigit(int c);	//如果c是数字,则返回非0整数,否则返回0

//记不住直接这样写
if(ch>='0'&&ch<='9')

8.2 整型最大值

注意:int范围和long范围一样,在机试中一定要用long long类型

#include<limits.h>
#include<stdio.h>
int M1 = INT_MAX;
int m1 = INT_MIN;	//其他类型同理
long long mm1 = LONG_LONG_MAX;

//也可以这么写,注意有的编译器可能会报错,报错的话把后面的H去掉
int M2 = 0x7fffffffH;
int m2 = 0x80000000H;

int main(){
	printf("%d\n",M1);
	printf("%d\n",m1);
	printf("%ld\n",LONG_MAX);
	printf("%lld\n",mm1);
	return 0;
}

在这里插入图片描述


四、力扣常见报错

错误提示1
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6160000002d8 at pc 0x556c2692357e bp 0x7ffca71fc0d0 sp 0x7ffca71fc0c0
调试:科软机试只能用printf查看自己程序哪里错了,所以要多写printf,可以很快找到自己的程序哪里出错了
错误原因:使用了未分配的空间,数组越界。

  • 数组定义的空间不够大,导致越界,我还使用了sizeof(arr)导致错上加错,要注意sizeof()只能求静态数组的空间大小,malloc分配内存的数组sizeof()统一会返回8。
  • memset函数报错,memset(arr,0 ,sizeof(arr);,如果arr是静态数组就可以这么初始化,如果这个arr是malloc动态分配内存的数组,sizeof默认返回8,所以就报数组越界错了,第三个参数最好是前面malloc里面怎么写这个就怎么写
  • int* ans = (int*)malloc(len1*sizeof(char));sizeof里面int误写成char

错误提示2
Line 25: Char 39: runtime error: store to address 0x62e00059e040 with insufficient space for an object of type 'struct TreeNode *' [solution.c]
错误原因:给数组分配的内存空间不够

  • (struct TreeNode**)malloc(10000*sizeof(int));把sizeof(struct TreeNode*)写成了sizeof(int),导致分配的内存空间不够

错误提示3
Line 26: Char 17: runtime error: shift exponent -1 is negative [solution.c]
错误原因:位运算移位的位数只能是非负整数

  • 2<<0 - 1,由于位运算优先级非常低,该表达式会优先进行减法运算,因此导致移位负数,因此需要给位运算加括号,改成 (2<<0) - 1

错误提示4:
Line 96: Char 17: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'struct TreeNode', which requires 8 byte alignment [TreeNode.c] 0xbebebebebebebebe: note: pointer points here <memory cannot be printed>
错误原因: 二叉树节点左子树与右子树没有初始化为NULL,或链表末尾没有指向NULL


错误提示5
AddressSanitizer:DEADLYSIGNAL ==21==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7ff25e341149 bp 0x7ffd63421960 sp 0x7ffd63421260 T0)
错误原因: scanf或者sscanf没加&


错误提示6
测试样例单独测试都能通过,但是放到一起测试却显示报错
错误原因: 代码中有全局变量没有初始化,或者没有写*returnSize = 0;


五、完结撒花

初试384分排415名,复试81.93分(184.3分)排102名,总分排235,逆袭了180名,明天就写经验贴
在这里插入图片描述

  • 32
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值