【代码随想录】链表-golang

news2024/11/24 19:58:18

链表 from 代码随想录

移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

思路:设置一个新的节点,节点的下一个是链表的第一个节点

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
    ptr := &ListNode{Next:head}
    for vptr := ptr;vptr.Next != nil;{
        if vptr.Next.Val == val{
            vptr.Next = vptr.Next.Next
        }else{
            vptr = vptr.Next
        }
    }
    return ptr.Next
} 

设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

单向链表

设置一个头部的哨兵节点
在这里插入图片描述

type MyLinkedList struct {
	head *ListNode
	size int
}

type ListNode struct {
	Next *ListNode
	Val  int
}

func Constructor() MyLinkedList {
	return MyLinkedList{head:&ListNode{},size:0}
}


func (this *MyLinkedList) Get(index int) int {
	if index > this.size - 1 || index < 0 {
		return  -1
	}
	ptr := this.head
	for i:=0;i<=index;i++{
		ptr = ptr.Next
	}
	return ptr.Val
}


func (this *MyLinkedList) AddAtHead(val int)  {
	this.AddAtIndex(0,val)
}


func (this *MyLinkedList) AddAtTail(val int)  {
	this.AddAtIndex(this.size,val)
}


func (this *MyLinkedList) AddAtIndex(index int, val int)  {
	if index > this.size {
		return
	}
	index = max(index,0)
	this.size ++
	ptr := this.head
	for i:=0;i<index;i++{
		ptr = ptr.Next
	}
	adder := &ListNode{Val:val,Next:ptr.Next}
	ptr.Next = adder
}

func max(a,b int)int{
	if a > b {
		return a
	}
	return b
}

