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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

算法(13)-leetcode-explore-learn-数据结构-链表小结

發(fā)布時(shí)間:2023/12/13 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法(13)-leetcode-explore-learn-数据结构-链表小结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

leetcode-explore-learn-數(shù)據(jù)結(jié)構(gòu)-鏈表5

  • 1.小結(jié)
  • 2.例題
    • 2.1合并兩個(gè)有序鏈表
      • 思路1:迭代
      • 思路2:遞歸
    • 2.2 兩數(shù)相加
    • 2.3 扁平化多級(jí)雙向鏈表
    • 2.4 復(fù)制帶隨機(jī)指針的鏈表
    • 2.5 旋轉(zhuǎn)鏈表

本系列博文為leetcode-explore-learn子欄目學(xué)習(xí)筆記,如有不詳之處,請(qǐng)參考leetcode官網(wǎng):https://leetcode-cn.com/explore/learn/card/linked-list/

所有例題的編程語(yǔ)言為python

1.小結(jié)

單鏈表雙鏈表的相同點(diǎn):
1.無(wú)法在常量時(shí)間內(nèi)隨意訪問(wèn)數(shù)據(jù)
2.能夠在o(1)時(shí)間內(nèi),在給定節(jié)點(diǎn)之后完成新節(jié)點(diǎn)的添加
3.能夠在o(1)的時(shí)間內(nèi),刪除鏈表的第一節(jié)點(diǎn)

區(qū)別:刪除給定節(jié)點(diǎn)
單鏈表無(wú)法由給定節(jié)點(diǎn)獲取前一個(gè)節(jié)點(diǎn),因此在刪除給定節(jié)點(diǎn)之前必須花費(fèi)o(n)的時(shí)間來(lái)找出前一個(gè)節(jié)點(diǎn)
雙鏈表中,可以使用“prev”字段獲取前一個(gè)節(jié)點(diǎn),因此能在o(1)的時(shí)間內(nèi)=刪除給定節(jié)點(diǎn)。

鏈表的主要優(yōu)勢(shì):刪除添加節(jié)點(diǎn)十分方便

2.例題

2.1合并兩個(gè)有序鏈表

leetcode 21
將兩個(gè)升序鏈表合并為一個(gè)新的升序鏈表并返回。

思路1:迭代

# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = Noneclass Solution(object):def mergeTwoLists(self, l1, l2):""":type l1: ListNode:type l2: ListNode:rtype: ListNode"""if l1==None or l2==None:return l1 if l1 else l2res_head=ListNode(0)res_curr_node=res_headwhile(l1 and l2):if l1.val<=l2.val:l1_next_node=l1.nextl1.next=Noneres_curr_node.next=l1l1=l1_next_noderes_curr_node=res_curr_node.nextelse:l2_next_node=l2.nextl2.next=Noneres_curr_node.next=l2l2=l2_next_noderes_curr_node=res_curr_node.nextif l1:res_curr_node.next=l1if l2:res_curr_node.next=l2return res_head.next

精簡(jiǎn)寫(xiě)法:

class Solution(object):def mergeTwoLists(self, l1, l2):if l1==None or l2==None:return l1 if l1 else l2res_head=ListNode(0)res_curr_node=res_headwhile(l1 and l2):if l1.val<=l2.val:res_curr_node.next=l1l1=l1.nextelse:res_curr_node.next=l2l2=l2.nextres_curr_node=res_curr_node.nextres_curr_node.next=l1 if l1 else l2 return res_head.next

思路2:遞歸

遞歸最重要的是遞歸出口

class Solution(object):def mergeTwoLists(self, l1, l2):""":type l1: ListNode:type l2: ListNode:rtype: ListNode"""if l1==None:return l2elif l2==None:return l1elif l1.val<=l2.val:l1.next=self.mergeTwoLists(l1.next,l2)return l1 # 由頂向下時(shí),已經(jīng)決定了第一個(gè)節(jié)點(diǎn)是誰(shuí),遞歸得到最底端時(shí),直接將長(zhǎng)鏈表的剩余部分鏈接回已經(jīng)排序好的鏈表中。else:l2.next=self.mergeTwoLists(l1,l2.next)return l2

2.2 兩數(shù)相加

給出兩個(gè) 非空的鏈表 來(lái)表示兩個(gè) 非負(fù)整數(shù)。其中,他們各自的位數(shù)是按照 逆序 方式存儲(chǔ)的,并且每個(gè)節(jié)點(diǎn)只能存儲(chǔ)一位 數(shù)字。

如果,我們將這兩個(gè)數(shù)相加起來(lái),返回一個(gè)新的鏈表表示它們的和

可以假設(shè)除了數(shù)字0之外,兩個(gè)數(shù)字都不會(huì)以0開(kāi)頭

