经典算法-链表(golang)

type ListNode struct {
	Val int
	Next *ListNode
}

// 83. Remove Duplicates from Sorted List  删除有序链表中的重复元素
// 解题思路:相同的只改变指针指向,不同的才会移动当前的cur指针,cur作为当前判断的指针
// Input: 1->1->2			Output: 1->2
// Input: 1->1->2->3->3		Output: 1->2->3
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil {
		return head
	}
	cur := head		// cur指向头结点,而且改变cur指向不会影响到head的指向
	for cur.Next != nil {
		if cur.Val == cur.Next.Val {	// 当前节点的值等于下个节点的值
			cur.Next = cur.Next.Next	// cur指向下下个节点(cur指针不会移动)
		}else {	// 当前节点的值不等于下个节点的值
			cur = cur.Next		// 当前指针后移到下一个不同值的节点
		}
	}
	return head
}

// 876. Middle of the Linked List	找到链表的中间点
// 解题思路:快慢指针,从head开始跑,快指针结束时,返回慢指针
// Input: 1->2->3->4->5 	Output: 3
// Input: 1->2->3->4->5->6 	Output: 4
func middleNode(head *ListNode) *ListNode {
	slow, fast := head, head
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
	}

	return slow
}

// 206. Reverse Linked List   翻转链表
// 解题思路:将链表分为两个部分:第一个节点和剩余节点
//Input: 1->2->3->4->5->NULL	Output: 5->4->3->2->1->NULL
func reverseList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	var pre *ListNode
	cur := head
	for cur != nil {
		//pre, cur, cur.Next = cur, cur.Next, pre //这句话最重要
		nextNode := cur.Next	// 先保存cur后面的节点
		cur.Next = pre			// 将cur指向pre,pre刚开始为nil,就相当于最后一位
		pre = cur				// 这时cur是最新的整个需要被链接的部分,这时赋值给pre,pre就是每次要被cur链接的
		cur = nextNode			// 继续处理后面的节点
	}
	return pre
}

// 141. Linked List Cycle  	判断链表是否有环
// 解题思路:快慢指针,从head开始跑,快指针结束前,一直判断slow == fast
// Input: head = [3,2,0,-4], pos = 1 	Output: true
// Input: head = [1,2], 	 pos = 0 		Output: true
func hasCycle(head *ListNode) bool {
	if head == nil {
		return false
	}
	slow, fast := head, head
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
		if slow == fast {
			return true
		}
	}
	return false
}

// 237. Delete Node in a Linked List	删除某个节点
// 解题思路:相当于用下个节点来替换当前节点
// Input: head = [4,5,1,9], node = 5		Output: [4,1,9]
// Input: head = [4,5,1,9], node = 1 	Output: [4,5,9]
func deleteNode(node *ListNode) {
	node.Val = node.Next.Val
	node.Next = node.Next.Next
}

// 203. Remove Linked List Elements	删除所有等于这个值的节点
// 解题思路:注意如何删除头结点,所以需要额外创建一个节点p,指向头结点,头结点是第一结点,只是一般没有数据
// Input: 1->2->6->3->4->5->6, val = 6	Output: 1->2->3->4->5
func removeElements(head *ListNode, val int) *ListNode {
	p := &ListNode{-1, head}
	cur := p
	for cur.Next != nil {
		if cur.Next.Val == val {	// 只要等于val,都要跳过该节点,cur此时不会移动,因为下一次判断都是cur.Next
			cur.Next = cur.Next.Next
		}else {
			cur = cur.Next			// 不等的时候,cur后移一步
		}
	}
	return p.Next					// 不能return head, 因为head有可能就是要删除的节点
}

// 234. Palindrome Linked List	判断是否为回文链表
// 解题思路:找到中心点,如果中心点是奇数需要+1(不需要比较这个节点),然后将链表后半段翻转和前半段进行比较(后半段链表个数作循环条件)
// Input: 1->2			Output: false
// Input: 1->2->2->1	Output: true
func isPalindrome(head *ListNode) bool {
	dummyP, midP := head, head
	for dummyP != nil && dummyP.Next != nil {
		dummyP = dummyP.Next.Next
		midP = midP.Next
	}
	// 如果是奇数
	if dummyP != nil {
		midP = midP.Next
	}
	midP = reverseList(midP)
	for midP != nil {
		if head.Val == midP.Val {
			head, midP = head.Next, midP.Next
			continue
		}
		return false
	}
	return true
}

