leetcode 21 合并两个有序链表
题解分析: 分别遍历2个有序链表,创建一个新的链表,遍历的时候进行比较,谁小就加入新的链表,这个题目主要就是需要你自己加一个虚拟头节点,也就是代码中的res,这样最后输出就会简单很多
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
head := &ListNode{}
res := &ListNode{}
res = head
for l1 != nil && l2 != nil {
if l1.Val > l2.Val {
head.Next = l2
l2 = l2.Next
}else {
head.Next = l1
l1 = l1.Next
}
head = head.Next //这里不要忘记了
}
if l1 == nil {
head.Next = l2
}
if l2 == nil {
head.Next = l1
}
return res.Next
}
23. 合并K个升序链表
题解分析:这里我们用到了归并的一种思想(可以先去看看归并排序,这样理解的更清楚)。
我们可以先将整个数组merge来进行划分,分完后再进行合并,这个时候我们可以发现合并不就是和上面的题目的要求是一样的吗?这个时候我们直接引用上面的mergeTwoLists来进行合并。(先把归并排序搞懂就直接明白了)
需要注意的是写递归的时候一定一定要注意递归终止的条件。
func mergeKLists(lists []*ListNode) *ListNode {
if lists == nil || len(lists) == 0 {
return nil
}
return merge(lists,0,len(lists)-1)
}
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
head := &ListNode{}
res := &ListNode{}
res = head
for l1 != nil && l2 != nil {
if l1.Val > l2.Val {
head.Next = l2
l2 = l2.Next
}else {
head.Next = l1
l1 = l1.Next
}
head = head.Next //这里不要忘记了
}
if l1 == nil {
head.Next = l2
}
if l2 == nil {
head.Next = l1
}
return res.Next
}
//将数组进行划分
func merge(l []*ListNode,left int,right int) *ListNode {
if left == right { //这里很容易漏
return l[left]
}
if left > right{
return nil
}
mid := (left + right) / 2
leftNode:=merge(l,left,mid)
rightNode:=merge(l,mid+1,right)
return mergeTwoLists(leftNode,rightNode)
}
141. 环形链表
题解分析:就像一个操场,如果有环的话,一个人跑的快,一个慢,那么肯定会相遇,我们设置2个不同速度的节点,就可以知道有没有环。
func hasCycle(head *ListNode) bool {
slow, fast := head, head
for fast != nil && fast.Next !=nil{ // 快指针指向真实节点
slow, fast = slow.Next, fast.Next.Next // 慢的走一步 快的走两步
if slow == fast { // 快慢指针相遇,有环
return true
}
}
return false // fast走出去了,没有环
}
142. 环形链表 II
解题思路:
在相遇的时候我让慢指针从相遇点走,再让head从开始走,那么当他们相遇的时候,就到了环的起始的位置。 (图片是从leetcode里面截取的)
func detectCycle(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return nil
}
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
break
}
}
if fast == nil || fast.Next == nil {
return nil
}
tmp := head
for tmp != slow {
tmp = tmp.Next
slow = slow.Next
}
return tmp
}
876. 链表的中间结点
题解分析:这道题还是只使用快慢指针,比较简单,但是需要注意的是当链表只有一个元素的时候,返回的是这个元素。
func middleNode(head *ListNode) *ListNode {
if head == nil{ //注意这里就好
return nil
}
fast := head
slow := head
for fast != nil && fast.Next != nil {
fast = fast.Next.Next
slow = slow.Next
}
return slow
}
160. 相交链表
题解思路: 开两个指针分别遍历这两个链表,在第一次遍历到尾部的时候,指向另一个链表头部继续遍历,这样会抵消长度差。
如果链表有相交,那么会在中途相等,返回相交节点;
如果链表不相交,那么最后会 nil == nil,返回 nil;
func getIntersectionNode(headA, headB *ListNode) *ListNode {
a, b := headA, headB
for a != b {
if a == nil {
a = headB
} else {
a = a.Next
}
if b == nil {
b = headA
} else {
b = b.Next
}
}
return a
}
19. 删除链表的倒数第 N 个结点
解题思路: 双指针,一个在前,一个在后,前面的先走N步,然后两个指针一起往后走每次一步,直到 first 走成nil也就是到尾巴了。
那么要删除的就是 slow.Next 所以我们只要让 slow.Next = slow.Next.Next 就行了
func removeNthFromEnd(head *ListNode, n int) *ListNode {
newHead := &ListNode{
Next: head,
}
slow,fast := newHead,newHead
for i:=0;i<n;i++{
fast = fast.Next
}
for fast.Next!=nil{
fast = fast.Next
slow = slow.Next
}
slow.Next = slow.Next.Next
return newHead.Next
}
剑指 Offer 24. 反转链表
题解思路: 这道题递归建议去leetcode看看有图示的解法,迭代解法只需要我们
递归解法:只需要我们拿出一张纸,自己话一遍就OK了
func reverseList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
last := reverseList(head.Next)
head.Next.Next = head
head.Next = nil
return last
}
迭代解法:
func reverseList(head *ListNode) *ListNode {
var prev *ListNode //最前节点
curr := head
for curr != nil {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}
return prev
}
92. 反转链表 II
题解分析: 这道题比较困难,可以这样理解,当左边为1的时候,解法是什么样的?然后再使用递归来进行题解。
func reverseBetween(head *ListNode, left int, right int) *ListNode {
if left == 1 {
return reverse(head,right)
}
head.Next = reverseBetween(head.Next,left-1,right-1)
return head
}
//这不就是反转从开始到指定位置的函数吗?
var success *ListNode
func reverse(head *ListNode,n int) *ListNode {
if n == 1 {
success = head.Next
return head
}
last := reverse(head.Next,n-1)
head.Next.Next = head
head.Next = success
return last
}
25. K 个一组翻转链表
func reverseKGroup(head *ListNode, k int) *ListNode {
if head == nil {
return nil
}
a := head
b := head
for i := 0; i < k; i ++ {
if b == nil {
return head
}
b = b.Next
}
newHead := reverse(a,b)
a.Next = reverseKGroup(b,k)
return newHead
}
//反转从 head 到right 的链表
func reverse (head *ListNode,right *ListNode) *ListNode {
pre := &ListNode{}
cur := head
nxt := head
for cur != right {
nxt = cur.Next
cur.Next = pre
pre = cur
cur = nxt
}
return pre
}
234. 回文链表
解题思路:
我们使用快慢指针,找到链表的中间节点,然后将后半部分进行反转链表,之后再进行比较。
func isPalindrome(head *ListNode) bool {
if head == nil {
return false
}
fast := head
slow := head
//找到中间节点
for fast != nil && fast.Next != nil {
fast = fast.Next.Next
slow = slow.Next
}
slow = reserve(slow)
for slow != nil {
if head.Val != slow.Val {
return false
}
head = head.Next
slow = slow.Next
}
return true
}
//递归反转链表
func reserve(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
last := reserve(head.Next)
head.Next.Next = head
head.Next = nil
return last
}
203. 移除链表元素
题解思路: 这道题不难,主要是为了联系递归。
func removeElements(head *ListNode, val int) *ListNode {
if head == nil {
return head
}
head.Next = removeElements(head.Next,val)
if(head.Val == val){
return head.Next;
} else {
return head;
}
}