[算法学习]复杂链表的复制

问题描述: 复制一个复杂链表。 在复杂链表中,每个结点除了有一个指向下一个结点的next指针外,还有一个 sibing指针 指向链表中任意结点或者NULL。

解法一:“爆破”

解法分析:

  1. 遍历第一遍数组,把复制链的next和各结点值复制好。需要时间O(n)
  2. 第二遍遍历,二重for循环根据原链表,将复制链的slibing指针连接好。需要时间O(n^2)
  3. 需要时间复杂度是O(n^2),空间复杂度是O(1)

参考代码如下

  
  
  
  
  1. /**
  2. * 复杂链表的结点
  3. *
  4. * @author kesar
  5. *
  6. */
  7. static class Node
  8. {
  9. int val;
  10. Node next;
  11. Node slibing;
  12. public Node(){}
  13. public Node(int val)
  14. {
  15. this.val = val;
  16. }
  17. @Override
  18. public String toString()
  19. {
  20. return "Node [val=" + val + "]";
  21. }
  22. }
  23. /**
  24. * 第一种解法:暴力复制。复制一遍next的,再每个结点遍历一遍进行slibing的比较。 时间复杂度是:O(n^2),空间复杂度是:O(1)
  25. *
  26. * @param oHead
  27. * @return
  28. */
  29. public static Node copy1(Node oHead)
  30. {
  31. if (oHead == null)
  32. {
  33. return null;
  34. }
  35. // 复制的链表的头结点
  36. Node cHead = new Node(oHead.val);
  37. // oMove是原链表上遍历用的移动指针,cMove是复制链表上遍历用的移动指针
  38. // 复制Node结点的值以及next链关系
  39. for (Node oMove = oHead.next, cMove = cHead; oMove != null; cMove = cMove.next, oMove = oMove.next)
  40. {
  41. cMove.next = new Node(oMove.val);
  42. }
  43. // 复制slibing的链关系
  44. for (Node oMove = oHead, cMove = cHead; oMove != null; cMove = cMove.next, oMove = oMove.next)
  45. {
  46. if (oMove.slibing == null)
  47. continue;
  48. // 查找开始: 遍历查找slibing所指原链表结点对应在copy链表中的结点
  49. Node findNode = cHead;
  50. for (; findNode != null && findNode.val != oMove.slibing.val; findNode = findNode.next)
  51. ;
  52. // 查找结束:findNode就是结果
  53. cMove.slibing = findNode;
  54. }
  55. return cHead;
  56. }

解法二:使用辅助空间

解法分析:

  1. 使用一个HashMap(Key:原链表上的结点,Value:复制链表上的结点),空间复杂度是O(n)
  2. 遍历第一遍数组:每次创建复制链的结点时,需要先查找HashMap中结点是否存在,不存在才创建,然后保存结点到HashMap中。需要时间O(n)
  3. 需要时间复杂度是O(n),空间复杂度是O(n)

参考代码如下

  
  
  
  
  1. /**
  2. * 第二种解法:利用HashMap的O(1)的高效率查找来取代第一中解法中的一个for循环。用O(n)的空间换来O(n)的时间。时间复杂度O(n),空间复杂度:O(n)
  3. *
  4. * @param oHead
  5. * @return
  6. */
  7. public static Node copy2(Node oHead)
  8. {
  9. if (oHead == null)
  10. {
  11. return null;
  12. }
  13. // 辅助空间:Key:原链表上的结点,Value:复制链表上的结点
  14. HashMap<Node, Node> map = new HashMap<Node, Node>();
  15. // 初始化复制链表的头结点
  16. Node cHead = new Node(oHead.val);
  17. map.put(oHead, cHead);
  18. if (oHead.slibing != null)
  19. {
  20. cHead.slibing = new Node(oHead.slibing.val);
  21. map.put(oHead.slibing, cHead.slibing);
  22. }
  23. // 作用:遍历原链表,复制结点到复制链表中。
  24. // 思路是这样:先从map找原结点对应的复制结点,如果没找到,就创建一个,然后连接到复制链表中,然后put入map中,便于其他时候使用
  25. for (Node oMove = oHead.next, cMove = cHead; oMove != null; oMove = oMove.next, cMove = cMove.next)
  26. {
  27. if (map.containsKey(oMove))
  28. {
  29. cMove.next = map.get(oMove);
  30. }
  31. else
  32. {
  33. cMove.next = new Node(oMove.val);
  34. map.put(oMove, cMove.next);
  35. }
  36. Node slibing = oMove.slibing;
  37. if (slibing == null)
  38. {
  39. continue;
  40. }
  41. if (map.containsKey(slibing))
  42. {
  43. cMove.next.slibing = map.get(slibing);
  44. }
  45. else
  46. {
  47. cMove.next.slibing = new Node(slibing.val);
  48. map.put(slibing, cMove.next.slibing);
  49. }
  50. }
  51. return cHead;
  52. }

解法三:“伸长分裂法”

解法分析:

  1. 遍历原链表。在原链表的每个结点的后面插入对应复制结点,将原链表“伸长”1倍;
  2. 遍历原链表。将复制结点的slibing连接好;
  3. 遍历原链表。将原结点和复制结点“分裂”开,将next连接好;
  4. 需要时间复杂度是O(n),空间复杂度是O(1)

参考代码如下

  
  
  
  
  1. /**
  2. * @param oHead
  3. * @return
  4. */
  5. public static Node copy3(Node oHead)
  6. {
  7. if (oHead == null)
  8. {
  9. return null;
  10. }
  11. // 1."伸长"
  12. for (Node oMove = oHead; oMove != null; oMove = oMove.next)
  13. {
  14. // 复制结点
  15. Node copy = new Node(oMove.val);
  16. // 插入复制结点到原结点的后面
  17. copy.next = oMove.next;
  18. oMove.next = copy;
  19. // 移动到复制结点处
  20. oMove = copy;
  21. }
  22. // 2.连接好slibing
  23. for (Node oMove = oHead; oMove != null; oMove = oMove.next)
  24. {
  25. if (oMove.slibing == null)
  26. {
  27. continue;
  28. }
  29. Node copy = oMove.next;
  30. copy.slibing = oMove.slibing.next;
  31. oMove = copy;
  32. }
  33. // 3."分裂",连接好原链表的next和复制链表中的next
  34. Node cHead = oHead.next;
  35. oHead.next = cHead.next;
  36. cHead.next = null;
  37. for (Node oMove = oHead.next, cMove = cHead; oMove != null; oMove = oMove.next, cMove = cMove.next)
  38. {
  39. Node copy = oMove.next;
  40. oMove.next = copy.next;
  41. copy.next = null;
  42. cMove.next = copy;
  43. }
  44. return cHead;
  45. }
  • 附:源码地址


来自为知笔记(Wiz)


你可能感兴趣的:([算法学习]复杂链表的复制)