被裁公司给了20 万的补偿,结果前领导找到我,说让跟他一起创业,每周干3天,保底挣3w~
最近一位同事找我吐槽,他一直在纠结是不是该跳槽去创业。
他前公司给了20万的补偿,但他本来是想找到一个新的工作,结果就遇到这个“创业诱惑”。领导承诺每周三天,保底3W,听起来简直是捡钱
但是,我得说,创业不是咱们做一个功能上线的事,更多时候是“填坑”。就像我做项目时,总是想着只要代码写好就没问题,结果总会遇到各种bug,光想法好是不够的,执行上的每一步都需要小心翼翼。
我觉得,创业没那么简单,起码要保证有一定的积蓄,并且能承担起失败的风险。
如果没有创业经验,最好先在公司里稳扎稳打,获取一些能提升自己的资源,再做决定。
毕竟,想创业的不是一时头脑发热,真要走那条路,心理准备要充足。【备注:文末可领最新资料】。
算法题:设计链表
今天我们聊聊一个经典的算法题:设计链表。
说到链表,首先得说明一个概念:链表是一种线性的数据结构,它不像数组那样存储在连续的内存空间中,而是每个元素(节点)都包含数据和指向下一个元素的指针(或引用)。这也就是链表和数组最大的区别,链表的内存不是连续的,它的每个元素存储在内存中不同的地方,但是每个节点会“知道”下一个节点在哪里。
链表的一些常见操作包括:添加元素、删除元素、查找元素、反转链表等等。这些操作常常是面试中考察的重点,尤其是需要实现一个自定义的链表类。
让我们先从简单的“设计一个链表”开始,定义一个链表节点类。假设我们只做单链表,不考虑双向链表或者循环链表的复杂情况。简单来说,链表节点的结构大概就应该是这样:
class ListNode {
int val;
ListNode next; // 构造函数
ListNode(int x) {
val = x;
next = null;
}
}
上面是链表节点类的简单定义。val存储节点的值,next是指向下一个节点的引用。
接下来,我们需要一个链表类来管理这些节点。链表类需要支持基本的操作,例如添加节点、删除节点、打印链表等。
假设我们要实现一个支持以下操作的链表类:
addAtHead(int val):在链表头部添加一个节点。addAtTail(int val):在链表尾部添加一个节点。deleteAtIndex(int index):删除指定位置的节点。printList():打印链表的所有节点。
具体代码如下:
class MyLinkedList {
private ListNode head; // 链表的头结点
private int size; // 链表的长度 // 初始化链表
public MyLinkedList() {
head = new ListNode(0); // 虚拟头节点,方便操作
size = 0;
}
// 在头部添加节点
public void addAtHead(int val) {
ListNode node = new ListNode(val);
node.next = head.next;
head.next = node;
size++;
}
// 在尾部添加节点
public void addAtTail(int val) {
ListNode node = new ListNode(val);
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
size++;
}
// 删除指定位置的节点
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return; // 如果索引无效,直接返回
}
ListNode cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
size--;
}
// 打印链表
public void printList() {
ListNode cur = head.next;
while (cur != null) {
System.out.print(cur.val + " -> ");
cur = cur.next;
}
System.out.println("null");
}
}
现在,我们来分析下每个操作:
addAtHead(int val):我们创建一个新的节点,把它的next指向当前头节点的下一个节点。然后更新头节点的next指向这个新节点。时间复杂度是O(1)。addAtTail(int val):我们从头节点开始遍历,直到找到链表的最后一个节点,将其next指向新节点。时间复杂度是O(n),因为我们可能需要遍历整个链表。deleteAtIndex(int index):首先检查索引是否合法,然后通过遍历找到前一个节点,修改它的next指向要删除节点的下一个节点。时间复杂度是O(n),因为最坏情况下我们需要遍历整个链表。printList():遍历链表,输出每个节点的值。时间复杂度是O(n)。
说到链表,除了基本的操作,还有一些更有挑战性的操作,比如链表反转。反转链表的算法是经典的面试题之一。反转链表的思路是:我们遍历链表,同时改变每个节点的next指向,使得链表的方向发生反转。下面是反转链表的实现代码:
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head; while (curr != null) {
ListNode nextTemp = curr.next; // 暂存下一个节点
curr.next = prev; // 反转当前节点的指向
prev = curr; // 移动prev和curr指针
curr = nextTemp;
}
return prev; // 返回新的头节点
}
这个算法的时间复杂度是O(n),空间复杂度是O(1),因为我们只用了常数级别的额外空间。
讲了这么多链表的实现,大家可能会觉得链表其实挺简单的,操作也不复杂。但其实,链表的细节操作还是有点讲究的,尤其是涉及到边界条件时。比如,删除头节点、空链表的处理、以及反转链表时指针的操作,每一步都得小心翼翼。
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。