思路:逆序存儲(chǔ)簡(jiǎn)化了問(wèn)題,直接遍歷兩個(gè)鏈表的對(duì)位元素,相加后維護(hù)一個(gè)進(jìn)位標(biāo)志flag。
冗余

# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = Noneclass Solution(object):def addTwoNumbers(self, l1, l2):""":type l1: ListNode:type l2: ListNode:rtype: ListNode"""flag=0res_head=ListNode(0)res_cur_node=res_headwhile(l1 and l2):sum_num=l1.val+l2.val+flagflag=sum_num//10res_cur_node.next=ListNode(sum_num%10)res_cur_node=res_cur_node.nextl1=l1.nextl2=l2.nextwhile(l1):#print(l1.val)sum_num=l1.val+flagflag=sum_num//10res_cur_node.next=ListNode(sum_num%10)res_cur_node=res_cur_node.nextl1=l1.nextwhile(l2):#print(l2.val)sum_num=l2.val+flagflag=sum_num//10res_cur_node.next=ListNode(sum_num%10)res_cur_node=res_cur_node.nextl2=l2.nextif flag:res_cur_node.next=ListNode(flag)return res_head.next

精簡(jiǎn)

class Solution(object):def addTwoNumbers(self, l1, l2):""":type l1: ListNode:type l2: ListNode:rtype: ListNode"""carry=0res_head=ListNode(0)res_cur_node=res_headwhile(l1 or l2 or carry):if l1:carry+=l1.vall1=l1.nextif l2:carry+=l2.vall2=l2.nextcarry,val=divmod(carry,10)res_cur_node.next=ListNode(val)res_cur_node=res_cur_node.nextreturn res_head.next

2.3 扁平化多級(jí)雙向鏈表

多級(jí)雙向鏈表中,除了指向下一個(gè)節(jié)點(diǎn)和前一個(gè)節(jié)點(diǎn)的指針外,它還有一個(gè)子鏈表指針,可能指單獨(dú)的雙向鏈表。這些子鏈表也可能有一個(gè)或多個(gè)自己的子項(xiàng)。一次類推,生成多級(jí)數(shù)據(jù)結(jié)構(gòu) 。

給出位于鏈表第一級(jí)的頭節(jié)點(diǎn),請(qǐng)扁平化鏈表,使所有的節(jié)點(diǎn)出現(xiàn)子啊單級(jí)雙鏈表中。

直覺(jué):采用遞歸的方式求解,可每個(gè)節(jié)點(diǎn)該如何處理呢:
新建一個(gè)res_head,res_head下一個(gè)節(jié)點(diǎn)應(yīng)該為curr_node.child,curr_node.next,

官方思路遞歸:扁平化處理可以看作對(duì)二叉樹(shù)進(jìn)行先序遍歷,child作為二叉樹(shù)中的指向座子樹(shù)的left指針,next可以看作二叉樹(shù)中的right指針。
難點(diǎn):深度優(yōu)先遍歷到了末尾該如何讓扁平化操作?
flatten_dfs(prev, curr)接收兩個(gè)指針作為函數(shù)參數(shù),并返回扁平化鏈表中的尾部指針。curr指向需要扁平化的子列表,prev指向curr元素的前一個(gè)元素。
在dfs函數(shù)中首先要建立prev和curr的雙向鏈接
然后對(duì)左子樹(shù)進(jìn)行操作dfs(curr,cuur.child)其將返回扁平化子列表的尾部元素,再調(diào)用dfs(tail,curr.next)對(duì)右子樹(shù)進(jìn)行操作。注意點(diǎn):
1.在進(jìn)行左子樹(shù)操作時(shí),需要先保存curr.next的信息
2.在扁平化child指針?biāo)赶虻牧斜碇?#xff0c;應(yīng)該刪除child指針

""" # Definition for a Node. class Node(object):def __init__(self, val, prev, next, child):self.val = valself.prev = prevself.next = nextself.child = child """class Solution(object):def flatten(self, head):""":type head: Node:rtype: Node"""if head==None:return headdummy_head=Node(None,None,head,None)self.flatten_dfs(dummy_head,head)dummy_head.next.prev=Nonereturn dummy_head.nextdef flatten_dfs(self,prev,curr):if curr==None:return prevcurr.prev=prevprev.next=currtempNext=curr.nexttail=self.flatten_dfs(curr,curr.child)curr.child=Nonereturn self.flatten_dfs(tail,tempNext)

官方思路迭代:

2.4 復(fù)制帶隨機(jī)指針的鏈表

給定一個(gè)鏈表,每個(gè)節(jié)點(diǎn)包含一個(gè)額外增加的隨機(jī)指針,該指針可以指向鏈表中的任何節(jié)點(diǎn)或空節(jié)點(diǎn)
編程實(shí)現(xiàn)這個(gè)鏈表的深度拷貝

