链表题不会做?lc经典链表算法最细解题思路+源码,从此告别链表算法(下)

关于面试的充分准备

一些基础知识和理论肯定是要背的,要理解的背,用自己的语言总结一下背下来。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,我能明显感觉到国庆后多了很多高级职位,所以努力让自己成为高级工程师才是最重要的。

好了,希望对大家有所帮助。

接下来是整理的一些Android学习资料,有兴趣的朋友们可以关注下我免费领取方式

①Android开发核心知识点笔记

②对标“阿里 P7” 40W+年薪企业资深架构师成长学习路线图

③面试精品集锦汇总

④全套体系化高级架构视频

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Map<Node1, Node1> map = new HashMap<>();
Node1 cur = head;
while (cur != null) {
map.put(cur, new Node1(cur.value));
cur = cur.next;
}
//把副节点连接起来
cur = head;
while (cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).rand = map.get(cur.rand);
cur = cur.next;
}
return map.get(head);
}

这种方法的时间复杂度为 O(n), 空间复杂度也为 O(n)。

方法2

其实我们也可以不需要哈希表来辅助,也就是说 ,我们是可以做到空间复杂度为 O(1)的,我们可以把复制的副节点插入到原链表中去,这样也能把原节点与副节点进行关联,进而 定位到随机节点。例如,对于链表 1->2->3->null。首先生成副节点 1’, 2’, 3。然后把副节点插入到原节点的相邻位置,即把原链表变成 1->1’->2->2’->3->3’->null。

这样我们也可以在连接副节点的时候,找到相应的随机节点。例如 1 的随机节点是 3,则 1’ 的随机节点是 3’。显然,1节点的随机节点的下一个节点就是 1’的随机节点。具体代码如下:

//方法二
public static Node1 copyListWithRand2(Node1 head){
Node1 cur = head;
Node1 next = null;

//把复制的节点插进去
while (cur != null) {
next = cur.next;
Node1 temp = new Node1(cur.value);//复制节点
temp.next = cur.next;
cur.next = temp;
cur = next;
}
//在一边把复制的节点取出来一边连接。
cur = head;
next = null;
while (cur != null) {
next = cur.next.next;//保存原链表的下一个节点
cur.next.next = next != null ? next.next : null;
cur.next.rand = cur.rand != null ? cur.rand.next : null;
cur = next;
}
return head.next;
}

采用这种方法的时候,由于随机节点有可能是空指针,随意写代码的时候要注意。

7、将单链表的每K个节点之间逆序

【题目描述】

给定一个单链表的头节点head, 实现一个调整单链表的函数,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。

例如:

链表:1->2->3->4->5->6->7->8->null, K = 3。

调整后:3->2->1->6->5->4->7->8->null。其中 7,8不调整,因为不够一组。

【要求】

如果链表的长度为 N, 时间复杂度达到 O(N)。

【解答】

这道题我们可以用递归来实现,假设方法reverseKNode()的功能是将单链表的每K个节点之间逆序。reverse()方法的功能是将一个单链表逆序。

那么对于下面的这个单链表,其中 K = 3。

我们把前K个节点与后面的节点分割出来:

temp指向的剩余的链表,可以说是原问题的一个子问题。我们可以调用reverseKNode()方法将temp指向的链表每K个节点之间进行逆序。再调用reverse()方法把head指向的那3个节点进行逆序,结果如下:

接着,我们只需要把这两部分给连接起来就可以了。最后的结果如下:

如果不大理解,看下代码可能就比较好理解了。

代码如下

//每k个节点为一组的逆转
public static Node reverseKNodes(Node head, int k) {
if (head == null || head.next == null) {
return head;
}
Node cur = head;
for (int i = 1; cur != null && i < k; i++) {
cur = cur.next;
}
//判断是否能组成一组。
if (cur == null) {
return head;
}
//temp指向剩余的链表
Node temp = cur.next;
cur.next = null;
//把k个节点进行反转
Node newHead = reverse(head);
//把之后的部分链表进行每K个节点逆转转
Node newTemp = reverseKNodes(temp, k);
//把两部分节点连接起来
return newHead;
}

//单链表逆序
public static Node reverse(Node head) {
if (head == null || head.next == null) {
return head;
}
Node newHead = reverse(head.next);
head.next.next = head;
head.next = null;
return newHead;
}

