week15
141 - 环形链表
经典的快慢指针, 快指针每次走两步,慢指针每次走一步,如果他们能相遇说明一定有环;
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* slow = head, *fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
return true;
}
return false;
}
};142 - 环形链表II
在上一题判断有没有环的基础上,找到入口 实际上就是要额外记录环的长度,这样让双指针中的一个指针提前与另一个指针环的长度,则他们再次相遇的时候一定是环的起点;
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head, *fast = head;
bool flag = false;
// 1. 判断是否有环
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
flag = true;
break;
}
}
if(!flag) return nullptr;
// 2. 记录环的长度 并让cur比head提前走 环那么长的指针
// 这样他们再次相遇的时候一定就是起点
ListNode* cur = head;
do
{
slow = slow->next;
cur = cur->next;
}while(slow != fast);
// 3. cur 比 head 提前了一整个环的长度 同时走 直到相遇 就是起点
while(cur != head)
{
cur = cur->next;
head = head->next;
}
return head;
}
};143 - 重排链表
注意的点就在这个如何保证左半段链表node个数大于等于右边上了
144 - 二叉树的前序遍历
总结在后面
145 - 二叉树的后序遍历
在这里复习一下迭代写法的二叉树前序 中序 后序遍历
前序遍历和中序遍历很像,前序:根左右, 中序:左根右
这里都是通过栈来模拟递归调用的过程,尽可能去遍历左子树, 只要有左子树就插入到栈内;
唯一的区别就是根节点是加入时处理 还是弹出时处理,这里要区分一下代码
后序遍历的实现就不太一样了 主要是有一个反序的过程;
这里利用前序遍历类似的方法,我们预先得到 根右左的遍历结果,再反序即可;
146 - LRU 缓存机制
LRU (Least Recently Used)缓存机制
在缓存满的时候,删除缓存里最久未使用的数据,然后再放入新元素;
数据的访问时间很重要,访问时间距离现在最近,就最不容易被删除。
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组关键字-值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
这两个操作应该是o(1)的
用到的数据结构: 双链表

147 - 对链表进行插入排序
模拟题, 找到第一个比当前值大的Node 插他前面
148 - 排序链表
就mergeSort 好了,题目要求的空间复杂度o(1) 只能用迭代方式完成,太麻烦就不写了
149 - 直线上最多的点数
枚举中心点 -> 枚举斜率
这里注意一下 垂直的情况(斜率为负无穷的情况) 和重复点的情况就好了
还有精度问题 -> long double
150 - 逆波兰表达式求值
就按照题里描述的那样 用栈模拟就好了
Last updated