题目:指定区间反转
题目链接:LeetCode-92. 反转链表 II
解决方法
源码地址:GitHub-golang版本
方法1:头插法
思路分析
- 找到left左边的元素,保持不动(作为反转虚拟头结点),注意这里需要新创建一个节点newNode指向head,再逐步移动到left前(因为可能left是1,则虚拟头结点就是直接指向head的)
- 从left向后依次取下一个节点,插入到虚拟头结点后面,每次操作都相当于left结点向后走,直到占到right元素的位置
- 因为left元素每次去掉后面的元素,都是连接它.next.next,所以反转完之后,自然left是指向原来right元素的下一个的,所以该链表现在已经正确了
- return newNode.Next
Go代码
func reverseBetween(head *ListNode, left int, right int) *ListNode {
if head == nil || head.Next == nil {
return head
}
newlist := &ListNode{}
newlist.Next = head
pre := newlist
tmp := head
for i:=1; i<left; i++{
pre = pre.Next
tmp = tmp.Next
}
for i:=0; i<right-left; i++{
next := tmp.Next
tmp.Next = tmp.Next.Next
next.Next = pre.Next
pre.Next = next
}
return newlist.Next
}
方法2:穿针引线法
思路分析
- 将该链表分成3段,left前,反转区间,right后,反转完中间之后,穿针引线起来
- 所以需要变量结点存储(为了之后穿针引线):left前的位置、right后的位置
- 在反转区间,进行一次链表反转即可(这里有三种方式:虚拟头插法、自我反转、递归反转)
Go代码
func reverseLink(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
tmp := head
newlist := reverseLink(tmp.Next)
tmp.Next.Next = tmp
tmp.Next = nil
return newlist
}
func reverseBetween2(head *ListNode, left int, right int) *ListNode {
if head == nil || head.Next == nil {
return head
}
newlist := &ListNode{}
newlist.Next = head
pre := newlist
for i:=1; i<left; i++{
pre = pre.Next
}
tmp := pre.Next
leftNode := tmp
for i:=0; i<right-left; i++{
tmp = tmp.Next
}
rightAferNode := tmp.Next
tmp.Next = nil
nleft := reverseLink(leftNode)
leftNode.Next = rightAferNode
pre.Next = nleft
return newlist.Next
}