// 160. Intersection of Two Linked Lists	找到两个链表(没有环)的交叉点
// 解题思路:不能使用暴力破解法,循环遍历A,B。 应该两个指针一起走,短链表先到达终点,从那一刻开始算,长链表继续走直到终点同时长链表的头指针也在走,
// 等到终点的时候,长短链表的长度一样了,最后循环判断他们,只要有一个节点相等就ok了
// Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
// Output: Reference of the node with value = 8
func getIntersectionNode(headA, headB *ListNode) *ListNode {
	curA, curB := headA, headB
	for curA != nil && curB != nil {
		curA = curA.Next
		curB = curB.Next
	}
	for curA != nil {
		curA = curA.Next
		headA = headA.Next
	}
	for curB != nil {
		curB = curB.Next
		headB = headB.Next
	}
	for headA != headB {
		headA = headA.Next
		headB = headB.Next
	}
	return headA
}

// 19. Remove Nth Node From End of List		删除倒数第n个节点
// 解题思路: 定义快慢指针,快的先走n步,然后快慢再一起走,直到快指针Next为空, 记得返回的是p.Next而不是head,因为head也有可能被删
// input: list: 1->2->3->4->5, and n = 2
// Output: 1->2->3->5
func removeNthFromEnd(head *ListNode, n int) *ListNode {
	p := &ListNode{-1, head}
	slow, fast := p, p
	for ; n > 0; n-- {
		fast = fast.Next
	}
	for fast.Next != nil {
		slow = slow.Next
		fast = fast.Next
	}
	slow.Next = slow.Next.Next
	return p.Next

}

// 142. Linked List Cycle II	找到链表中环的起点
// 解题思路:使用额外内存map,将链表的节点存进map,判断如果有相同的点,则返回节点(即为环的起点)
func detectCycle(head *ListNode) *ListNode {
	m := make(map[*ListNode]int)
	cur := head
	for ; cur != nil; cur = cur.Next {
		if _, ok := m[cur]; ok {
			return cur
		}
		m[cur] = 1
	}
	return nil
}

// 148. Sort List	链表排序
// 解题思路(需要额外内存):使用额外内存slice,将链表的节点存进slice,然后sort.Ints排序后,再回写到链表
func sortList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	var list []int
	cur, cur1 := head, head
	for cur != nil {
		list = append(list, cur.Val)
		cur = cur.Next
	}
	sort.Ints(list)
	for _, v := range list {
		cur1.Val = v
		cur1 = cur1.Next
	}
	return head

}


// 148. Sort List	链表排序
// 解题思路(不需要额外内存):分治法-归并排序,需要用到递归
func sortList(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	var pre *ListNode
	slow, fast := head, head
	for fast != nil && fast.Next != nil {
		pre = slow
		slow, fast = slow.Next, fast.Next.Next
	}
	pre.Next = nil  // 中间截断,slow的前面一个节点作为head的结束点
	l := sortList(head)
	r := sortList(slow)
	return func (l, r *ListNode) *ListNode {
		list := &ListNode{}
		cur := list
		for l != nil && r != nil {
			if l.Val <= r.Val {
				cur.Next = l
				l = l.Next
			}else {
				cur.Next = r
				r = r.Next
			}
			cur = cur.Next
		}
		if l == nil {
			cur.Next = r
		}
		if r == nil {
			cur.Next = l
		}
		return list.Next
	}(l, r)
}

func mergeList(l, r *ListNode) *ListNode {
	list := &ListNode{}
	cur := list
	for l != nil && r != nil {
		if l.Val <= r.Val {
			cur.Next = l
			l = l.Next
		}else {
			cur.Next = r
			r = r.Next
		}
		cur = cur.Next
	}
	if l == nil {
		cur.Next = r
	}
	if r == nil {
		cur.Next = l
	}
	return list.Next

}


// 21. Merge Two Sorted Lists	合并两个有序链表
// 解题思路:新创建一个结构体,比较l1和l2大小,赋值给cur.Next,然后都后移一步
// Input: 1->2->4, 1->3->4
// Output: 1->1->2->3->4->4
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	head := &ListNode{}
	cur := head
	for 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
	}
	if l1 == nil && l2 != nil {
		cur.Next = l2
	}
	if l1 != nil && l2 == nil {
		cur.Next = l1
	}
	return head.Next
}

// 23. Merge k Sorted Lists 合并k个有序链表
// 解题思路:使用额外内存slice,遍历将链表的节点存进slice,然后sort.Ints排序后,再回写到链表
/*Input:
 [
	1->4->5,
	1->3->4,
	2->6
 ]
Output: 1->1->2->3->4->4->5->6
*/
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	var sliceList []int
	for _, v := range lists {
		for v != nil {
			sliceList = append(sliceList, v.Val)
			v = v.Next
		}
	}
	if sliceList == nil {
		return nil
	}
	sort.Ints(sliceList)
	head := &ListNode{}
	cur := head
	for k, v := range sliceList {
		cur.Val = v
		if k + 1 == len(sliceList) {
			cur.Next = nil
		}else {
			cur.Next = &ListNode{}
			cur = cur.Next
		}
	}
	return head
}

  

转载于:https://www.cnblogs.com/huangliang-hb/p/10855558.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值