日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

datawhale组队学习笔记(2)链表

發(fā)布時間:2023/12/19 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 datawhale组队学习笔记(2)链表 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

鏈表基礎(chǔ)知識:

  • 結(jié)構(gòu):
    ①邏輯結(jié)構(gòu):集合、線性結(jié)構(gòu)(一對一)、樹形結(jié)構(gòu)(一對多)、圖結(jié)構(gòu)(多對多);
    ②存儲結(jié)構(gòu):順序存儲(順序表)、鏈?zhǔn)酱鎯?#xff08;鏈?zhǔn)奖?#xff09;、索引存儲、散列存儲。
    2.鏈表分類:
    ①單鏈表、雙鏈表、循環(huán)鏈表(單/雙)
    ②帶頭結(jié)點/不帶頭節(jié)點
    3.(單)鏈表操作:
    插入元素、刪除元素、創(chuàng)建單鏈表(尾插法/頭插法)
  • 結(jié)構(gòu):
    ①邏輯結(jié)構(gòu):集合、線性結(jié)構(gòu)(一對一)、樹形結(jié)構(gòu)(一對多)、圖結(jié)構(gòu)(多對多);
    ②存儲結(jié)構(gòu):順序存儲(順序表)、鏈?zhǔn)酱鎯?#xff08;鏈?zhǔn)奖?#xff09;、索引存儲、散列存儲。
    2.鏈表分類:
    ①單鏈表、雙鏈表、循環(huán)鏈表(單/雙)
    ②帶頭結(jié)點/不帶頭節(jié)點
    3.(單)鏈表操作:
    插入元素、刪除元素、創(chuàng)建單鏈表(尾插法/頭插法)
  • T1 合并兩個有序鏈表

    【法一】迭代(不明失敗嘗試):將list2中的元素插入到list中
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def mergeTwoLists(self, list1, list2):""":type list1: Optional[ListNode]:type list2: Optional[ListNode]:rtype: Optional[ListNode]"""cur1=list1cur2=list2if not cur1:return list2elif not cur2:return list1while cur1 and cur2:if cur2.val<cur1.val: #只會出現(xiàn)在開頭temp=list1list1=cur2 #出現(xiàn)了一個我不能理解的問題就是,它倆綁定了,甚至還影響了list2的值(用逐行return看出來的),但我不能理解為什么,只能知道以后別隨便亂修改鏈表弄一大堆指針啥的,可能以后會明白吧??list1.next=tempcur1=list1cur2=cur2.nextelse: #cur2.val>=cur1.valif cur1.next:if cur2.val>=cur1.next.val:cur1=cur1.nextelse: #cur1.val<= cur2.val <cur1.next.valtemp=cur1.nextnew=cur2cur1.next=newnew.next=tempcur1=cur1.nextcur2=cur2.nextelse: #cur1到達list1的末尾temp=cur1.nextnew=cur2cur1.next=newnew.next=tempcur1=cur1.nextcur2=cur2.nextreturn list1

    整體思路是:
    1.初始:使用兩個指針,cur1指向list1首個結(jié)點,cur2指向list2首個節(jié)點
    2.思路:將list2中的元素逐個插入到list1中(因此要逐個比較cur1和cur2指向元素的大小)
    ①cur1>cur2:
    把cur2指向的元素插入到cur1指向的元素之前,cur1向前移動一位(即繼續(xù)指向新list1的首個節(jié)點)
    ②cur1≤cur2:
    再判斷cur1.next與cur2的大小關(guān)系:
    (a)cur1.next≤cur2:
    將cur1指針后移一位
    (b)cur1.next>cur2:
    直接將cur2對應(yīng)元素插入到cur1之后,cur1和cur2各后移一位

    (中間套上了一層if cur1.next是因為要用到cur1.next.val,如果cur1已經(jīng)指到末尾了會報錯實際上這兩個else寫的是相同的)

    問題:出現(xiàn)了一個我不能理解的問題就是,出現(xiàn)了不符合邏輯的綁定??甚至還混亂地影響了list2的值(用逐行return看出來的),反正結(jié)果就是cur2從list2上跑到新list1上去了,但我不理解為什么會跑,為什么會關(guān)聯(lián)綁定…?只能知道以后別隨便亂選擇修改鏈表的方式,弄一大堆指針啥的,可能以后會明白吧??現(xiàn)在就現(xiàn)在想著創(chuàng)建新鏈表吧。。

    【法二】迭代:創(chuàng)建一個新鏈表,輪流插入list1和list2的元素
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def mergeTwoLists(self, list1, list2):""":type list1: Optional[ListNode]:type list2: Optional[ListNode]:rtype: Optional[ListNode]"""prehead=ListNode(-1) #創(chuàng)建一個新的空頭結(jié)點prev=prehead #創(chuàng)建一個指針,指向空頭結(jié)點(注意:這是指針,是可以修改東西的!)while list1 and list2:if list1.val<=list2.val:prev.next=list1 #指針?biāo)肝恢玫膎extlist1=list1.nextelse:prev.next=list2list2=list2.next #指針?biāo)肝恢玫膎extprev=prev.next #指針后移一位,繼續(xù)修改后面if list1 is None:prev.next=list2elif list2 is None:prev.next=list1#prev.next=list1 if list1 is not None else list2return prehead.next #雖然修改的一直都是prev.next,但是因為那是指針,所以它指到之處,確實被修改了

    關(guān)于指針的問題,仔細想了想其實是這樣:

    ① 像平時(例如之前做的數(shù)組題),當(dāng)我們使用指針時,通常是作為 索引 ,然后根據(jù) nums[cur]來對應(yīng)所指的數(shù)據(jù),自然就是可以修改的,這種指針并不涉及賦值問題,因為這樣的指針是邏輯意義上的索引指針,而不是物理意義上的指針;

    ②關(guān)于賦值問題,比如平時我們 a=1, b=a, a=3 這樣三句的結(jié)果是b=1,a=3,就是說賦值并不會造成關(guān)聯(lián),只是復(fù)制了一下這個值而已,這是普通的賦值語句,但是放到鏈表里,就要注意一些其他的東西了;

    ③在鏈表中用到的指針:

    首先要想明白鏈表的數(shù)據(jù)結(jié)構(gòu),比如list1=[1,2,4],那么:

    list1.val=1, list1.next=[2,4],

    list1.next.val=2, list1.next.next=[4],

    list1.next.next.val=4, list1.next.next.next=None

    要注意,無論是list1還是list1.next這樣,都是 ListNode()類型,可以大致類似于list1=ListNode(),也就是如果我們現(xiàn)在list1=cur,那么cur也是一個ListNode()類型,但實際上并沒有新實例化一個類,而是把cur真正的指到了list1這個位置上,這樣就不再是僅僅單純的賦值語句了,而是真正物理意義上的指針,它修改的是list1的.val或者next,而不是僅僅復(fù)制,因此直接return原部分就可以得到修改后的了。

    【法三】遞歸(與回溯)
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def mergeTwoLists(self, list1, list2):""":type list1: Optional[ListNode]:type list2: Optional[ListNode]:rtype: Optional[ListNode]"""if not list1:return list2if not list2:return list1if list1.val<=list2.val:list1.next=self.mergeTwoLists(list1.next,list2)return list1else:list2.next=self.mergeTwoLists(list1,list2.next)return list2

    T2.移除鏈表元素

    【法一】迭代:依次判斷每個元素

    一個錯誤操作:(對于頭節(jié)點的錯誤處理)

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def removeElements(self, head, val):""":type head: ListNode:type val: int:rtype: ListNode"""cur=headif head:if head.val==val:head=head.nextwhile cur.next:if cur.next.val==val:cur.next=cur.next.nextelse: #這個else一定要注意,如果沒有else并且不縮進的話就錯啦cur=cur.nextreturn head

    正確操作:(對于頭節(jié)點的正確處理)

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def removeElements(self, head, val):""":type head: ListNode:type val: int:rtype: ListNode"""head=ListNode(next=head) #加一個頭結(jié)點pre=head #來一個指針while pre.next:if pre.next.val==val:pre.next=pre.next.nextelse:pre=pre.nextreturn head.next
    【法二】遞歸

    1.錯誤嘗試

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def removeElements(self, head, val):""":type head: ListNode:type val: int:rtype: ListNode"""head=ListNode(next=head) #創(chuàng)建一個空頭結(jié)點cur=head #將指針指向空頭節(jié)點(這在遞歸里是絕對不可以的,因為這個指針會被反復(fù)初始化)if not cur.next:return head.nextif cur.next.val==val:cur.next=cur.next.nextreturn self.removeElements(cur,val)else:return self.removeElements(cur.next,val)
    • “ 將指針指向空頭節(jié)點 ” 在遞歸里是絕對不可以的,因為這個指針會被反復(fù)初始化。

    • 迭代 vs 遞歸:

      ? 迭代時一般來說是需要用到指針的,因為原h(huán)ead要用到return的時候,如果走下去就無法溯源了。遞歸時是不該用指針的,因為在每一次調(diào)用時指針會被反復(fù)初始化;然后因為它是遞歸+回溯,它最后是會回到開頭的,所以其實也不需要弄個指針。

    2.正確遞歸

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def removeElements(self, head, val):""":type head: ListNode:type val: int:rtype: ListNode"""if not head:return Nonehead.next=self.removeElements(head.next,val)if head.val==val:return head.nextelse:return head

    T3. 旋轉(zhuǎn)鏈表

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def rotateRight(self, head, k):""":type head: ListNode:type k: int:rtype: ListNode"""len=0cur=headif not cur:return headwhile cur.next:len+=1cur=cur.nextelse:len+=1cur.next=headcur=cur.nextk_=k%lenfor i in range(len-k_-1):cur=cur.nexthead=cur.nextcur.next=Nonereturn head

    T4.刪除排序鏈表中的重復(fù)元素Ⅰ

    【法一】迭代
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""cur=headif not cur:return headwhile cur.next:if cur.val==cur.next.val:cur.next=cur.next.nextelse:cur=cur.nextreturn head
    【法二】遞歸
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""if not head:return headif not head.next:return headhead.next=self.deleteDuplicates(head.next) #其實基本屬于是子問題重疊+最優(yōu)子結(jié)構(gòu)了if head.val==head.next.val:return head.nextelse:return head

    比較類似于刪除鏈表元素,遞歸解法就是“下一個是誰?”這樣的問題,不過還算是首次盲寫遞歸成功!

    T5.刪除排序鏈表中的重復(fù)元素Ⅱ

    【法一】迭代(兩次循環(huán))(刪除重復(fù)元素+刪除特定元素)
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""a=[]#1 刪除重復(fù)元素(只要刪后面的就好,不需要加啞節(jié)點)cur=headif not cur:return headwhile cur.next:if cur.val==cur.next.val:a.append(cur.val)cur.next=cur.next.nextelse:cur=cur.next#2 刪除特定元素(由于首個節(jié)點也有可能被刪除,所以必須加一個啞節(jié)點)head=ListNode(next=head)cur=headwhile cur.next:if cur.next.val in a:cur.next=cur.next.nextelse:cur=cur.nextreturn head.next

    ? 其中,也可以很明顯的感受到 “ 刪除重復(fù)元素(只要刪后面的就好,不需要加啞節(jié)點)” 和 “ 刪除特定元素(由于首個節(jié)點也有可能被刪除,所以必須加一個啞節(jié)點) ”的區(qū)別。

    【法二】 迭代(一次循環(huán))(刪除重復(fù)元素+刪除特定元素)
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""a=[]head=ListNode(next=head)cur=headif not cur.next:return cur.nextwhile cur.next.next:if cur.next.val==cur.next.next.val:a.append(cur.next.val)cur.next=cur.next.next.nextif not cur.next:breakelif cur.next.val in a:cur.next=cur.next.nextif not cur.next:breakelse:cur=cur.nextif cur.next: #用else就更帶感了if cur.next.val in a:cur.next=cur.next.nextreturn head.next

    ? 那個地方如果用else真的非常合適!因為while…else語句,指的就是:如果while循環(huán)是因為中途break而跳出,則不會執(zhí)行else語句;如果while循環(huán)是因為條件不再符合而退出,則執(zhí)行else語句。而恰好,這里如果 cur.next 還不是None,則最后會因為cur.next.next==None而退出,而如果cur.next變成None了,則循環(huán)判斷語句本身會報錯,因此必須使用break語句跳出,這樣也正好與else應(yīng)對應(yīng)的條件相反。所以這里用while…else(配合內(nèi)部break)非常合適。

    【法三】迭代(一次雙重循環(huán))(察覺+循環(huán)直到消滅)
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""a=[]head=ListNode(next=head)cur=headwhile cur.next and cur.next.next:if cur.next.val==cur.next.next.val:a=cur.next.valwhile cur.next and cur.next.val==a:cur.next=cur.next.nextelse:cur=cur.nextreturn head.next

    ? 這種方法除了提出了明智(相對于法二)的“循環(huán)直到消滅”之外,還有很重要的一點就是,它提出了cur.next and cur.next.next這種,也就是cur.next and cur.next.val==a這種避免出錯的方式,也用不到break啦,自然也不是那么需要while…else語句這種啦。

    【法四】遞歸
    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def deleteDuplicates(self, head):""":type head: ListNode:rtype: ListNode"""if not head or not head.next:return headif head.val!=head.next.val:head.next=self.deleteDuplicates(head.next)else:move=head.nextwhile move and head.val==move.val: #這里在第一次其實是重復(fù)了的,但是更簡潔了move=move.nextreturn self.deleteDuplicates(move) #這就是主要區(qū)別,不用head.next=而用return就是刪掉自己了return head

    總結(jié)

    以上是生活随笔為你收集整理的datawhale组队学习笔记(2)链表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。