func (this *MyLinkedList) DeleteAtIndex(index int)  {
	if index > this.size - 1 || index < 0{
		return
	}
	this.size --
	ptr := this.head
	for i:=0;i<index;i++{
		ptr = ptr.Next
	}
	ptr.Next = ptr.Next.Next
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Get(index);
 * obj.AddAtHead(val);
 * obj.AddAtTail(val);
 * obj.AddAtIndex(index,val);
 * obj.DeleteAtIndex(index);
 */

双向链表

在两头各设置一个哨兵节点
在这里插入图片描述

type MyLinkedList struct {
    head,tail *node
    size int
}

type node struct{
    val int
    next,prev *node
}


func Constructor() MyLinkedList {
    head := &node{}
    tail := &node{}
    head.next = tail
    tail.prev = head
    return MyLinkedList{head:head,tail:tail,size:0}
}


func (this *MyLinkedList) Get(index int) int {
    if index >= this.size || index < 0 {
        return -1
    }
    if index+1 > this.size/2 {
        eptr := this.tail
        for i:=0;i <= this.size-index-1;i++{
            eptr = eptr.prev
        }
        return eptr.val
    }else{
        sptr := this.head
        for i:=0;i <= index;i++{
            sptr = sptr.next
        }
        return sptr.val
    }
}


func (this *MyLinkedList) AddAtHead(val int)  {
    this.AddAtIndex(0,val)
}


func (this *MyLinkedList) AddAtTail(val int)  {
    this.AddAtIndex(this.size,val)
}


func (this *MyLinkedList) AddAtIndex(index int, val int)  {
    if index > this.size {
        return 
    }
    this.size++
    index = max(index,0)
    if index+1 > this.size/2 {
        eptr := this.tail
        for i:=0;i < this.size-index-1;i++{
            eptr = eptr.prev
        }
        adder := &node{next:eptr,prev:eptr.prev,val:val}
        eptr.prev.next = adder
        eptr.prev = adder
    }else{
        sptr := this.head
        for i:=0;i < index;i++{
            sptr = sptr.next
        }
        adder := &node{next:sptr.next,prev:sptr,val:val}
        sptr.next.prev = adder
        sptr.next = adder
    }
}

func max (a,b int)int{
    if a > b {
        return a
    }
    return b
}

func (this *MyLinkedList) DeleteAtIndex(index int)  {
    if index >= this.size || index <0 {
        return
    }
    if index+1 > this.size/2 {
        eptr := this.tail
        for i:=0;i < this.size-index-1;i++{
            eptr = eptr.prev
        }
        if eptr.prev.prev != nil{
            eptr.prev.prev.next = eptr
        }
        eptr.prev = eptr.prev.prev
    }else {
        sptr := this.head
        for i:=0;i < index;i++{
            sptr = sptr.next
        }
        if sptr.next.next != nil{
            sptr.next.next.prev = sptr
        }
        sptr.next = sptr.next.next
    }
    this.size --
}


/**
 * Your MyLinkedList object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Get(index);
 * obj.AddAtHead(val);
 * obj.AddAtTail(val);
 * obj.AddAtIndex(index,val);
 * obj.DeleteAtIndex(index);
 */

翻转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

迭代

思路:双指针(ptr指向当前节点;prev指向ptr的上一个节点),创建next临时节点

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseList(head *ListNode) *ListNode {
   var prev *ListNode
   ptr := head
   for ptr != nil{
       next := ptr.Next
       ptr.Next = prev
       prev = ptr
       ptr = next
   }
   return prev
}

递归

注释来自leetcode评论区

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
 // 以链表1->2->3->4->5举例
func reverseList(head *ListNode) *ListNode {
   if head == nil || head.Next == nil{
               /*
                直到当前节点的下一个节点为空时返回当前节点
                由于5没有下一个节点了,所以此处返回节点5
             */
       return head
   }
   //递归传入下一个节点,目的是为了到达最后一个节点
   newHead := reverseList(head.Next)
                   /*
            第一轮出栈,head为5,head.next为空,返回5
            第二轮出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                      把当前节点的子节点的子节点指向当前节点
                      此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                      此时链表为1->2->3->4<-5
                      返回节点5
            第三轮出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                      此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                      此时链表为1->2->3<-4<-5
                      返回节点5
            第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                      此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                      此时链表为1->2<-3<-4<-5
                      返回节点5
            第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                      此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                      此时链表为1<-2<-3<-4<-5
                      返回节点5
            出栈完成,最终头节点5->4->3->2->1
         */
   head.Next.Next = head
   head.Next = nil
   return newHead
}

双指针递归

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseList(head *ListNode) *ListNode {
   return reverse(nil,head)
}

func reverse (prev,head *ListNode) *ListNode {
    if head == nil{
        return prev
    }
    tmp := head.Next
    head.Next = prev
    return reverse(head,tmp)
}

两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

迭代

思路:衔接虚拟头节点,通过上一个节点prev后两个节点
在这里插入图片描述

1 加上head

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func swapPairs(head *ListNode) *ListNode {
    dummy := &ListNode{Next:head}
    prev := dummy
    for head != nil && head.Next != nil{
        prev.Next = head.Next
        next := head.Next.Next
        head.Next.Next = head
        head.Next = next
        prev = head
        head = next
    }
    return dummy.Next
}

不带head(推荐)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func swapPairs(head *ListNode) *ListNode {
    dummy := &ListNode{Next:head}
    prev := dummy
    for prev.Next != nil && prev.Next.Next != nil{
        node1 := prev.Next
        node2 := prev.Next.Next
        prev.Next = node2
        node1.Next = node2.Next
        node2.Next = node1
        prev = node1
    }
    return dummy.Next
}

递归

思路:
在这里插入图片描述
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func swapPairs(head *ListNode) *ListNode {
    if head == nil || head.Next == nil{
        return head
    }
    one := head
    two := one.Next
    three := two.Next
    two.Next = one
    one.Next = swapPairs(three)
    return two
}

删除链表的倒数第N个节点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

思路:快慢指针,慢指针为dummy,快指针为head,快指针先移动n次,然后移动慢指针,直到快指针为空
时间复杂度O(n),空间复杂度O(1)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    dummy := &ListNode{Next:head}
    fp,sp := head,dummy
    for i:=0;i<n;i++{
        fp = fp.Next
    }
    for ;fp != nil;fp = fp.Next{
        sp = sp.Next
    }
    sp.Next = sp.Next.Next
    return dummy.Next
}

