链表类算法题
Posted Kris_u
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表类算法题相关的知识,希望对你有一定的参考价值。
1、反转链表leetcode 206:
// ListNode Definition for singly-linked list.
type ListNode struct
Val int
Next *ListNode
func reverseList(head *ListNode) *ListNode
if head == nil || head.Next == nil
return head
var prev *ListNode
cur := head
for cur != nil
cur.Next, prev, cur = prev, cur, cur.Next
return prev
2、将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
递归实现:
func mergeLists(l1,l2 ListNode)
//1.递归终止条件
if(l1 == nil)return l2
if(l2 == nil)return l1
//2.递归合并
if(l1.val < l2.val)
l1.next = mergeTwoLists(l1.next,l2) //对l1.next, l2为头节点的两个链表进行合并
return l1
else
l2.next = mergeTwoLists(l2.next,l1) //对l2.next, l1为头节点的两个链表进行合并
return l2
3、234leetcode :判断链表是否为回文链表
/***/
// Definition for singly-linked list.
type ListNode struct
Val int
Next *ListNode
func isPalindrome(head *ListNode) bool
if head == nil || head.next ==nil
return true
firstEnd := endOfFirstHalfList(head)
//后半段反转列表
reverseHead := reverseList(firstEnd.Next)
//回文序列的后半段反转之后跟前半段是相同的
p1 := head
p2 := reverseHead
for p2 != nil
if p1.Val != p2.Val
return false
p1 = p1.Next
p2 = p2.Next
return true
//慢指针走到列表的一半时,快指针则走到了列表末尾;那么,返回的slow就是列表的前半段
func endOfFirstHalfList(head *ListNode) *ListNode
slow := head
fast := head
for fast.Next != nil && fast.Next.Next != nil
fast = fast.Next.Next
slow = slow.Next
return slow
//反转列表
func reverseList(head *ListNode) *ListNode
var prev *ListNode = nil
current := prev
current = head
for current != nil
current.Next, prev, current = prev, current, current.Next
return prev
package main
import "fmt"
func main()
head := new(ListNode)
head.Val = 1
ln2 := new(ListNode)
ln2.Val = 2
ln3 := new(ListNode)
ln3.Val = 1
// ln4 := new(ListNode)
// ln4.Val = 1
head.Next = ln2
ln2.Next = ln3
// ln3.Next = ln4
fmt.Println("head", head)
fmt.Println("head", head.Next)
fmt.Println("head", head.Next.Next)
fmt.Println("head", head.Next.Next.Next)
head1 := new(ListNode)
head1.Val = 1
node2 := new(ListNode)
node2.Val = 4
node3 := new(ListNode)
node3.Val = 5
head1.Next = node2
node2.Next = node3
fmt.Println("head1", head1)
fmt.Println("head1", head1.Next)
fmt.Println("head1", head1.Next.Next)
fmt.Println("isPalindrome:", isPalindrome(head))
fmt.Println("isPalindrome:", isPalindrome(head1))
输出:
head &1 0xc0000881f0
head &2 0xc000088200
head &1 <nil>
head <nil>
head1 &1 0xc000088250
head1 &4 0xc000088260
head1 &5 <nil>
isPalindrome: true
isPalindrome: false
25. K 个一组翻转链表 - 力扣(LeetCode) (leetcode-cn.com)
func reverseKGroup(head *ListNode, k int) *ListNode
dummy := new(ListNode)
dummy.Val = 0
dummy.Next = head
pre := dummy // 链表头节点head之前加一个dummy节点
end := dummy
for end.Next != nil
//开始pre、end处于同一个节点,end指针前进K个节点,通过for循环实现
for i := 0; i < k && end != nil; i++
end = end.Next
if end == nil
break
start := pre.Next //start表示子链表的头节点
next := end.Next //next表示下一个子链表的头节点(每个子链表有K个节点)
end.Next = nil //
pre.Next = reverseList(start)
//设置新的pre、end
start.Next = next
pre = start
end = pre
return dummy.Next
链表排序:归并排序思想
func sortList(head *ListNode) *ListNode
left, right := cutList(head)
// 单个的链表不再切割 否则会一直切下去
if left != nil && left.Next != nil
left = sortList(left)
if right != nil && right.Next != nil
right = sortList(right)
return mergeList(left, right)
// 利用快慢指针 找到链表中点,对半切分为两个链表
func cutList(head *ListNode)(*ListNode, *ListNode)
if head == nil
return nil, nil
fast := head.Next
slow := head
for fast != nil && fast.Next != nil
fast = fast.Next.Next
slow = slow.Next
slowNext := slow.Next //low.Next为后半个子链表第一个节点(头部)
slow.Next = nil //slow是前半个子链表的尾部,则其Next应为nil
return head, slowNext
func mergeList(list1 *ListNode, list2 *ListNode) *ListNode
if list1 == nil
return list2
else if list2 == nil
return list1
var head = new(ListNode)
var cur = head
for list1 != nil && list2 != nil
if list1.Val < list2.Val
cur.Next = list1
list1 = list1.Next
else
cur.Next = list2
list2 = list2.Next
cur = cur.Next
if list1 == nil
cur.Next = list2
else
cur.Next = list1
return head.Next
4、2. 两数相加 - 力扣(LeetCode) (leetcode-cn.com)
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
/**
* Definition for singly-linked list.
* type ListNode struct
* Val int
* Next *ListNode
*
*/
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode
result := &ListNode
tmp := result
sur := 0
for l1 != nil || l2 != nil
sum := 0
tmp.Next = &ListNode
if l1 != nil
sum += l1.Val
l1 = l1.Next
if l2 != nil
sum += l2.Val
l2 = l2.Next
tmp.Next.Val = (sum+sur) % 10
sur = (sum+sur) / 10
tmp = tmp.Next
if sur != 0
tmp.Next = &ListNode
tmp.Next.Val = sur
return result.Next
5、判断链表是否有环
思路:快指针一次走两步,慢指针一次走一步,如果链表有环,那么两个指针始终会相遇。
type ListNode struct
Data interface
Next *ListNode
func HasCycle(head *ListNode) bool
if head == nil
return false
fast, slow := head, head
for fast != nil && slow != nil && fast.Next != nil
slow = slow.Next
fast = fast.Next.Next
if slow == fast
return true
return false
3、LRU缓存 leetcode
LRU,全称是 Least Recently Used,即最近最少使用。是一种缓存淘汰策略算法。
算法的思想:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。所以,当指定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
参考:
链接:https://leetcode-cn.com/problems/lru-cache/solution/jian-dan-shi-li-xiang-xi-jiang-jie-lru-s-
type Node struct
key, val int
prev, next *Node
func initNode(key, val int) *Node
return &Node
key: key,
val: va,
type DlinkList struct
head, tail *Node
size int //链表元素数
func initDlinkList() *DlinkList
dll := &DlinkList
head: initNode(0, 0),
tail: initNode(0, 0),
size: 0,
dll.head.next = dll.tail
dll.tail.prev = dll.head
return dll
//在链表尾部添加新节点
func (dl *DlinkList) addNode(x *Node)
x.next = dl.tail
x.prev = dl.tail.prev
dl.tail.prev.next = x
dl.tail.prev = x
dl.size++
//删除链表中的x节点
func (dl *DlinkList) del(x *Node)
x.prev.next = x.next
x.next.prev = x.prev
x.prev, x.next = nil, nil
dl.size--
//删除链表中的第一个节点,并返回该节点
func (dl *DlinkList) delFirstnode() *Node
if dl.head.next == dl.tail.prev
return
first := dl.head.next
dl.del(first)
return first
//双链表只能从尾部插入,尾部节点是最近使用的,靠近头部的数据是最久使用的
type LRUCache struct
capacity int
keyMap map[int]*Node
cache *DlinkList
func initLRUCache(capacity int) LRUCache
lru := LRUCache
capacity: capacity,
keyMap: map[int]*Node,
cache: initDlinkList(),
return lru
func (lru *LRUCache) makeRecentNode(key int)
node := lru.keyMap[key]
lru.cache.del(node) //删除旧的key的节点
lru.cache.addNode(node) //添加到链尾
//在链表尾部添加新节点
func (lru *LRUCache) addRecentNode(key, value int)
node := initNode(key, value)
lru.cache.addNode(node) //添加至双链表
lru.keyMap[key] = node //添加至字典
// 删除某一个 key 及对应元素
func (lru *LRUCache) delKey(key int)
node := lru.keyMap[key]
lru.cache.del(node) //删除双向链表中的key节点
delete(lru.keyMap,key) //删除字典中的key节点
// 删除最近最少使用的元素
func (lru *LRUCache) deleteLRU()
// 链表的第一个就是最近最少使用的元素
delFirstNode := lru.cache.delFirstnode()
// 删除字典中的key节点
delete(lru.keyMap, delFirstNode.key)
func (lru *LRUCache) Get(key int) int
node, exist := lru.keyMap[key]
if !exist
return -1
lru.makeRecentNode(key)
return node.val
/*
①若节点key已经存在,删除旧的节点,再添加到链尾
②若节点不存在缓存容量已满,则删除使用最少的节点,添加到链尾
③链尾节点数据是最新的
*/
func (lru *LRUCache) Put(key, value int)
_, exist := lru.keyMap[key]
if exist
lru.delKey(key) //删除旧节点
else
if lru.capacity == lru.cache.size
lru.deleteLRU()
lru.addRecentNode(key, value) //链尾数据是最新的
3、全排列:
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
本题的算法如下:
对于第一个数,可以采用任意数组中任意一个数作为开头,所以遍历数组取出一个数,这一步得到的中间结果就是遍历出的这个数,并且得到新的数组,就是原入口参数数组去除掉我们遍历出的数的数组,利用这个数组,再次遍历取出下一个数
如果入口参数的数组中不包含任何元素,那么说明我们把入口参数数组已经深度遍历完成,就记录这个结果
如果入口参数数组还包含元素,那么我们遍历入口参数数组中剩下的元素,依次取出一个元素追加到结果中,作为中间结果。
func permute(num []int) [][]int
res := make([][]int, 0)
tmp := make([]int, 0)
res = recursion(num, tmp, res)
return res
func recursion(num, tmp []int, res [][]int) [][]int
if len(num) == 0
res = append(res, tmp)
return res
fmt.Println("num", num)
for index, value := range num
newNum := make([]int, len(num)-1)
newTmp := append(tmp, value)
//
count := 0
for i, v := range num
if index != i
newNum[count] = v
count++
res = recursion(newNum, newTmp, res)
return res
以上是关于链表类算法题的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode练习(Python):链表类:第23题:合并K个排序链表:合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。