当然,这道题一个很简单的做法就是利用栈来辅助,每K个节点入栈就把这K个节点出栈连接成一个链表,之后剩余再在进栈…

不过这种做法的额外空间复杂度是O(K)。

8、将搜索二叉树转换成双向链表

【题目描述】

对于二叉树的节点来说,有本身的值域,有指向左孩子和右孩子的两个指针;对双向链表的节点来说,有本身的值域,有指向上一个节点和下一个节点的指针。在结构上,两种结构有相似性,现有一棵搜索二叉树,请将其转为成一个有序的双向链表。   节点定义:

class Node2{
public int value;
public Node2 left;
public Node2 right;

public Node2(int value) {
this.value = value;
}
}

例如:

这棵二叉搜索树转换后的双向链表从头到尾依次是 1~9。对于每一个节点来说,原来的 right 指针等价于转换后的 next 指针,原来的 left 指针等价于转换后的 last 指针,最后返回转换后的双向链表的头节点。

【要求】

如果链表的长度为 N, 时间复杂度达到 O(N)

【解答】

方法一:采用队列辅助

如果用一个队列来辅助的话,还是挺容易。采用中序遍历的方法,把二叉树的节点全部放进队列,之后在逐一弹出来连接成双向链表。

代码如下

public static Node2 convert1(Node2 head) {
Queue queue = new LinkedList<>();
//将节点按中序遍历放进队列里
inOrderToQueue(head, queue);
head = queue.poll();
Node2 pre = head;
pre.left = null;
Node2 cur = null;
while (!queue.isEmpty()) {
cur = queue.poll();
pre.right = cur;
cur.left = pre;
pre = cur;
}
pre.right = null;
return head;
}

private static void inOrderToQueue(Node2 head, Queue queue) {
if (head == null) {
return;
}
inOrderToQueue(head.left, queue);
queue.offer(head);
inOrderToQueue(head.right, queue);
}

这种方法的时间复杂度为 O(n), 空间复杂度也为 O(n)。

方法2:通过递归的方式

在之前打卡的9道题中,几乎超过一般都用到了递归,如果这些题目使用的递归大家都理解了,并且能够自己独立写出代码了,那么我相信大家对递归的思想、使用已经有一定的熟练性。

我们假设函数conver的功能就是把二叉树变成双向链表,例如对于这种一棵二叉树:

经过conver转换后变成这样:

注意,转换之后,把最右边节点的right指针指向了最左边的节点的。

对于下面这样一颗二叉树:

采用conver函数分别对左右子树做处理,结果如下:

之后,再把他们连接起来

了解了基本原理之后,直接看代码吧。

public static Node2 conver(Node2 head) {
if (head == null) {
return head;
}
Node2 leftE = conver(head.left);
Node2 rightE = conver(head.right);
Node2 leftB = leftE != null ? leftE.right : null;
Node2 rightB = rightE != null ? rightE.right : null;
if (leftE != null && rightE != null) {
leftE.right = head;
head.left = leftE;
head.right = rightB;
rightB.left = head;
rightE.right = leftB;
return rightE;
} else if (leftE != null) {
leftE.right = head;
head.left = leftE;
head.right = leftB;
return head;
} else if (rightE != null) {
head.right = rightB;
rightB.left = head;
rightE.right = head;
return rightE;
} else {
head.right = head;
return head;
}
}

时间复杂度为O(n),空间复杂度为O(h),其中h是二叉树的高度。

原理虽然不难,但写起代码,还是有挺多细节需要注意的,所以一直强调,有时间的话,一定要自己手打一遍代码,有时你以为自己懂了,可能在写代码的时候,发现自己并没有懂,一写就出现很多bug。

9、删除单链表的第 K个节点

【题目描述】

在单链表中删除倒数第 K 个节点

【要求】

如果链表的长度为 N, 时间复杂度达到 O(N), 额外空间复杂度达到 O(1)

最后

由于题目很多整理答案的工作量太大,所以仅限于提供知识点,详细的很多问题和参考答案我都整理成了 PDF文件

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

H5ZL-1715476072562)]

[外链图片转存中…(img-TzdnuX2l-1715476072562)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值