问题描述: 复制一个复杂链表。 在复杂链表中,每个结点除了有一个指向下一个结点的next指针外,还有一个 sibing指针 指向链表中任意结点或者NULL。
解法一:“爆破”
解法分析:
- 遍历第一遍数组,把复制链的next和各结点值复制好。需要时间O(n)
- 第二遍遍历,二重for循环根据原链表,将复制链的slibing指针连接好。需要时间O(n^2)
- 需要时间复杂度是O(n^2),空间复杂度是O(1)
参考代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| * 复杂链表的结点 * * @author kesar * */ static class Node { int val; Node next; Node slibing;
public Node(){}
public Node(int val) { this.val = val; }
@Override public String toString() { return "Node [val=" + val + "]"; } }
* 第一种解法:暴力复制。复制一遍next的,再每个结点遍历一遍进行slibing的比较。 时间复杂度是:O(n^2),空间复杂度是:O(1) * * @param oHead * @return */ public static Node copy1(Node oHead) { if (oHead == null) { return null; } Node cHead = new Node(oHead.val);
for (Node oMove = oHead.next, cMove = cHead; oMove != null; cMove = cMove.next, oMove = oMove.next) { cMove.next = new Node(oMove.val); }
for (Node oMove = oHead, cMove = cHead; oMove != null; cMove = cMove.next, oMove = oMove.next) { if (oMove.slibing == null) continue; Node findNode = cHead; for (; findNode != null && findNode.val != oMove.slibing.val; findNode = findNode.next) ; cMove.slibing = findNode; }
return cHead; }
|
解法二:使用辅助空间
解法分析:
- 使用一个HashMap(Key:原链表上的结点,Value:复制链表上的结点),空间复杂度是O(n)
- 遍历第一遍数组:每次创建复制链的结点时,需要先查找HashMap中结点是否存在,不存在才创建,然后保存结点到HashMap中。需要时间O(n)
- 需要时间复杂度是O(n),空间复杂度是O(n)
参考代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| * 第二种解法:利用HashMap的O(1)的高效率查找来取代第一中解法中的一个for循环。用O(n)的空间换来O(n)的时间。时间复杂度O(n),空间复杂度:O(n) * * @param oHead * @return */ public static Node copy2(Node oHead) { if (oHead == null) { return null; } HashMap<Node, Node> map = new HashMap<Node, Node>();
Node cHead = new Node(oHead.val); map.put(oHead, cHead); if (oHead.slibing != null) { cHead.slibing = new Node(oHead.slibing.val); map.put(oHead.slibing, cHead.slibing); } for (Node oMove = oHead.next, cMove = cHead; oMove != null; oMove = oMove.next, cMove = cMove.next) { if (map.containsKey(oMove)) { cMove.next = map.get(oMove); } else { cMove.next = new Node(oMove.val); map.put(oMove, cMove.next); } Node slibing = oMove.slibing; if (slibing == null) { continue; } if (map.containsKey(slibing)) { cMove.next.slibing = map.get(slibing); } else { cMove.next.slibing = new Node(slibing.val); map.put(slibing, cMove.next.slibing); } } return cHead; }
|
解法三:“伸长分裂法”
解法分析:
- 遍历原链表。在原链表的每个结点的后面插入对应复制结点,将原链表“伸长”1倍;
- 遍历原链表。将复制结点的slibing连接好;
- 遍历原链表。将原结点和复制结点“分裂”开,将next连接好;
- 需要时间复杂度是O(n),空间复杂度是O(1)
参考代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| * @param oHead * @return */ public static Node copy3(Node oHead) { if (oHead == null) { return null; } for (Node oMove = oHead; oMove != null; oMove = oMove.next) { Node copy = new Node(oMove.val); copy.next = oMove.next; oMove.next = copy; oMove = copy; } for (Node oMove = oHead; oMove != null; oMove = oMove.next) { if (oMove.slibing == null) { continue; } Node copy = oMove.next; copy.slibing = oMove.slibing.next; oMove = copy; } Node cHead = oHead.next; oHead.next = cHead.next; cHead.next = null; for (Node oMove = oHead.next, cMove = cHead; oMove != null; oMove = oMove.next, cMove = cMove.next) { Node copy = oMove.next; oMove.next = copy.next; copy.next = null; cMove.next = copy; } return cHead; }
|