抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

3.1 删除单向链表倒数第n个节点

LeetCode No.19

问题描述:删除单向链表倒数第n个节点(只遍历一次)
Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

思路:两个指针,p1先走n步,然后p1和p2再一起走,当p1到链表结尾,p2就是要删除的节点。注意处理可能删除的是头结点(n=length)或者不需要删除(n>length)的情况。
可以通过增加一个虚拟的头节点,避免对头节点的特殊处理。

示例代码

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    p1, p2 := head, head
    i := 0
    for ; i < n && p1 != nil ; i++ {
        p1 = p1.Next
    }
    if p1 == nil {
        if i < n {
            // 不需要删除
            return head
        } else {
            // 删除头节点
            return head.Next
        }
    }
    for p1.Next != nil {
        p1 = p1.Next
        p2 = p2.Next
    }
    t := p2.Next
    if t != nil {
        p2.Next = t.Next
    }
    return head
}

3.2 K个一组翻转链表

LeetCode No.25

题目描述:给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

思路: 先遍历一遍求出链表长度n,则需要翻转n/k组。使用一个虚拟头节点保存结果,每一轮翻转完将尾节保存,下一轮翻转结束后将上一轮的为节点的Next节点指向当前轮的头结点。

示例代码:

func reverseKGroup(head *ListNode, k int) *ListNode {
    n := 0
    for p := head; p != nil; p = p.Next {
        n++
    }
    reshead := &ListNode{}
    var lasttail *ListNode
    for i, p := 0, head; i <= n/k; i++ {
        if i == n / k {
            lasttail.Next = p
            break
        }
        curhead, curtail := p, p
        for j := 0; j < k; j++ {
            tmp := p
            p = p.Next
            tmp.Next = curhead
            curhead = tmp
        }
        if i == 0 {
            reshead.Next = curhead
        } else {
            lasttail.Next = curhead
        }
        lasttail = curtail
    }
    return reshead.Next
}

评论