type LikedList struct{
Val int
Next *LikedList
}
// 头插法,倒置单链表
func reverseLikedList(head *LikedList)*LikedList{
if(head == nil || head.Next == nil){
return head
}
var pre, next *LikedList
// head是当前节点,pre是当前节点的前一个几点,next是当前节点的后一个节点
for head != nil { // 当前节点不为空
next = head.Next // 备份head.Next(指向当前节点的下一个节点),防止移动节点时找不到后置节点
head.Next = pre // 更新head.Next,后一个节点指向前一个(翻转)
pre = head // 前一个节点后移
head = next // 当前节点后移
}
return pre // 注意:当pre指向原链表的最后一个节点时,head已经指向最后一个节点的Next即空节点,所以这里应返回pre
}
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseBetween(head *ListNode, m int, n int) *ListNode {
changeLen := n - m 1 // 计算需要逆置的节点个数
var pre *ListNode = nil // 初始化开始逆置的节点的前驱
var result *ListNode = head // 最终转换后的链表的头结点,非特殊情况即为head
move := m - 1 // head向后移动m-1个位置指向第m个节点
for(head != nil && move > 0){ // 将head后移m-1个位置,即
pre = head // for循环后pre指向第m个节点的前驱节点
head = head.Next // for循环后head指向第m个节点
move--
}
var reversedListTail *ListNode = head // 此时reversedListTail指向的是第m个节点,该节点即是链表片段反转后的尾节点
var reversedListHead *ListNode = nil // 记录链表片段反转后的头结点
for(head != nil && changeLen > 0){ // 逆置changeLen个节点
next := head.Next // 暂存当前节点的下一个节点
head.Next = reversedListHead // 当前节点的Next指针域指向新开辟的反转后的头结点
reversedListHead = head // 反转后的链表的头结点后移一个位置
head = next // 当前节点后移一个节点
changeLen-- // 每完成一个节点逆置,changLen--
}
reversedListTail.Next = head // 连接逆置后的链表尾与逆置段的后一个节点,翻转后的尾节点指向第n个节点的下一个节点
if(pre != nil){ // 如果pre不为空,说明不是从第1个节点开始逆置的,即m > 1
pre.Next = reversedListHead // 将逆置链表开始的节点前驱与逆置后的头结点连接起来
}else{ // 如果pre为空,说明m=1,即从第1个节点开始逆置,结果即为逆置后的头结点
result = reversedListHead
}
return result
}
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
var lenA, lenB int // 分别记录链表headA和链表headB的长度
lenA = getListLength(headA)
lenB = getListLength(headB)
if lenA > lenB {
headA = forwardDeltaLenNode(lenA, lenB, headA) // headA链表的头结点指向移动多出的节点个位置后
}else{
headB = forwardDeltaLenNode(lenB, lenA, headB) // 如果链表headB长,移动其头结点到相应位置
}
for headA != nil && headB != nil { // 没有到达链表末尾
if(headA == headB){ // 当前两个链表的节点相同,即指向同一个节点,说明找到的交点;否则,两链表同时后移
return headA
}
headA = headA.Next
headB = headB.Next
}
return nil // 遍历到链表末尾还没有找到同一个节点,说明两链表没有交点
}
// 逐个节点遍历,获取链表长度
func getListLength(head *ListNode)int{
var lengthList int
for head != nil {
lengthList
head = head.Next
}
return lengthList
}
// 较长链表移动 长链表长度-短链表长度 个节点后对应的头指针
// 参数longLen和shortLen分别表示长链表和短链表的长度,longList对应长链表
func forwardDeltaLenNode(longLen, shortLen int, longList *ListNode)*ListNode{
deltaLen := longLen - shortLen
for longList != nil && deltaLen != 0{
longList = longList.Next
deltaLen--
}
return longList // 如果longList为nil或者deltaLen=0直接返回此时的头结点longList
}
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func partition(head *ListNode, x int) *ListNode {
//var preHead, postHead *ListNode // 前后两部分链表的头结点,不能这么声明,这样声明的话两者都为&ListNode{0, nil}其中Next域为nil,当运行到prePtr.Next = head时会报panic: runtime error:invalid memory address or nil pointer deference错误
preHead := &ListNode{0, nil} // 生成一个preHead链表的头结点,该节点固定一直不对其移动,改头节点的Val为多少都不影响结果,因为使用的是头结点的Next节点
postHead := &ListNode{0, nil} // 生成一个postHead链表的头结点,该节点固定不动
prePtr := preHead // prePtr指针对preHead链表进行遍历,注意:开始时其指向preHead
postPtr := postHead
for head != nil { // 遍历原链表
if(head.Val < x ){ // 小于x的节点尾插到preHead链表后面
prePtr.Next = head // prePtr的Next域指向当前节点,即将当前节点从preHead链表尾部prePtr依次插入
prePtr = head // prePtr指针后移一位,指向当前节点
}else{ // 大于等于x的节点放在postHead链表的后面
postPtr.Next = head // 将当前节点插入到postHead链表尾节点postPtr后面
postPtr = head // postHead链表的尾节点后移一位
}
head = head.Next // 当前指针后移一位
}
// 对head链表遍历结束分为preHead和postHead两个子链表
prePtr.Next = postHead.Next // 注意:这里是将preHead链表的尾节点prePtr的Next域指向postHead链表头结点的下一个节点
postPtr.Next = nil // postPtr的尾节点的Next域指向空
return preHead.Next // 返回preHead链表的Next之后的链表
}
END 十期推荐 【251期】面试官:谈谈你对零拷贝的理解~ 【252期】运行时常量池的一道面试题(JDK8环境) 【253期】面试官:熟悉Docker操作吗?说几个常用的Docker命令吧 【254期】面试官:来谈谈微服务组件Feign的工作原理吧 【255期】面试官:Mybatis是如何运用设计模式的? 【256期】面试官常考的 21 条 Linux 命令 【257期】面试官:谈谈你对Java线程安全与不安全的理解 【258期】今日头条的面试题:LRU原理和Redis实现 【259期】面试官:Spring事务失效的场景有哪些?如何解决? 【260期】Java线程池,这篇能让你和面试官聊了半小时 ? ~