链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

哈希集合存储

思路:创建一个hashmap,先遍历headA存储全部元素,再去遍历b去尝试命中hashmap,命中返回节点,否则返回nil
空间复杂度O(m)m为headA的长度,时间复杂度为O(m+n) m,n为headA和headB的长度

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    vis := map[*ListNode]bool{}
    for tmp:=headA;tmp != nil;tmp = tmp.Next{
        vis[tmp] = true
    }
    for tmp:=headB;tmp != nil;tmp = tmp.Next{
        if vis[tmp]{
            return tmp
        }
    }
    return nil
}

双指针

思路:记住链表拼接
存在相同节点:ptrA遍历完a表再遍历b表,步数为a+(b-c),ptrB遍历完b表再遍历a表,步数为b+(a-c),
在这里插入图片描述
不存在相同节点:ptrA:a+b;ptrB:b+a

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    if headA == nil || headB == nil{
        return nil
    }
    ptrA,ptrB := headA,headB
    for ptrA != ptrB {
        if ptrA == nil{
            ptrA = headB
        }else {
            ptrA = ptrA.Next
        }
        if ptrB == nil{
            ptrB = headA
        }else{
            ptrB = ptrB.Next
        }
    }
    return ptrA
}

环形链表II

题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。

哈希表-空间复杂度较高,不推荐

思路:遍历链表,先尝试命中map,如果没有就将元素存储在map里
时间复杂度O(n),空间复杂度O(n)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    gain := map[*ListNode]int{}
    pos := 0
    for head != nil {
        if _,ok := gain[head];ok {
            return head
        }
        gain[head] = pos
        pos ++
        head = head.Next
    }
    return nil
}

双指针

思路 ,这是快慢指针,快指针速度为2,慢指针速度为1
在这里插入图片描述>第一次相遇时:sp走了 x + y;fp走了x+y+n(z+y),由此可推算出
2spLength = fpLength -> 2(x+y) = x+y+n(z+y) -> x+y = n(y+z)
-> x = n(y+z) - y -z + z -> x = (n-1)(y+z) + z
(此为简化抽象过程,n可以为随机大于等一1的数字)当n等于0时,x = z

第一次相遇后,将fp重定位到head,以速度为1前进直到再次与sp相遇得出胡那行链表的入口节点

自解版本

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    fp,sp := head,head
    for fp != nil{
        if fp.Next == nil{
            return nil
        }
        fp = fp.Next.Next
        sp = sp.Next
        if fp == sp {
            break
        }
    }
    if fp == nil{
        return nil
    }
    fp = head
    for fp != sp{
        fp = fp.Next
        sp = sp.Next
    }
    return fp
}

标准版本

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    fp,sp := head,head
    for fp != nil{
        if fp.Next == nil{
            return nil
        }
        fp = fp.Next.Next
        sp = sp.Next
        if fp == sp {
            fp = head
            for fp != sp {
                fp = fp.Next
                sp = sp.Next
            }
            return fp
        }
    }
    return nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/116525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿根廷夺冠早已预判,梅西经济爆火,这款产品在跨境电商卖断货了

2022年12月18日23:00&#xff0c;世界杯的决赛将举行&#xff0c;阿根廷会战法国&#xff1b;期间&#xff0c;梅西和姆巴佩也将会在绿茵场上狭路相逢。而作为现役名声最为响亮的球星之一&#xff0c;此次卡塔尔也是梅西最后一次征战世界杯赛场&#xff0c;同时&#xff0c;随着…

