leetcode刷题记录day035:138和430
作者:互联网
138、难度中等:
方法一:原创:暴力哈希表:
思路:有三点有解决的:
①、构建所有的next:第一轮循环从头开始遍历
②、每个next和random都不能是原先链表的节点:创建新链表节点时采用ano.next = new Node(head.next.val,null,null);方式
③、构建所有的random:创建哈希表,第一轮循环时加入原链表和新链表各节点的逐个对应关系,第二轮循环从头开始遍历,从哈希表中取出新链表的节点,采用ano.random = con.get(ori.random);方式
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head == null){
return null;
}
// 创建对应题传链表和新链表各个节点的哈希表
Map<Node, Node> con = new HashMap<Node, Node>();
// 用于构建新链表
Node ano = new Node(head.val,null,null);
// 加入对应关系
con.put(head,ano);
// 作为返回结果用
Node ans = ano;
// 用于第二轮循环加入random时用,保存原链表头结点
Node ori = head;
// 第一轮循环加入所有next
while(head.next != null){
ano.next = new Node(head.next.val,null,null);
con.put(head.next,ano.next);
ano = ano.next;
head = head.next;
}
// 第二轮循环加入random
ano = ans;
while(ano != null){
ano.random = con.get(ori.random);
ano = ano.next;
ori = ori.next;
}
return ans;
}
}
方法二:回溯 + 哈希表:
思路:本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建,因此我们需要变换思路。
我们用哈希表记录每一个节点对应新节点的创建情况,若当前节点不再哈希表中,我们首先要进行拷贝,然后我们进行「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝(我们检查「当前节点的后继节点」和「当前节点的随机指针指向的节点」的创建情况。如果这两个节点中的任何一个节点的新节点没有被创建,我们都立刻递归地进行创建。)
,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。
class Solution {
Map<Node, Node> cachedNode = new HashMap<Node, Node>();
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
// 从第一个节点开始处理,哟哟与第一个节点的next和random还未被创建出来,所以递归的调用方法本身
// 去创建next和random,又由于调用方法本身又会创建next、random各自的next和random
// 这样最后就复制完了链表
// 如何确保递归会停止,哈希表存储哪些结点已经被创建完了
if (!cachedNode.containsKey(head)) {
Node headNew = new Node(head.val);
cachedNode.put(head, headNew);
headNew.next = copyRandomList(head.next);
headNew.random = copyRandomList(head.random);
}
// 返回头结点
return cachedNode.get(head);
}
}
/**
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/fu-zhi-dai-sui-ji-zhi-zhen-de-lian-biao-rblsf/
**/
方法三:迭代 + 节点拆分:空间复杂度O(1)
具体原理点击下方链接:根据图解直接看代码就能看懂
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/fu-zhi-dai-sui-ji-zhi-zhen-de-lian-biao-rblsf/
class Solution {
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
for (Node node = head; node != null; node = node.next.next) {
Node nodeNew = new Node(node.val);
nodeNew.next = node.next;
node.next = nodeNew;
}
for (Node node = head; node != null; node = node.next.next) {
Node nodeNew = node.next;
nodeNew.random = (node.random != null) ? node.random.next : null;
}
Node headNew = head.next;
for (Node node = head; node != null; node = node.next) {
Node nodeNew = node.next;
node.next = node.next.next;
nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
}
return headNew;
}
}
430、难度中等:
方法一:原创:深度搜索(递归):用时超越100,内存变化不定
思路:
遍历题传链表(不考虑子链表),遍历时若当前节点存在子链表,那就调用递归深度搜索方法。
递归方法中我们所做的如下:
子链表中的节点可能还存在子链表,在判断当前节点是否存在子链表时,为防止出现死循环,我们还需新增一个变量用于表示当前节点的子链表正准备被循环、
我们需要注意节点间的关系,否则会leetcode会提示报错(后台会遍历答案链表):当前节点存在子链表时:
那么当前节点的next指向子链表的第一个节点,子链表第一个节点的prev指向当前节点。
当前节点原先的next的prev指向子链表的最后一个节点,子链表最后一个节点的next指向前节点原先的next
当前节点的子链表指向应修改为空
递归设计原理:把共性相同的流程提取出来
/*
// Definition for a Node.
class Node {
public int val;
public Node prev;
public Node next;
public Node child;
};
*/
class Solution {
Node visited; // 保存正在被遍历子链表的节点
public Node flatten(Node head) {
if(head == null){
return null;
}
// 答案链表的首节点作为返回值
Node ans = head;
// 不考虑子链表的情况下循环题传链表
while(head != null){
// 若当前节点有子链表,调用递归方法
if(head.child != null){
// 表示当前节点head的子链表正在被遍历
visited = head;
dfs(head);
}
head = head.next;
}
return ans;
}
// 递归方法
public void dfs(Node head){
// 保存当前节点的next防止丢失
Node next = head.next;
// 当前.next = 子链表首节点
head.next = head.child;
// 子链表首节点.prev = 当前
head.child.prev = head;
// 当前.child = null
head.child = null;
// 开始前往子链表的末尾
while(head.next != null){
// 若子链表的节点中也存在子链表。
// 由于下面的dfs调用head,而这里的判断用的也是 head
// 为防止陷入死循环不断进入该 if 判断语句调用 dfs(head);
// 我们用visited保存head
if(head.child != null && visited != head){
visited = head;
dfs(head);
}
head = head.next;
}
// 当前head是子链表中的最后一个节点,其next指向当前节点原先的next
head.next = next;
// 为防止当前节点是最后一个节点,next是null,但null无prev,为防止报错我们需加判断
if(next != null){
next.prev = head;
}
// 更新当前节点
head = head.next;
}
}
标签:Node,head,null,leetcode,链表,next,day035,138,节点 来源: https://blog.csdn.net/m0_52937388/article/details/121061713