難點(diǎn):新建節(jié)點(diǎn),很簡(jiǎn)單,隨機(jī)節(jié)點(diǎn)該如何指向?

先遍歷一遍形成一個(gè)單鏈表,再遍歷一遍原鏈表找到帶隨機(jī)指針的節(jié)點(diǎn),在單鏈表中找到對(duì)應(yīng)的節(jié)點(diǎn),難的是對(duì)應(yīng)節(jié)點(diǎn)怎么找,因?yàn)?#xff0c;指針存的是地址,在新鏈表中并不知道該指向哪一個(gè)?解決方案–維護(hù)一張map映射表,每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的新節(jié)點(diǎn),因此便可以找到對(duì)應(yīng)的節(jié)點(diǎn)。

""" # Definition for a Node. class Node:def __init__(self, x, next=None, random=None):self.val = int(x)self.next = nextself.random = random """class Solution(object):def copyRandomList(self, head):""":type head: Node:rtype: Node"""if head==None:return NonevisitedHash={}res_head=Node(0)res_cur_node=res_headcur_node=headwhile(cur_node):node=Node(cur_node.val,None,None)res_cur_node.next=nodevisitedHash[cur_node]=noderes_cur_node=res_cur_node.nextcur_node=cur_node.nextcur_node=headres_cur_node=res_head.nextwhile(cur_node):if cur_node.random:node=visitedHash[cur_node.random]res_cur_node.random=nodecur_node=cur_node.nextres_cur_node=res_cur_node.nextreturn res_head.next

參考官網(wǎng)給題解:遞歸
帶隨機(jī)指針的鏈表可以看作一張圖,要做的是遍歷整張圖,并拷貝它??截惖囊馑际敲慨?dāng)遇到一個(gè)新的未訪問(wèn)過(guò)的節(jié)點(diǎn),需創(chuàng)造新的節(jié)點(diǎn)。在回溯的過(guò)程中記錄訪問(wèn)過(guò)的節(jié)點(diǎn),否則因?yàn)殡S機(jī)指針存在,會(huì)導(dǎo)致死循環(huán)。

""" # Definition for a Node. class Node:def __init__(self, x, next=None, random=None):self.val = int(x)self.next = nextself.random = random """class Solution(object):def __init__(self):self.visitedHash={}def copyRandomList(self, head):""":type head: Node:rtype: Node"""if head==None:return Noneif head in self.visitedHash:return self.visitedHash[head]node=Node(head.val,None,None)self.visitedHash[head]=nodenode.next=self.copyRandomList(head.next)node.random=self.copyRandomList(head.random)return node

2.5 旋轉(zhuǎn)鏈表

給定一個(gè)鏈表,將鏈表的每個(gè)節(jié)點(diǎn)向右移動(dòng)k個(gè)位置,其中k是非負(fù)數(shù)。

思路1:和旋轉(zhuǎn)數(shù)組一樣,每次右移一位,移動(dòng)K次即可

# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = Noneclass Solution(object):def rotateRight(self, head, k):""":type head: ListNode:type k: int:rtype: ListNode"""if head==None or head.next==None:return headl=0cur_node=headwhile(cur_node):l+=1cur_node=cur_node.nextk=k%ldef rotate_one_step(head):pre_pre_node=Nonepre_node=headcur_node=head.nextwhile(cur_node):pre_pre_node=pre_nodepre_node=cur_nodecur_node=cur_node.nextpre_pre_node.next=Nonepre_node.next=headreturn pre_nodewhile(k>0):head=rotate_one_step(head)k-=1return head

思路2: 移動(dòng)k次,就是將倒數(shù)的k個(gè)節(jié)點(diǎn)相對(duì)順序不變的移動(dòng)到鏈表的頭部。所以從鏈表的head開(kāi)始,往后找到L-k個(gè)節(jié)點(diǎn),將后半部分移動(dòng)到鏈表的前半部分。

# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = Noneclass Solution(object):def rotateRight(self, head, k):""":type head: ListNode:type k: int:rtype: ListNode"""if head==None or head.next==None:return headl=0cur_node=headwhile(cur_node):l+=1cur_node=cur_node.nextk=k%l# 首尾相連pre_node=Nonecur_node=headwhile(cur_node):pre_node=cur_nodecur_node=cur_node.nextpre_node.next=head# 尋找切割點(diǎn)cur_node=headfor _ in range(1,l-k): #[0,l-k-1]cur_node=cur_node.next# 確定的新的頭部new_head=cur_node.nextcur_node.next=Nonereturn new_head

總結(jié)

以上是生活随笔為你收集整理的算法(13)-leetcode-explore-learn-数据结构-链表小结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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