目录
文章目录
一、常用函数
package main
import (
"fmt"
)
/**
golang实现单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
链表中的数据以节点来表示,每个节点的构成:元素(数据元素的映像)+ 指针(指向后继元素存储位置)。
元素是存储数据的存储单元,指针是连接每个节点的地址数据。
节点结构:
|--data--|--next--|
data域存放节点值的数据域,next域存放节点的直接后继地址(位置)的指针域(链域)
头指针head和终端节点
单链表中每个几点的存储地址是存放在其前趋节点next域中。而开始节点无前趋,所以应该设置头指针head指向开始节点。
链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端节点无后继,所以终端节点的指针域为空,即NULL。
*/
type Node struct {
// 值
Data interface{}
// 后继节点指针
Next *Node
}
// 链表是否为空
func IsEmpty(node *Node) bool {
return node== nil
}
// 是否是最后一个节点
func IsLast(node *Node) bool {
return node.Next == nil
}
// 查找指定节点的前一个节点
func FindPrevious(data interface{}, node *Node) *Node {
tmp := node
for tmp!=nil && tmp.Next != nil && tmp.Next.Data != data {
tmp = tmp.Next
}
return tmp
}
// 查找某个值在哪个节点
func Findx(data interface{},node *Node) *Node {
p := node
for ;p != nil;p=p.Next {
if(p.Data == data) {
return p
}
}
return nil
}
// 查找某个值在哪个节点
func Find(data interface{}, node *Node) *Node {
tmp := node
for tmp!=nil && tmp.Data != data {
tmp = tmp.Next
}
return tmp
}
// 插入节点:在指定节点插入节点
/**
position:指定的节点位置
*/
func Insert(data interface{}, position *Node) {
// 新建一个节点
tmpCell := new(Node)
if tmpCell == nil {
fmt.Println("err: out of space")
}
// 给新建的节点的值域赋值为传入的data值
tmpCell.Data = data
// 新建的节点的next指针指向的是指定节点position的next
tmpCell.Next = position.Next
// 指定节点position的后继节点变成了新建的节点
position.Next = tmpCell
}
// 删除节点
func Delete(data interface{}, node *Node) {
tmp := node
for tmp.Next!=nil {
if(tmp.Next.Data == data){
p := tmp.Next
tmp.Next = p.Next
p.Next = nil
break;
}
tmp = tmp.Next
}
}
// 删除链表
// func DeleteList(node **Node) {
// p := node
// for *p != nil {
// tmp := *p
// *p = nil
// *p = tmp.Next
// }
// }
func DeleteList(node *Node) {
p := node
for p != nil {
tmp := p
p = tmp.Next
tmp.Next = nil
}
node = nil
}
//反转链表 递归
func ReverseList(node *Node) *Node{
p :=node
if p.Next==nil{
return p
}
q:=ReverseList(p.Next)
p.Next.Next=p
p.Next=nil
return q
}
//返回倒数第k个数 双指针法
func kthToLast(k int,node *Node) *Node{
p := node
q := node
for ;k>0;k--{
p=p.Next
}
for p!=nil{
p=p.Next
q=q.Next
}
return q
}
//返回倒数第k个数 递归
var size int //全局变量记录向后递归次数
func ZkthToLast(k int,node *Node) *Node{
p:=node
if p==nil{
return p
}
t:=ZkthToLast(k,p.Next)
size++
if size==k{
return p
}
if size<k{
return t
}
if size>k{
return t
}
return t
}
//反转链表 非递归
func NReverseList(node *Node) *Node{
p :=node
var cre *Node =nil
for p!=nil{
t:=p.Next
p.Next=cre
cre=p
p=t
}
return cre
}
//打印列表
func PrintList(list *Node) {
p := list
for p != nil {
fmt.Printf("%d ", p.Data)
// fmt.Printf("%d-%v-%p ", p.Data, *p, p.Next)
p = p.Next
}
fmt.Println()
}
/**LRU算法***************************************************/
//哈希表
type LRUCache struct {
size int
capacity int
cache map[int]*DLinkedNode
head, tail *DLinkedNode
}
//双向链表
type DLinkedNode struct {
key, value int
prev, next *DLinkedNode
}
func initDLinkedNode(key, value int) *DLinkedNode {
return &DLinkedNode{
key: key,
value: value,
}
}
//建一个空的双向链表
func Constructor(capacity int) LRUCache {
l := LRUCache{
cache: map[int]*DLinkedNode{},
head: initDLinkedNode(0, 0),
tail: initDLinkedNode(0, 0),
capacity: capacity,
}
l.head.next = l.tail
l.tail.prev = l.head
return l
}
//取一个数
func (this *LRUCache) Get(key int) int {
if _, ok := this.cache[key]; !ok {
return -1
}
node := this.cache[key]
//放到最前边
this.moveToHead(node)
return node.value
}
//加一个数
func (this *LRUCache) Put(key int, value int) {
//如果没有
if _, ok := this.cache[key]; !ok {
node := initDLinkedNode(key, value)
this.cache[key] = node
this.addToHead(node)
this.size++
if this.size > this.capacity {
removed := this.removeTail()
delete(this.cache, removed.key)
this.size--
}
} else {
node := this.cache[key]
node.value = value
this.moveToHead(node)
}
}
//在前边添加
func (this *LRUCache) addToHead(node *DLinkedNode) {
node.prev = this.head
node.next = this.head.next
this.head.next.prev = node
this.head.next = node
}
//删除节点
func (this *LRUCache) removeNode(node *DLinkedNode) {
node.prev.next = node.next
node.next.prev = node.prev
}
//移到前方
func (this *LRUCache) moveToHead(node *DLinkedNode) {
this.removeNode(node)
this.addToHead(node)
}
//删除尾部
func (this *LRUCache) removeTail() *DLinkedNode {
node := this.tail.prev
this.removeNode(node)
return node
}
/*!!!!!!!!!!!!!!!!!!!判断是否有环,判断入环点*/
//快慢指针
func detectCycle(head *Node) *Node {
fast,slow:=head,head
if fast==nil{
return nil
}
for fast!=nil{
if fast.Next==nil{
return nil
}
fast = fast.Next.Next
slow = slow.Next
if fast==slow{
break
}
}
if fast==nil{
return nil
}
for slow=head;slow!=fast;slow=slow.Next{
fast=fast.Next
}
return fast
}
//*****************回文链表
// type ListNode struct {
// Val int
// Next *ListNode
// }
//反转链表
func reverseList(head *Node) *Node {
var prev, cur *Node = nil, head
for cur != nil {
nextTmp := cur.Next
cur.Next = prev
prev = cur
cur = nextTmp
}
return prev
}
//找到前一半链表
func endOfFirstHalf(head *Node) *Node {
fast := head
slow := head
for fast.Next != nil && fast.Next.Next != nil {
fast = fast.Next.Next
slow = slow.Next
}
return slow
}
//判断是否是回文链表
func isPalindrome(head *Node) bool {
if head == nil {
return true
}
// 找到前半部分链表的尾节点并反转后半部分链表
firstHalfEnd := endOfFirstHalf(head)
secondHalfStart := reverseList(firstHalfEnd.Next)
// 判断是否回文
p1 := head
p2 := secondHalfStart
result := true
for result && p2 != nil {
if p1.Data != p2.Data {
result = false
}
p1 = p1.Next
p2 = p2.Next
}
// 还原链表并返回结果
firstHalfEnd.Next = reverseList(secondHalfStart)
return result
}
//反转链表mn
func reverseBetween(head *Node, m int, n int) *Node {
// 关键点是m的前一个节点
dummy := &Node{
Next: head,
}
prem := dummy
for i := 1; i <= m-1; i++ {
prem = prem.Next
}
// m和n区间内反转
current := prem.Next
var pre *Node
for i := m; i <= n; i++ {
tempNext := current.Next
current.Next = pre
pre = current
current = tempNext
}
// prem.Next为m节点,原始m节点应该指向n+1节点
prem.Next.Next = current
// prem指向pre(反转之后的头节点)
prem.Next = pre
return dummy.Next
}
func main() {
//定义头结点
headNode := &Node{
Data:0,
Next:nil,
}
list := headNode
//1.指定位置插入结点1
Insert(1, headNode)
//2.打印列表
PrintList(list)
//3.判断是否为空
fmt.Println(IsEmpty(list))
//4.是否是最后一个节点
fmt.Println(IsLast(headNode))
//5.根据值查找节点
p := Find(1, list)
fmt.Printf("pos: %#v\n",p)
//插入数据
Insert(2, p)
Insert(3, p)
PrintList(list)
//删除结点
// Delete(3, list)
// PrintList(list)
//删除链表
// DeleteList(list)
// PrintList(list)
//反转链表递归
Reverselist:=ReverseList(list)
PrintList(Reverselist)
//反转链表非递归
NReverselist:=NReverseList(Reverselist)
PrintList(NReverselist)
//返回倒数第k个数 双指针法
kthToLast :=kthToLast(3,NReverselist)
fmt.Println(kthToLast)
//返回倒数第k个数 递归
kthToLast = ZkthToLast(3,NReverselist)
fmt.Println(kthToLast)
//判断是否有环
fmt.Println(detectCycle(NReverselist))
//判断回文链表
fmt.Println(isPalindrome(NReverselist))
//反转链表mn
PrintList(reverseBetween(NReverselist,0,1))
}
二、习题
1.Add Two Numbers
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
var res ListNode
var t *ListNode = &res
var p *ListNode = l1
var q *ListNode = l2
var c int = 0
for ;p!=nil || q!=nil; {//有节点
var temp *ListNode = new(ListNode)
t.Next = temp
t = t.Next
if(p!=nil && q==nil){
tval := p.Val + c
temp.Val = tval % 10
c = tval / 10
p = p.Next
}else if(p==nil && q!=nil){
tval := q.Val + c
temp.Val = tval % 10
c = tval / 10
q = q.Next
}else{
tval := (p.Val + q.Val + c)
temp.Val = tval % 10
c = tval / 10
p = p.Next
q = q.Next
}
}
if(c > 0){
temp := ListNode{Val:c,Next:nil}
t.Next = &temp
}
return res.Next
}
2.Remove Nth Node From End of List
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
//法一 查长度
// func removeNthFromEnd(head *ListNode, n int) *ListNode {
// var headNode *ListNode = &ListNode{Val:0,Next:head}
// var q,t = headNode,headNode
// var p *ListNode = head
// len := 1
// for p != nil {
// len++
// p = p.Next
// }
// for i := len - n -1;i > 0 ;i-- {
// q = q.Next
// }
// t = q.Next
// q.Next = t.Next
// t.Next = nil
// return headNode.Next
// }
//法二 双指针法
// 间隔n
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummyHead := &ListNode{Next:head}
preSlow,slow,fast := dummyHead,head,head//preSlow.Next指向待删除节点
for fast != nil {
if n <= 0 { //fast point tail or nil move slow keep distance
preSlow = slow
slow = slow.Next
}
n--
fast = fast.Next
}
preSlow.Next = slow.Next
return dummyHead.Next
}
3.Merge Two Sorted Lists
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
//法一: 选小合并
// func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
// p,q := list1,list2
// dummy := &ListNode{}
// cur := dummy
// for p != nil && q != nil {
// if p.Val <= q.Val {
// t := &ListNode{Val:p.Val}
// cur.Next = t
// cur = cur.Next
// p = p.Next
// }else{
// t := &ListNode{Val:q.Val}
// cur.Next = t
// cur = cur.Next
// q = q.Next
// }
// }
// if p == nil {
// cur.Next = q
// }else{
// cur.Next = p
// }
// return dummy.Next
// }
//法二:递归,每两个节点选小的返回,然后选小的下一个进行递归。 结束条件是:其中一个遍历完,将剩余链表返回
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
if list1 == nil {
return list2
}
if list2 == nil {
return list1
}
if list1.Val < list2.Val {
list1.Next = mergeTwoLists(list1.Next,list2)
return list1
}
list2.Next = mergeTwoLists(list1,list2.Next)
return list2
}
4. Merge k Sorted Lists
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
// 分治法:递归合并子k链表
func mergeKLists(lists []*ListNode) *ListNode {
length := len(lists)
if length < 1{
return nil
}
if length == 1 {
return lists[0]
}
half := length/2
left := mergeKLists(lists[:half])
right := mergeKLists(lists[half:])
return mergeTowLists(left,right)
}
func mergeTowLists(l1 *ListNode,l2 *ListNode) *ListNode {
if l1 == nil {
return l2
}
if l2 ==nil {
return l1
}
if l1.Val < l2.Val {
l1.Next = mergeTowLists(l1.Next,l2)
return l1
}
l2.Next = mergeTowLists(l1,l2.Next)
return l2
}
5.Swap Nodes in Pairs
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func swapPairs(head *ListNode) *ListNode {
dummyNode := &ListNode{Next:head}
for pre:=dummyNode; pre!=nil && pre.Next!=nil && pre.Next.Next!=nil; {
cur:=pre.Next
next:=cur.Next
pre.Next,cur.Next,next.Next,pre = next,next.Next,cur,cur
}
return dummyNode.Next
}
6.Reverse Nodes in k-Group
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseKGroup(head *ListNode, k int) *ListNode {
node := head
for i:=0; i < k; i++ {
if node== nil {
return head
}
node = node.Next
}
newHead := reverse(head,node)
head.Next = reverseKGroup(node,k)
return newHead
}
func reverse(first *ListNode,last *ListNode) *ListNode{
prev := last
for first!=last {
tmp := first.Next
first.Next = prev
prev = first
first = tmp
}
return prev
}
7.Rotate List
Example 2:
Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL
题目大意 #
旋转链表 K 次。
解题思路 #
这道题需要注意的点是,K 可能很大,K = 2000000000 ,如果是循环肯定会超时。应该找出 O(n) 的复杂度的算法才行。由于是循环旋转,最终状态其实是确定的,利用链表的长度取余可以得到链表的最终旋转结果。
这道题也不能用递归,递归解法会超时。
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil || head.Next== nil || k ==0 {
return head
}
dummyNode := &ListNode{Next:head}
len:=0
cur := dummyNode
//count and make chain
for cur.Next!=nil{
len++
cur = cur.Next
}
if (k % len) == 0{
return head
}
//find res and remove chain
cur.Next = head
cur = dummyNode
for i := len - k%len;i > 0;i-- {//time of move forward
cur = cur.Next
}
res := &ListNode{Next:cur.Next}
cur.Next = nil
return res.Next
}