力扣刷题第七天--链表篇

前言

第七天,开启新篇章--链表。数据结构与算法这门课学了过去太久了,所以写题之前得捡捡。上午睡觉,下午第一节课还是困,第二节课考试,晚上才开始学。

内容

一、移除链表元素

203.移除链表元素

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

先解释一下递归和迭代
递归

它涉及到一个函数直接或间接地调用自身的过程。

优点包括代码简洁和可读性强,因为它可以直观地描述问题分解的过程。然而,不恰当地使用递归可能导致性能问题,因为它涉及到大量的函数调用和内存消耗。

迭代

通过重复步骤来解决问题。

迭代的优点在于其性能通常优于递归,因为它避免了大量的函数调用和内存消耗。然而,迭代的代码可能不如递归代码简洁和可读性强。

递归法

递归地调用removeElements函数,以head.Next作为新的head,并删除其所有值等于val的节点。然后,将返回的新链表赋值给head.Next

如果头节点的值等于val,则返回下一个节点作为新的头节点。这样就删除了当前的头节点。

//8ms 4.77MB

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
    if head==nil{
        return head
    }
      head.Next=removeElements(head.Next,val)
      if head.Val==val{
          return head.Next
      }
       return head
}
迭代法 

创建一个新的链表节点dummyHead,并将其Next字段设置为当前链表的头节点head。这样,dummyHead就成为了新链表的头节点,它指向原始链表的头节点。

返回处理后的链表的头节点。由于我们在前面使用了一个虚拟头节点,所以返回的是dummyHead.Next而不是dummyHead。

//4ms 4.34MB 优解

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

 比较两段代码

一,注意Val和val

二,leetcode里,链表的结点都默认定义好了,直接用就行了,都没有注意到链表的结点是如何定义的。而在面试的时候,一旦要自己手写链表,就写的错漏百出。 

三,一个是在原链表进行删除,此时需要单独考虑头结点的情况,一个是创建一个虚拟头结点

四,当从链表中删除一个结点时,Go语言会自动进行内存回收。不需要显式地释放链表中删除节点的内存,使得Go语言的内存使用更加高效,并且减少了因手动管理内存而引起的错误。(有的语言是没有的)

二、反转链表

206.反转链表

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

本题为后端高频面试题,收录于《热招技术岗上岸指南

递归法

这里就用官方解释,方便理解 //0ms 2.65MB

func reverseList(head *ListNode) *ListNode {
         
     if head==nil||head.Next==nil{
         return head
     }
     newHead:=reverseList(head.Next)
     head.Next.Next=head
     head.Next=nil
     return newHead
}
迭代法/双指针法

定义pre和cur两个指针,temp保存cur的下一个结点。

cur.Next=pre是关键步骤,cur的下一个结点设置为pre,就指向了原本的前一个结点。

仔细想想 想清楚 //0ms 2.35MB

func reverseList(head *ListNode) *ListNode {
    var pre *ListNode
    cur:=head
    for cur!=nil{
      temp:=cur.Next//保存cur的下一个节点 因为接下来要改变cur.next
      //将cur.next 指向pre ,此时已经反转了第一个节点了
     cur.Next=pre// 翻转操作
     // 更新pre 和 cur指针
     pre=cur
     cur=temp
    }
    return pre//此时我们return pre指针就可以了,pre指针就指向了新的头结点
}

最后

链表确实不熟,怎么变换确实得想清楚。

想到一个点,短时间的努力,是体现不出你和别人的差距的。所以,一定要坚持,不要放弃!

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值