基于Python实现电影推荐系统【100010052】

电影推荐系统 标签&#xff1a;Tensorflow、矩阵分解、Surprise、PySpark 1、用Tensorflow实现矩阵分解 1.1、定义one_batch模块 import numpy as np import pandas as pddef read_and_process(filename, sep ::):col_names [user, item, rate, timestamp]df pd.read_cs…

IP判断.库函数复习.数组.C

strtok(在string.h库里&#xff09;函数以"."为分隔符对IP字符串进行切分. atoi函数&#xff08;在stdlib.h里&#xff09;将切分的一部分字符串转换为十进制数字. 描述 C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串&#xf…

LeetCode题目笔记——1759. 统计同构子字符串的数目

文章目录题目描述题目难度——中等方法一&#xff1a;数学代码/C代码/Python总结题目描述 给你一个字符串 s &#xff0c;返回 s 中 同构子字符串 的数目。由于答案可能很大&#xff0c;只需返回对 109 7 取余 后的结果。 同构字符串 的定义为&#xff1a;如果一个字符串中的…

300道网络安全工程师面试题(附答案解析)冲刺金三银四

2022年马上就要过去了&#xff0c;先来灵魂三连问&#xff0c;年初定的目标完成多少了&#xff1f;薪资涨了吗&#xff1f;女朋友找到了吗&#xff1f; 好了&#xff0c;不扎大家的心了&#xff0c;接下来进入正文。 由于我之前写了不少网络安全技术相关的文章和回答&#xff…

nginx 报400_nginx 400 Bad request

记录一次自己写出来的bug. 首先自己在gateway中做了filter,操作了header 操作中返回的报错400 nginx, 所以一直将矛头指向了nginx配置,但是各种查询和修改后,错误依旧. 静下心来一步步的看,发现请求实际上已经通过nginx发送到了gateway中,并且gateway日志中也清楚的记录了lo…

[普及练习场]失踪的7

本专辑上篇&#xff1a; [普及练习场] 生活大爆炸版石头剪刀布 看得都爽&#xff0c;对吧&#xff01;感谢hydro的页面和浴谷的搬运。 目录 一.读题 失踪的7 题意 二 .做题 算法原理 算法实现 全篇代码分解讲解 输入 中心 一.读题 失踪的7 题目描述 远古的 Pascal 人也…

FIT2CLOUD飞致云荣膺“2022年度OSCHINA优秀开源技术团队”奖项

2022年12月&#xff0c;知名开源技术社区OSCHINA&#xff08;开源中国&#xff09;公布了“2022年度OSCHINA优秀开源技术团队”入选名单。凭借在开源软件研发和开源社区运营方面的优秀表现&#xff0c;FIT2CLOUD飞致云获得了OSCHINA社区的认可&#xff0c;荣膺“2022年度优秀开…

基于人脸关键点检测的驾驶员睡意检测系统

摘要 驾驶员注意力不集中或者分心是道路交通事故的主要原因。 为了减少道路交通事故&#xff0c;设计开发驾驶员疲劳检测系统至关重要。 本研究利用人脸关键点检测方法提出了驾驶员睡意检测系统&#xff0c;目的是使驾驶更安全。 一.人类检测方法 人脸关键点检测是人脸识别任…

B. Array Walk(贪心)

Problem - 1389B - Codeforces 给你一个数组a1,a2,...,an&#xff0c;由n个正整数组成。 最初&#xff0c;你站在索引1处&#xff0c;分数等于a1。你可以进行两种移动。 向右移动--从你当前的索引x走到x1&#xff0c;并将ax1加入你的分数。这个动作只有在x<n时才能进行。 …

黑客窃取 4 亿 Twitter 用户记录,勒索马斯克破财消灾

整理 | 何苗 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 上周五&#xff0c;一个用户名为 Ryushi 的用户在黑客论坛 Breached 上发布了一个帖子声称&#xff0c;已成功利用漏洞抓取了超 4 亿 Twitter 用户数据并在线出售。 为了证明数据的真实性&am…

spring cloud gateway网关转发websocket请求

springcloud gateway网关是所有微服务的统一入口。 1、springcloud gateway关键术语 Route&#xff1a;路由&#xff0c;网关配置的基本组成模块。一个Route模块由一个 ID&#xff0c;一个目标 URI&#xff0c;一组断言和一组过滤器定义。如果断言为真&#xff0c;则路由匹配…

经营报表-FineReport配置Oracle外接数据库(2)

1. 配置外接数据库 1.1 外接数据库配置入口 外接数据库的配置入口&#xff0c;有三种形式&#xff1a; 1&#xff09;超级管理员第一次登录数据决策系统时&#xff0c;即可为系统配置外接数据库。如下图所示&#xff1a; 2&#xff09;对于使用内置数据库的系统&#xff0c;管…

蓝桥杯嵌入式|第十三届蓝桥杯嵌入式省赛程序设计试题及其题解

题目 十三届省赛是要制作一个可由串口设置密码的密码锁。在本场比赛中&#xff0c;我们将用到LED模块、按键模块、串口模块、定时器的PWM模块以及官方会提供源码的LCD模块。下面就请看原题&#xff1a; 题解 在正式题解前&#xff0c;大家需要注意以下几点&#xff1a; 由于LCD…

《计算机网络》——第二章知识点

物理层:在连接各种计算机的传输媒体上传输数据比特流&#xff0c;确定与传输媒体接口有关的一些特性。1.机械特性 定义物理连接的特性&#xff0c;规定物理连接时所采用的规格、接口形状、引线数目、引脚数量和排列情况。 2.电气特性 规定传输二进制位时&#xff0c;线路上信…

【深度学习框架TensorFlow】使用TensorFlow框架构建全连接的神经网络,实现手写数字识别

文章目录一.TensorFlow1.1 内容介绍二.开始实验2.1TensorFlow的基本使用2.2基于全连接神经网络的手写数字识别2.3 结论一.TensorFlow 使用深度学习框架TensorFlow。 目标&#xff1a; 1.了解TensorFlow的基本用法&#xff1b; 2.学习使用TensorFlow构建全连接的神经网络&…

双周赛(三)

T1&#xff1a; 如果你仍然再用二指禅打字&#xff0c;那我建议你重新学习打字&#xff0c;这样你打字会更快&#xff0c;感觉更舒适和愉快。 有很多网站教授正确的打字。下图描述了基本原理: 用同一手指按压颜色相同的键。黄色键需要用小指按压&#xff0c;蓝色的用无名指&a…

最新 iOS 更新后 iPhone 联系人和数据丢失/丢失

我两天前做了最新的更新&#xff0c;现在我有丢失的联系人。帮助&#xff01;&#xff01; 许多 iPhone 用户犹豫是否将他们的设备升级到最新的 iOS 系统有一个&#xff08;也许是几个&#xff09;充分的理由。每次 iOS 发布后&#xff0c;总会有新功能震撼我们的世界。但是&am…

Unity 小积累

** Unity 学习小积累 ** 1.FindObjectsOfType和FindObjectOfType 前者返回所有个体&#xff08;集合&#xff09; 后者返回第一个个体 &#xff08;单个&#xff09; 2.uinty打包问题 打包webgl遇到了 实际上和py没有关系 c盘不够了 单纯 3.Unity 默认下载位置 坑 1.Uni…

【css样式】页面实现一侧固定一侧滚动的效果,到底部后一起滚动

文章目录position的定位类型position的定位类型 static&#xff1a;默认值&#xff0c;没有定位&#xff0c;遵循正常的文档流 fixed&#xff1a;固定定位&#xff0c;元素的位置是相对于浏览器窗口 relative&#xff1a;相对定位&#xff0c;相对于其正常的位置&#xff0c;移…