大家都说要把剑指offer的50 个面试题反复的看,烂熟于心,但是在看过一次后,觉得有些与实际工作用用处不大。这里整理了几个 自己认为比较重要、且适用自己的面试题,方便后续查看:
数据结构一直是技术面试的重点,大多数面试题都是围绕着数组、字符串、链表、树、战及队列这几种常见的数据结构展开的,因此每一个应聘者都要熟练掌握这几种数据结构
数组和字符串是两种最基本的数据结构,它们用连续内存分别存储数 字和字符。链表和树是面试中出现频率最高的数据结构。
一:数组
tips1: 当数组作为函数的参数进行传递时, 数组就自动退化为同类型的指针
例如:
int GetSize(int data[])
{
return sizeof(data);
}
int main()
{
int datal[] ={1,2,3,4,5};
size1=sizeof(data1);
int *date2=data1;
size2 = sizeof(data2);
size3=Getsize(data1);
}
printf( ” %d, %d, %d", sizel, size2, size3);
结果是:20, 4, 4。
size1:data I 是一个数组, sizeof(data I)是求数组的大小。这个数组包含 5 个整数,每个整数占 4 字节,因此总共是 20 字节
size2: data2声明为指针,尽管它指向了数组dataI的第一个数字,但它的本质仍然是一 个指针。在32位系统上,对任意指针求sizeof,得到的结果都是4。
size3:在 CIC++ 中, 当数组作为函数的参数进行传递时, 数组就自动退化为同类型的指针。 因此尽管函数GetSize的参数data被声明为数组,但它会退化为指针,size3的结果仍然是4。
二、字符串
CIC++中每个字符串都以字符’/0’作为结尾,这样我们就能很方便地找到字符串的最后尾部。但由于这个特点,每个字符串中都有一个额外字符的开销,稍不留神就会造成字符串的越界。比如下面的代码:
char str[10];
strcpy(str,”0123456789”);
声明一个长度为10的字符数组,然后把字符串”0123456789”复制到数组中。”。123456789”这个字符串看越来只有10个字符,但实际上它 的末尾还有-个‘/0’字符,因此它的实际长度为11个字节。要正确地复制该 字符串,至少需要一个长度为11个字节的数组。
tips2:
结果:str1 and str2 are not same str3 and str4 are same
1.
str1 and str2 are not same:str1和str2是两个字符串数组, 我们会为它们分配两个长度为12个字 节的空间, 并把”helloworld', 的内容分别复制到数组中去。 这是两个初始地址不同的数组,因此str1和str2的值也不相同;
2.
str3 and str4 are same: str3和str4是两个指针,我们无须为它们分配内存以存储字符串的内容, 而只需要把它们指向”hello world,,在内存中的地址就可以了。 由于”hello world'”是常量字符串,它在内存中只有一个拷贝,因此str3和str4指向的是同一个地址。
面试题4:替换空格
题目:请实现一个函数,把字符串中的每个空格替换成"%20",例如“We are happy.”,则输出“We%20are%20happy.”。
分析:挨个替换,会存在一个字符变成3个字符,遇到空格后,需要将数据往后移2个位置。直观的做法是从头到尾扫描字符, 每 一次碰到空格字符的时候做替换。由于是把1个字符替换成3个字符,我们必须要把空格后面所有的字符都后移两个字节, 否则就有两个字符被覆盖了。——————时间复杂度太高,O(n平方)
正解: 先找出所有空格数,显然替换后的数组长度 = 旧数组长度 + 空个数*2,然后从后往前依次替换即可。
class Solution
{
public:
void replaceSpace(char str,int length)
{
int num = 0;//空格数
for(int i = 0;str[i];i++)
num += (str[i] == ’ ');
int index_old = length;
int index_new = length+num2;
while(index_old >= 0)
{
if(str[index_old] != ' ')
str[index_new--] = str[index_old--];
else
{
str[index_new--] = '0';
str[index_new--] = '2';
str[index_new--] = '%';
index_old--;
}
}
return ;
}
};
测试用例:
• 输入的字符中包含空格(空格位于字符串的最前面,空格位于字 符串的最后面,空格位于字符净的中间,字符串中有连续多个空格)。
• 输入的字符串中没有空格。
• 特殊输入测试(字符串是个NULL指针、字符串是个空字符串、 字符串只有个空格字符、字符串只有连续多个空格〉。
扩展题目:
1. 有两个排序的数组Al和A2,内存在A1的末尾有足够多的空余空间,容纳A2. 请实现一个函数, 把A2中的所有数字插入到Al中并且所有的数字是排序的。和前面的例题一样,很多人首先想到的办法是在Al中从头到尾复制数 字, 但这样就会出现多次复制1个数字的情况。 更好的办法是从尾到头比较Al和A2中的数字, 并把较大的数字复制到Al的合适位置。
2. 合并两个数组(包括字符串)时, 如果从前往后复制每个数字(或字 符)需要重复移动数字(或字符)多次, 那么我们可以考虑从后往前复制, 这样就能减少移动的次数, 从而提高效率.
三、链表
链表的结构很简单, 它自指针把若干个结点连接成链状结构。 链表的创建、 插入结点、 删除结点 等操作都只需要20行左右的代码就能实现, 其代码量比较适合面试。
我们说链表是一种动态数据结构, 是因为在创建链表时, 无须知道链表的长度。 当插入一个结点时, 我们只需要为新结点分配内存, 然后调整 指告|的指向来确保新结点被链接到链表当中。 内存分配不是在创建链表时 -次性完成, 而是每添加~个结点分配一次内存。 由于没有闲置的内存,链袤的空间效率比数组高。
struct ListNode
{
ListNode val; //节点的值
ListNode nxt; //下一个节点
}
链表的 增删改查 操作,必须会(可以直接百度,资料很多)
面试题5:从尾到头打印链表
题目:输入个链表的头结点,从尾到头反过来打印出每个结点的值。
分析:从尾到头,其实是一个先进后出的 过程,可以使用栈来实现,也可以使用 递归方法来实现:
//利用递归实现从尾到头打印
void PrintListRecursive(struct Student *head)
{
if(head != NULL)
{
if(head->next != NULL)
{
PrintListRecursive(head->next);
}
printf("%ld,%5.1f\n",head->num,head->score);
}
}
面试题13:在0(1)时间删除链表结点
面试题15:链表中倒数第K个节点
两个指针,第一个先走k步,第二个正常走,当第一个到达尾部,那第二个就是倒数k个了(空链表、K为0,K大于整个链表长度、链表头部、链表尾部)
16 :反转链表
断开的时候,需要记录下一个链表(链表头结点为null、仅有一个节点)
17 : 合并两个排序的链表
比较头结点,插入新链表中,然后不断比较头结点,递归方式实现(输入的 两个链表有多个结点,结点的值互不相同或者存在值相等的多个结点;两个链表的 一个或者两个头结点为 NULL 指针、两个链表中只有一个结点)
37:两个链表的第一个公共节点