美文网首页
反转链表之递归

反转链表之递归

作者: 追风骚年 | 来源:发表于2021-02-28 13:40 被阅读0次

递归的写法总是使人眼前一亮,总是让人满口称赞,正常也写不出那么优美的递归。

递归首先一点需要明确递归函数的定义(函数作用、参数、返回值)和递归的出口。

labuladong 一直在强调不要跳进递归,不要跳进递归。因为人脑是思考不了那么复杂的堆栈逻辑,人脑擅长高屋建瓴去思考函数定义,而不是底层逻辑。

反转整个链表

// 反转整个链表
func reverseAll(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }

    // 继续反转下个节点
    newHead := reverseAll(head.Next)
    // 递归调用到最后,最后一个节点就是新的头结点

    //【1】 1 -> 2 -> 3 -> 4 -> 5
    //【2】 1 <-> 2 <- 3 <- 4 <- 5
    //【3】 nil <-1 <- 2 <- 3 <- 4 <- 5
    head.Next.Next = head // 这里 head 还是当前节点, head.Next => 2 ,让 2 的next 指向 当前节点 1
    head.Next = nil       // 切断当前节点的下个指针
    return newHead
}

func TestReverseAll(t *testing.T) {
    t.Log(reverseAll(GenerateLists(1, 2, 3, 4)))
}

反转链表前 K 个节点

func reverseK(head *ListNode, k int) *ListNode {
    var lastNext *ListNode // 头节点的下个节点需要记住,否则后面连不起来
    var reverse func(head *ListNode, k int) *ListNode
    reverse = func(head *ListNode, k int) *ListNode {
        if k == 1 {
            lastNext = head.Next
            return head
        }

        last := reverse(head.Next, k-1)

        head.Next.Next = head
        head.Next = lastNext // 和 reverseAll 的区别在于 这里的 head 指针指向上面切断节点
        return last
    }
    return reverse(head, k)
}

func TestReverseK(t *testing.T) {
    t.Log(reverseK(GenerateLists(1, 2, 3, 4, 5), 3))
}

反转链表 M 到 N 个节点

func reverseMN(head *ListNode, m, n int) *ListNode {
    if m == 1 {
        return reverseK(head, n) //
    }

    head.Next = reverseMN(head.Next, m-1, n-1)
    return head
}

func TestReverseMN(t *testing.T) {
    t.Log(reverseMN(GenerateLists(1, 2, 3, 4, 5, 6, 7), 2, 4))
}

我的辅助函数


// ListNode ListNode
type ListNode struct {
    Val  int
    Next *ListNode
}

func (head *ListNode) String() string {
    cur := head

    arr := []string{}
    for cur != nil {
        arr = append(arr, strconv.Itoa(cur.Val))
        cur = cur.Next
    }
    return strings.Join(arr, ",")
}

// GenerateList GenerateList
func GenerateList(arr []int) *ListNode {
    head := &ListNode{
        Val: -1,
    }

    current := head
    for i := 0; i < len(arr); i++ {
        current.Next = &ListNode{
            Val: arr[i],
        }
        current = current.Next
    }

    return head.Next
}

// GenerateLists GenerateLists
func GenerateLists(arr ...int) *ListNode {
    return GenerateList(arr)
}

相关文章

  • Algorithm小白入门 -- 单链表

    单链表递归反转链表k个一组反转链表回文链表 1. 递归反转链表 单链表节点的结构如下: 1.1 递归反转整个单链表...

  • 链表反转

    循环反转链表 递归反转链表

  • 单链表反转

    单链表 单链表反转 递归方法

  • 反转链表(java实现)

    链表反转 节点数据结构如下: 链表反转的两种方式:递归和非递归 递归方式如下: 非递归方式如下:

  • leecode刷题(22)-- 反转链表

    leecode刷题(22)-- 反转链表 反转数组 反转一个单链表。 示例: 进阶:你可以迭代或递归地反转链表。你...

  • 数据结构专题:1.单向链表反转与排序

    有如下单向链表 1.单向链表反转,递归 递归的方式其实是从尾节点开始进行指针反转,最终递归反转到头节点 2.单向链...

  • 初级算法-链表-反转链表

    给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 进阶:链表可以选用迭代或递归方式完成反转。你能...

  • 反转链表之递归

    递归的写法总是使人眼前一亮,总是让人满口称赞,正常也写不出那么优美的递归。 递归首先一点需要明确递归函数的定义(函...

  • 链表相关的题

    单向链表反转 如1->2->3->4,反转成4->3->2->1反转链表有2种做法,递归和循环。递归写法: 循环写...

  • 链表反转

    反转类型问题是面试中的常见问题。如反转字符串,反转链表等,今天给出利用递归和非递归方法解决反转链表问题的两个解决思...

网友评论

      本文标题:反转链表之递归

      本文链接:https://www.haomeiwen.com/subject/fzrgfltx.html