技巧汇总
- 快慢指针
- 先找到中间节点
- 如果要调用next..确保当前节点不为空。 依次类推。.next不为空
- 是否有环。走过的路。重新走。互相走。
- 画图,分解,
- 暴力法。用hashset
- 插入法翻转。
package main
import (
"fmt"
. "github.com/isdamir/gotype"
)
func AddLNode(h1, h2 *LNode) *LNode {
// 考虑为空
if h1 == nil || h1.Next == nil {
return h2
}
if h2 == nil || h2.Next == nil {
return h1
}
c := 0 // 记录进位
sum := 0
p1 := h1.Next
p2 := h2.Next
resultHead := &LNode{}
p := resultHead
for p1 != nil || p2 != nil {
var p1_int int
var p2_int int
if p1 == nil {
p1_int = 0
} else {
p1_int = p1.Data.(int)
}
if p2 == nil {
p2_int = 0
} else {
p2_int = p2.Data.(int)
}
p.Next = &LNode{}
sum = p1_int + p2_int + c
p.Next.Data = sum % 10
c = sum / 10
p = p.Next
if p1 != nil {
p1 = p1.Next
}
if p2 != nil {
p2 = p2.Next
}
}
// 最后有进位
if c == 1 {
p.Next = &LNode{Data: 1}
}
return resultHead
}
// 对链表进行重新排序
// 输入 L0 -> L1 -> L2 -> Ln-1 -> Ln
// 输出 L0 -> Ln -> L2 -> Ln-1 ..
// 思路: 找到中间节点。对链表的后半部分 反转 。 前半部分和后半部分合并
//找中间节点
func findMiddleNode(head *LNode) *LNode {
if head == nil || head.Next == nil {
return head
}
// 快慢指针 1 2 3 4 5 6 7
// fast 1 3 5 7 fast = 7
// slow 1 2 3 4 slow = 4
// slowpre 1 1 2 3 slopre = 3
// 快慢指针 1 2 3 4 5 6 7 8
// fast 1 3 5 7 nil fast = 7
// slow 1 2 3 4 5 slow = 5
// slowpre 1 1 2 3 4 slopre = 4
fast := head
slow := head
slowPre := head
for fast != nil && fast.Next != nil {
slowPre = slow
slow = slow.Next
fast = fast.Next.Next
}
slowPre.Next = nil
return slow
}
//头节点的单链表进行翻转
func reversLNode(head *LNode) *LNode {
// 插入法来翻转,从第二个节点开始插入
if head == nil || head.Next == nil {
return head
}
var cur *LNode
var curnext *LNode
cur = head.Next.Next //从第二个元素开始插入
head.Next.Next = nil
for cur != nil {
// myhead 1 2 3 4
// myhead 2 1 3 4
curnext = cur.Next // 先获取到next 3
// node1 := // 获取头节点的next 1 // 这里是xinfuzhi?
// head.Next = cur // 头指针 指向 2
cur.Next = head.Next // 2 指向 1
head.Next = cur
// node1.Next = curnext // 1 指向3
cur = curnext
// curnext = cur.Next
// cur.Next = head.Next
// head.Next = cur
// cur = curnext
}
return head
}
// 合并列表
func ReorderLNode(head *LNode) {
if head == nil || head.Next == nil {
return
}
cur1 := head
mid := findMiddleNode(head.Next)
head2 := &LNode{}
head2.Next = mid
cur2 := reversLNode(head2)
// fmt.Println("cur1:", cur1)
// fmt.Println("cur2:", cur2)
PrintNode("cur1:", cur1)
PrintNode("cur2:", cur2)
cur1 = cur1.Next
cur2 = cur2.Next
for cur1.Next != nil {
// 1 2 3 4
// 8 7 6 5
// 1 8 2 3 4
// 7 6 5
cur1_tmp := cur1.Next // 2 3 4
cur1.Next = cur2 // 1 8 7 6 5
cur1 = cur1_tmp // 2 3 4
cur2_tmp := cur2.Next // 7 6 5
cur2.Next = cur1 // 1 8 2 3 4
cur2 = cur2_tmp // 7 6 5
}
// 奇数 场景
// 1 7 2 6 3
// 5 4
cur1.Next = cur2
}
// 找出单链表中的倒数第K个元素
// 方法一: 遍历俩遍。 第一次知道链表的个数 n . 第二次 遍历到 n-k就行。
func FindLastK1(head *LNode, k int) *LNode {
if head == nil || head.Next == nil {
return head
}
return head
}
// 方法二
// 快慢指针: 快指针fast先走k步, 从K+1开始 和 slow指针从起始位置开始继续走。 fast遇到nil停止。
func FindLastK2(head *LNode, k int) *LNode {
if head == nil || head.Next == nil {
return head
}
fast := head.Next
slow := head.Next
i := 0
for i = 0; i < k && fast != nil; i++ {
fast = fast.Next
}
if i < k {
// 提前退出,不足K
return nil
}
for fast != nil {
slow = slow.Next
fast = fast.Next
}
return slow
}
// 检测一个较大的单链表是否有环
//暴力法:set存储。 如果遍历到已经在set中的LNode.说明 有环。
// 快慢指针遍历法:
// 快慢指针 fast slow . 如果相遇说明有环,返回相遇点
//
func isLoop(head *LNode) *LNode {
if head == nil || head.Next == nil {
return head
}
slow := head.Next
fast := head.Next
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
return slow
}
}
return nil
}
// 找出环的入口点。
// slow : 走了 s 步 fast走了2s步 1 2 3 4 5 6 7 -> 3
/**
a : 起点到入口点的距离
x : 入口点到遇见点的距离
L : 总长度
y : 遇见点到 入口点的步数
n : 快指针走过环的圈数 。大于等于 >= 1
r : 环的长度
如果相遇 说明
2s = s + nr -> 2s -s = nr -> s = nr
s = a + x // 入口点 + x
a + x = nr
a + x = (n-1)r + r 因为 r = L - a
a + x = (n-1)r + L - a
a = (n-1)r + L -a -x
b = L -a -x
a = (n-1) r + b
说明从相遇点开始走(n-1)r + b步一定会和初始点出发在 a相遇。
*/
//
func FindLoopNode(head *LNode, meetNode *LNode) *LNode {
first := head.Next
second := meetNode
for first != second {
first = first.Next
second = second.Next
}
return first
}
// k个元素为一组进行翻转
func ReverseK(head *LNode, k int) {
if head == nil || head.Next == nil {
return
}
// k = 3
pre := head
begin := head.Next // 1
var end *LNode // 3
var pNext *LNode // 4
for begin != nil {
end = begin
for i := 1; i < k; i++ {
if end.Next != nil {
end = end.Next
} else {
break
}
}
pNext = end.Next // 获取4
end.Next = nil // 3-> nil
myhead := &LNode{}
myhead.Next = begin
pre.Next = reversLNode(myhead).Next
begin.Next = pNext // 1 -> 4
pre = begin // pre = 1
begin = pNext // begin = 4
}
}
//合并俩个有序列表
func MergeLNode(h1 *LNode, h2 *LNode) *LNode {
if h1 == nil || h1.Next == nil {
return h2
}
if h2 == nil || h2.Next == nil {
return h1
}
p1 := h1.Next
p2 := h2.Next
r := &LNode{}
pre := r
for p1 != nil && p2 != nil {
if p1.Data.(int) < p2.Data.(int) {
pre.Next = p1 // myhead-> 1
pre = p1 // pre: 1
p1 = p1.Next // p1 : 3
} else {
pre.Next = p2
pre = p2
p2 = p2.Next
}
}
if p1 != nil {
pre.Next = p1
}
if p2 != nil {
pre.Next = p2
}
return r
}
// 给定单链表,中的某个节点的指针。 删除这个节点
// 如果是最后一个节点,没法删除
// 如果不是,则复制后面一个节点的数据。
func RemoveNode(deleteNode *LNode) bool {
if deleteNode == nil || deleteNode.Next == nil {
return false
}
// deleteNode = 5
deleteNode.Data = deleteNode.Next.Data // 5 6 7 8 -> 6 6 7 8
deleteNode.Next = deleteNode.Next.Next
return true
}
// 判断俩个链表是否交叉
// 方法一: hash .遍历添加到set中。判断。
// 方法二: 首位相接法 , l1_last -> l2_head . 判断是否有环
// 方法三: 尾节点法。 如果交叉,那么一定是同一个尾节点。
/**
你走你的。我走我的。然后我走你的,你走我的。一定会相遇
l1: 1 2 3 4 5
l2: 2 3 4 5
l1: 1 2 3 4 5 2 3 4 5
l2: 2 3 4 5 1 2 3 4 5
*/
func IsIntersect(head1 *LNode, head2 *LNode) *LNode {
if head1 == nil || head1.Next == nil || head2 == nil || head2.Next == nil {
return nil
}
cur1 := head1.Next
cur2 := head2.Next
for cur1 != nil && cur2 != nil {
cur1 = cur1.Next
cur2 = cur2.Next
if cur1 == cur2 {
return cur1
}
}
if cur1 == nil {
cur1 = head2.Next
for cur1 != nil && cur2 != nil {
cur1 = cur1.Next
cur2 = cur2.Next
if cur1 == cur2 {
return cur1
}
}
if cur2 == nil {
cur2 = head1.Next
}
for cur1 != nil && cur2 != nil {
cur1 = cur1.Next
cur2 = cur2.Next
if cur1 == cur2 {
return cur1
}
}
}
if cur2 == nil {
cur2 = head1.Next
for cur1 != nil && cur2 != nil {
cur1 = cur1.Next
cur2 = cur2.Next
if cur1 == cur2 {
return cur1
}
}
if cur1 == nil {
cur1 = head2.Next
}
for cur1 != nil && cur2 != nil {
cur1 = cur1.Next
cur2 = cur2.Next
if cur1 == cur2 {
return cur1
}
}
}
return nil
}
// 如何 展开链接列表 除了next指针还有down指针。扁平化
/**
3 - > 11 -> 15 -> 30
6 21 22 39
8 50 40
31 55
3 6 8 11 15 21 22 30 31 39 40 50 55
归并法: 俩俩归并 。
*/
type LDNode struct {
data int
right *LDNode
down *LDNode
}
func (p *LDNode) Insert(headRef *LDNode, data int) *LDNode {
newNode := &LDNode{data: data, down: headRef}
headRef = newNode
return headRef
}
func MergeLDNode(h1 *LDNode, h2 *LDNode) *LDNode {
if h1 == nil {
return h2
}
if h2 == nil {
return h1
}
var r *LDNode
if h1.data < h2.data {
r = h1
r.down = MergeLDNode(h1.down, h2)
} else {
r = h2
r.down = MergeLDNode(h1, h2.down)
}
return r
}
func main() {
// 计算俩个单链表所代表的数之和
// 方式一: 遍历单链表,转换为整数。然后计算相加
// 缺点:如果链表所代表的数很大,就无法使用
// 方式二: 链表相加,要保留进位,长度不一样。需要继续计算
// l1 := &LNode{}
// l2 := &LNode{}
// CreateNode(l1, 8)
// CreateNode(l2, 8)
// PrintNode("l1: ", l1)
// PrintNode("l2: ", l2)
// l3 := AddLNode(l1, l2)
// PrintNode("sum: ", l3)
// l1 := &LNode{}
// CreateNode(l1, 8)
// PrintNode("l1: ", l1)
// m1 := findMiddleNode(l1.Next)
// PrintNode("l1: ", l1)
// fmt.Println(m1.Data)
// l2 := &LNode{}
// CreateNode(l2, 8)
// PrintNode("l2: ", l2)
// l2r := reversLNode(l2)
// PrintNode("l2: ", l2r)
// // PrintNode("翻转之后的 ", l2r)
// l := &LNode{}
// CreateNode(l, 8)
// // ReorderLNode(l)
// // PrintNode("result: ", l)
// // r := FindLastK2(l, 3)
// // fmt.Println(r.Data)
// l.Next.Next.Next.Next.Next.Next = l.Next.Next.Next.Next
// meetNode := isLoop(l)
// if meetNode != nil {
// fmt.Println("有环:", meetNode.Data)
// loopNode := FindLoopNode(l, meetNode)
// fmt.Print("入口Node:", loopNode.Data)
// }
fmt.Println("fuck ")
// l := &LNode{}
// CreateNode(l, 8)
// ReverseK(l, 3)
// PrintNode("k:", l)
// l1 := &LNode{}
// CreateNode(l1, 8)
// l2 := &LNode{}
// CreateNode(l2, 5)
// r := MergeLNode(l1, l2)
// PrintNode("mergeNOde: ", r)
// fmt.Println("delete node:")
// l := &LNode{}
// CreateNode(l, 9)
// PrintNode("delete before:", l)
// RemoveNode(l.Next.Next.Next.Next.Next)
// PrintNode("delete after:", l)
l1 := &LNode{}
CreateNode(l1, 9)
l2 := &LNode{}
CreateNode(l2, 4)
PrintNode("L1:", l1)
PrintNode("L2:", l2)
l2.Next = l1.Next.Next
l2.Next.Next.Next = l1.Next.Next.Next.Next
PrintNode("L1:", l1)
PrintNode("L2:", l2)
r := IsIntersect(l1, l2)
if r != nil {
fmt.Println("intersect:", r.Data)
}
}