创建时间: 2019/7/22 13:13
作者: sunpengwei1992@aliyun.com

问题

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例

输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4

解法一

看到这个题目,最直观的是什么?排序嘛,对不,我们将链表转化为数组,直接排序,最后组装一个新的链表,完事,因为两个链表本身 就是有序的,所以转化后的数组就是有序的,我们只需要依次比较两个数组,如下图:

链表-合并两个有序链表,O(1)空间复杂度可否? - 图1

  1. type ListNode struct {
  2. Val int
  3. Next *ListNode
  4. }
  5. func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
  6. //声明三个切片
  7. slice1 := make([]int,0)
  8. slice2 := make([]int,0)
  9. slice3 := make([]int,0)
  10. //将链表转换为数组
  11. for l1 != nil{
  12. slice1 = append(slice1,l1.Val)
  13. l1 = l1.Next
  14. }
  15. for l2 != nil{
  16. slice2 = append(slice2,l2.Val)
  17. l2 = l2.Next
  18. }
  19. //开始依次比较,这里一定注意切片越界
  20. i,j := 0,0
  21. for i<len(slice1) && j <len(slice2){
  22. if slice1[i] <= slice2[j] {
  23. slice3 = append(slice3,slice1[i])
  24. i++
  25. }else{
  26. slice3 =append(slice3,slice2[j])
  27. j++
  28. }
  29. }
  30. //将切片剩余的值补充上去后面
  31. for i<len(slice1){
  32. slice3 = append(slice3,slice1[i])
  33. i++
  34. }
  35. for j<len(slice2){
  36. slice3 = append(slice3,slice2[j])
  37. j++
  38. }
  39. //将最终排好序的数组转换为链表进行返回
  40. var head,result *ListNode = nil,nil
  41. for _,v := range slice3{
  42. if head == nil{
  43. head = &ListNode{v,nil}
  44. result = head
  45. continue
  46. }
  47. head.Next = &ListNode{v,nil}
  48. head = head.Next
  49. }
  50. return result
  51. }

上面代码我们可以看出申请了三个切片空间,其空间复杂度为O(n),在链表长度比较大的情况下,占用的额外空间回比较大,那怎么优化呢?

解法二

上面的解法一,我们申请了存放链表元素的数组空间,空间复杂度是O(n),那么不转数组行不?O(1)的空间复杂度可以完成吗,能不转数组吗?直接根据链表来比较,这样就不要用消耗内存空间了,我们一起尝试一下?如下图

链表-合并两个有序链表,O(1)空间复杂度可否? - 图2

  1. type ListNode struct {
  2. Val int
  3. Next *ListNode
  4. }
  5. func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
  6. //如果l1是nil,直接返回l2,因为链表本身是有序的
  7. if l1 == nil{
  8. return l2
  9. }
  10. //如果l2是nil,直接返回l2,因为链表本身是有序的
  11. if l2 == nil{
  12. return l1
  13. }
  14. //声明两个指针变量
  15. temp := &ListNode{-1,nil}
  16. result := temp
  17. for l1 != nil && l2 != nil{
  18. if l1.Val < l2.Val{ // l1链接
  19. n1 := l1
  20. temp.Next = n1
  21. temp = temp.Next
  22. l1 = l1.Next
  23. }else{ // l2链接
  24. n2 := l2
  25. temp.Next = n2
  26. temp = temp.Next
  27. l2 = l2.Next
  28. }
  29. }
  30. //补全剩余的链表
  31. if l1 == nil {
  32. temp.Next = l2
  33. }
  34. if l2 == nil {
  35. temp.Next = l1
  36. }
  37. return result.Next
  38. }

解法三

递归法,代码简单,感兴趣的了解一下,理解为最终要合并的两个链表长度一个为1,一个为0,满足递归终止条件。

  1. type ListNode struct {
  2. Val int
  3. Next *ListNode
  4. }
  5. func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
  6. //如果l1是nil,直接返回l2,因为链表本身是有序的
  7. if l1 == nil{
  8. return l2
  9. }
  10. //如果l2是nil,直接返回l2,因为链表本身是有序的
  11. if l2 == nil{
  12. return l1
  13. }
  14. if l1.Val < l2.Val{
  15. //将l1的next节点指向为l2,也就是将大的挂在小的后面
  16. l1.Next = mergeTwoLists(l1.Next,l2)
  17. return l1
  18. }else{
  19. //将l2的next节点指向为l1,也就是将大的挂在小的后面
  20. l2.Next = mergeTwoLists(l2.Next,l1)
  21. return l2
  22. }
  23. }

欢迎大家关注微信公众号:“golang那点事”,更多精彩期待你的到来
GoLang公众号.jpg