介绍项目的应用场景
和工业界应用的区别
学过什么数据结构和算法,刷过多少力扣题。
实现 strcpy。看我写的慢给我打断了,问我是不是没写过。答曰是,把思路给它讲了下,并说明拷贝时可能出现的覆盖问题。
平时编程写的多吗?出了道题目。Vim 上实现单词反转 "This is a girl"->"girl a is This",要求不能用 C++的一些接口,比 如 pop、push等,最好用纯 C 写,限时10分钟。what? 用 C++ vector 和 string 写了个 10 行左右的逻辑判断, 以为他说 的 pop、push 禁用是指不能用栈数据结构。实际他想让我写的是原地反转吧(也就是先整体反转,再逐单词反转)。
指针和引用的区别
tcp3次握手过程
怎么处理内存泄漏
原文件到可执行文件的过程
了不了解数据库(不了解)
事务相关(不了解)
求最长不重复子串的长度
深拷贝,浅拷贝区别
写一个深拷贝的例子
进程间通信方式
介绍重载重写
讲讲vector的增删操作和扩容
迭代器为什么可以遍历任何类型的数据
手撕:一串数字中找到最长的递增子序列
场景:100本书,A、B分别拿,一次可以拿1-5本,如何确保是A最后一个拿的
两个链表相交的判断方法 至少三种
暴力
简单的一个想法,对链表 A 中的每一个结点,我们都遍历一次链表 B 查找是否存在重复结点,第一个查找到的即第一个公共结点
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { for (ListNode *p = headA; p != nullptr; p = p->next) { for (ListNode *q = headB; q != nullptr; q = q->next) { if (p == q) return p; } } return nullptr; } };
时间复杂度:O(n^2)
空间复杂度:O(1)
哈希表
对暴力解法的一个优化方案是:先将其中一个链表存到哈希表中,此时再遍历另外一个链表查找重复结点只需 O(1)
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { unordered_set<ListNode *> s; for (ListNode *p = headA; p != nullptr; p = p->next) { s.emplace(p); } for (ListNode *p = headB; p != nullptr; p = p->next) { if (s.find(p) != s.end()) return p; } return nullptr; } };
时间复杂度:O(n)
空间复杂度:O(n)
栈
两个链表从公共结点开始后面都是一样的,若是我们顺着链表从后向前查找,很容易就能查找到链表的公共结点(第一个不相同的结点的下一个结点即所求)
那么如何从后向前查找呢?不难想到要使用栈
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { stack<ListNode *> s1, s2; for (ListNode *p = headA; p != nullptr; p = p->next) { s1.push(p); } for (ListNode *p = headB; p != nullptr; p = p->next) { s2.push(p); } ListNode *ans = nullptr; for ( ; !s1.empty() && !s2.empty() && s1.top() == s2.top(); s1.pop(), s2.pop()) ans = s1.top(); return ans; } };
时间复杂度:O(n)
空间复杂度:O(n)
计算长度
前面的几个方法或是时间,或是空间,不满足题目要求的 O(n)O(n)O(n) 时间复杂度,且仅用 O(1)O(1)O(1) 内存
前面栈的解法中提到,从后向前很容易查找,那么能不能从前向后呢?若是两链表等长,那自然是可以的,指针同步后移,当遇到公共结点时两指针就会相遇,但若链表不等长那就不行了,两个指针可能会指向不同的公共结点,也就无法确定一个结点是否是公共结点。
由此,我们可以想到,能不能把两个链表变成等长的链表呢?显然若两链表不等长,那么长的链表的前 n 个结点(n 是长链表比短链表多的结点数)显然不可能是公共结点。而剩余部分两链表是等长的,自然就可以按照顺序同步后移的方法查找公共结点。
不过,为确定两链表长度差,得先遍历两链表确定长度
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { int size1 = 1, size2 = 1; ListNode *p, *q; if (!headA || !headB)return NULL; /* 计算链表长度 */ for (p = headA; p->next != NULL; p = p->next, size1++); for (p = headB; p->next != NULL; p = p->next, size2++); /* 长链表先走,但不确定AB谁长,所以要写两个循环,但实际上有至少一个循环不会执行 */ p = headA; q = headB; for (int i = 0; i < size1 - size2; i++, p = p->next); for (int i = 0; i < size2 - size1; i++, q = q->next); for (; p && q && p != q; p = p->next, q = q->next); return p; } };
时间复杂度:O(n)
空间复杂度:O(1)
走过彼此的路
除了计算链表长度外,我们还可以利用 两链表长度和相等 的性质来使得两个遍历指针同步
具体做法是:先遍历其中一个链表,当到底末端后跳到另一链表,最后若两链表没有公共结点,那么两个链表指针都会走过 s1+s2个结点,同时到达两链表末尾
若有公共结点,由于最后会同时走到两链表终点,所以倒退回去,两个指针一定会在第一个公共结点处相遇
当然,若两链表等长,那确实不会跳到另一链表,不过链表等长本身指针就是同步的,同样也能找到公共结点
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *p, *q; for (p = headA, q = headB; p != q; ){ if (p != NULL) p = p->next; else p = headB; if (q != NULL) q = q->next; else q = headA; } return p; } };
时间复杂度:O(n)
空间复杂度:O(1)
手撕代码:链表反转;寻找字符串中出现次数最多的字符
读没读过Nginx的源码,你这个网络模型和别的有没有对比?
讲讲b+树和b树的区别
带头结点的单链表实现栈