前端尝试转GO学习(第四天)
把学到的知识应用到真实的解题当中。
对于链表,我们每次只分配出一个节点(node) 的内存。链表使用指针将各个节点组合到一起,这样就形成了一个连一个的链式的结构,这就是链表(Linked List)这个名称的由来。链表的每个节点都有两个部分:数据区和指针区。前者用来存储数据,后者用来存储指向下一个节点的指针。
234. 回文链表
先通过快慢指针找到中点,进行翻转,分为 left,right。通过对比,进行两个链表之间的对比,判断是否是回文链表。
func isPalindrome(head *ListNode) bool {
if head == nil || head.Next == nil {
return true
}
slow, fast := head, head
var prev *ListNode = nil
for fast != nil && fast.Next != nil {
prev = slow
slow = slow.Next
fast = fast.Next.Next
}
prev.Next = nil // 断开
// 翻转
var head2 *ListNode = nil
for slow != nil {
tmp := slow.Next
slow.Next = head2
head2 = slow
slow = tmp
}
// 比对
for head != nil && head2 != nil {
if head.Val != head2.Val {
return false
}
head = head.Next
head2 = head2.Next
}
return true
}
206. 反转链表
提供两个指针 pre cur 前指针 当前指针。每次把当前 cur 指针指向上一个 pre。保存下一个节点信息。
一开始把哨兵节点设置为 null,cur 设置为 head。一直迭代下去,直到 cur 当前节点为尾节点。
func reverseList(head *ListNode) *ListNode {
var pre *ListNode = nil
var cur = head
for (cur != nil) {
var temp = cur.Next
cur.Next = pre
pre = cur
cur = temp
}
return pre
}
23. 合并K个升序链表
func mergeKLists(lists []*ListNode) *ListNode {
// 分治
lenth := len(lists)
if lenth < 1 {
return nil
}
if lenth == 1 {
return lists[0]
}
num := lenth / 2
left := mergeKLists(lists[:num])
right := mergeKLists(lists[num:])
return mergeTwoList(left, right)
}
func mergeTwoList(l1, l2 *ListNode ) *ListNode {
head := &ListNode{}
cur := head
for l1 != nil || l2 != nil {
if l1 != nil && l2 != nil {
if l1.Val < l2.Val {
cur.Next = l1
l1 = l1.Next
} else {
cur.Next = l2
l2 = l2.Next
}
cur = cur.Next
} else if l1 != nil {
cur.Next = l1
break
} else {
cur.Next = l2
break
}
}
return head.Next
}
25. K 个一组翻转链表
func reverseKGroup(head *ListNode, k int) *ListNode {
hair := &ListNode{Next: head}
pre := hair
for head != nil {
tail := pre
for i := 0; i < k; i++ {
tail = tail.Next
if tail == nil {
return hair.Next
}
}
nex := tail.Next
head, tail = myReverse(head, tail)
pre.Next = head
tail.Next = nex
pre = tail
head = tail.Next
}
return hair.Next
}
func myReverse(head, tail *ListNode) (*ListNode, *ListNode) {
prev := tail.Next
p := head
for prev != tail {
nex := p.Next
p.Next = prev
prev = p
p = nex
}
return tail, head
}
141. 环形链表
假设有a和b两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合的。
func hasCycle(head *ListNode) bool {
fast, slow := head, head
for slow != nil && fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if (slow == fast) {
return true
}
}
return false
}
148. 排序链表
寻找链表的中点,将链表拆分成两个链表。寻找链表的中点可以使用快慢指针,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。对两个拆分处理的链表分别排序。将两个排序后的子链表合并,得到完整的排序后的链表。
func merge(head1, head2 *ListNode) *ListNode {
dummyHead := &ListNode{}
temp, temp1, temp2 := dummyHead, head1, head2
for temp1 != nil && temp2 != nil {
if temp1.Val <= temp2.Val {
temp.Next = temp1
temp1 = temp1.Next
} else {
temp.Next = temp2
temp2 = temp2.Next
}
temp = temp.Next
}
if temp1 != nil {
temp.Next = temp1
} else if temp2 != nil {
temp.Next = temp2
}
return dummyHead.Next
}
func sort(head, tail *ListNode) *ListNode {
if head == nil {
return head
}
if head.Next == tail {
head.Next = nil
return head
}
slow, fast := head, head
for fast != tail {
slow = slow.Next
fast = fast.Next
if fast != tail {
fast = fast.Next
}
}
mid := slow
return merge(sort(head, mid), sort(mid, tail))
}
func sortList(head *ListNode) *ListNode {
return sort(head, nil)
}
160. 相交链表
当双指针同时从出发点出发后,同时回到出发点,双指针还没有相遇,那么就说明这其中没有相交的结点。反之,则存在相交节点。
func getIntersectionNode(headA, headB *ListNode) *ListNode {
pointA := headA
pointB := headB
for pointA != nil || pointB != nil {
if (pointA == pointB) {
return pointA
}
if (pointA != nil) {
pointA = pointA.Next
} else {
pointA = headA
}
if (pointB != nil) {
pointB = pointB.Next
} else {
pointB = headB
}
}
return nil
}