2021.02.17 复杂链表的复制
今日题目:请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。


提示:
- -10000 <= Node.val <= 10000
- Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
思路:
- 法一:用哈希表辅助,采用空间换时间,哈希表为Map
,作为key的Node是原来链表中的结点,而作为值的Node是新建链表中对应的结点。分成两步走,第一步先建立起新的链表,此时把各结点的对应情况保存至map中,新链表各结点的random值都为null,第二步再从头开始遍历,利用哈希表处理random值即可。时间复杂度是O(n),空间复杂度为O(n)。 - 法二:第一步,先遍历一遍原链表,在原链表中的每个结点后边都新建一个结点,例如N后边拼接N`;第二步处理每个新结点的random值,它等于原结点random值的下一个;第三步,拆分两个单链表。
- 法一:用哈希表辅助,采用空间换时间,哈希表为Map
自己的菜鸡代码:
/*// 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) {Map<Node,Node> map = new HashMap<>();Node p = head, newHead = null, q = null;while(p != null){Node node = new Node(p.val);map.put(p, node);if(p == head) newHead = node;else q.next = node;q = node;p = p.next;}p = head;q = newHead;while(p != null){q.random = map.get(p.random);p = p.next;q = q.next;}return newHead;}}
运行结果:
法一(左)、法二(右)

2021.02.17 二叉搜索树与双向链表
今日题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
- 思路:
- 法一:(自己写的)递归中序遍历二叉树,用一个辅助的哈希表保存中序遍历序列,最后遍历一遍哈希表,修改各个结点的指针,这样子时间复杂度和空间复杂度都很高。
- 法二:(大佬的)在中序递归遍历时,就进行指针的处理。若root==null,返回,否则先递归遍历左子树,设置两个全局变量,一个是pre用于指向前一个结点,当pre == null时,当前结点就是第一个结点,令另一个全局变量head指向该结点,当pre != null时,令当前结点的左指针指向pre,令pre的右指针指向当前结点,再让pre = 当前结点(当前结点是下一个结点的前结点),再递归遍历右子树。最后pre指向的是最后一个结点,令head的左指针指向pre,pre的右指针指向head,返回head即可。时间复杂度为O(n),空间复杂度为O(n)。
自己的菜鸡代码: ```java /* // Definition for a Node. class Node { public int val; public Node left; public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;left = _left;right = _right;
} }; */ class Solution { private LinkedList
list = new LinkedList<>(); public Node treeToDoublyList(Node root) { // 按中序遍历序列的顺序线索化// 试一下用空间换时间if(root == null) return root;InOrder(root);Node pre = list.getLast();Node head = list.getFirst();while(!list.isEmpty()){Node node = list.removeFirst();node.left = pre;if(!list.isEmpty()){node.right = list.getFirst();}else{node.right = head;}pre = node;}return head;
}
void InOrder(Node root){
if(root == null) return;if(root.left != null){InOrder(root.left);}list.add(root);if(root.right != null){InOrder(root.right);}
} }
// 法二 /* // Definition for a Node. class Node { public int val; public Node left; public Node right;
public Node() {}public Node(int _val) {val = _val;}public Node(int _val,Node _left,Node _right) {val = _val;left = _left;right = _right;}
}; */ class Solution { private Node pre, head; public Node treeToDoublyList(Node root) { if(root == null) return null; pre = null; dfs(root); head.left = pre; pre.right = head; return head; }
void dfs(Node root){if(root == null) return;dfs(root.left);root.left = pre;if(pre != null){pre.right = root;}else{head = root;}pre = root;dfs(root.right);}
} ```
- 运行结果:
法一(左)、法二(右):

