精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

重新排列一個單鏈表

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:吳師兄學算法 ? 作者:吳師兄 ? 2022-10-10 09:39 ? 次閱讀

一、題目描述

給定一個單鏈表 L:L0→L1→…→Ln-1→Ln ,

將其重新排列后變?yōu)椋篖0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是單純的改變節(jié)點內(nèi)部的值,而是需要實際的進行節(jié)點交換。

示例1:

給定鏈表 1->2->3->4->5, 重新排列為 1->5->2->4->3.

示例2:

給定鏈表 1->2->3->4, 重新排列為 1->4->2->3.

1a525330-47bb-11ed-a3b6-dac502259ad0.png

二、題目解析

這道題目很考察基本功和觀察能力,最終的結(jié)果就是將原鏈表的前半部分和原鏈表的后半部分反轉(zhuǎn)之后的鏈表進行合并得到的

所以,需要執(zhí)行以下三個操作。

1、尋找出原鏈表的中點,把鏈表劃分為兩個區(qū)域

2、將右邊的鏈表進行反轉(zhuǎn)

3、把這兩個區(qū)域進行交錯合并

1、使用快慢指針尋找鏈表中點

在鏈表的頭節(jié)點設(shè)置兩個指針 slow、fast,同時將它們向后移動。

1a9fbd82-47bb-11ed-a3b6-dac502259ad0.png

每一次,slow 向后移動一步,fast 向后移動兩步。

1acce5aa-47bb-11ed-a3b6-dac502259ad0.png1b0d0af4-47bb-11ed-a3b6-dac502259ad0.png

于是,找到了中間節(jié)點 5,把鏈表劃分為兩個區(qū)域。

1b2a6f86-47bb-11ed-a3b6-dac502259ad0.png

2、將右邊的鏈表進行反轉(zhuǎn)

1b68b21e-47bb-11ed-a3b6-dac502259ad0.png

3、把這兩個區(qū)域進行交錯合并

屬于歸并排序的降維版本,這個操作不了解的話可以復習一下歸并排序

三、參考代碼

1、Java 代碼

//登錄AlgoMooc官網(wǎng)獲取更多算法圖解
//https://www.algomooc.com
//作者:程序員吳師兄
//代碼有看不懂的地方一定要私聊咨詢吳師兄呀
//重排鏈表(LeetCode 143):https://leetcode.cn/problems/reorder-list/
classSolution{
publicvoidreorderList(ListNodehead){
//a、尋找出原鏈表的中點,把鏈表劃分為兩個區(qū)域
//b、將右邊的鏈表進行反轉(zhuǎn)
//c、把這兩個區(qū)域進行交錯合并

//1、使用快慢指針尋找出鏈表的中點來
//*******************************************************
//對于1->2->3->4->5->6->7->8
//中間節(jié)點值為5
//所以左邊區(qū)域為1->2->3->4->5
//右邊區(qū)域為6->7->8
//但在視頻講解中,我把5歸為了右邊區(qū)域,這是一個錯誤
//雖然這個錯誤并不影響結(jié)果,因為合并過程都是一樣的邏輯
//*******************************************************
ListNodemid=middleNode(head);

//2、基于mid這個中點,將鏈表劃分為兩個區(qū)域

//左邊的區(qū)域開頭節(jié)點是head
ListNodeleftHead=head;

//右邊的區(qū)域開頭節(jié)點是mid.next
ListNoderightHead=mid.next;

//將鏈表斷開,就形成了兩個鏈表了
mid.next=null;

//3、將右邊的鏈表進行反轉(zhuǎn)
rightHead=reverseList(rightHead);

//4、將這兩個鏈表進行合并操作,即進行【交錯拼接】
while(leftHead!=null&&rightHead!=null){

//拼接過程如下
//5、先記錄左區(qū)域、右區(qū)域【接下來將有訪問的兩個節(jié)點】
ListNodeleftHeadNext=leftHead.next;

ListNoderightHeadNext=rightHead.next;

//6、左邊連接右邊的開頭
leftHead.next=rightHead;

//7、leftHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
leftHead=leftHeadNext;

//8、右邊連接左邊的開頭
rightHead.next=leftHead;

//9、rightHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
rightHead=rightHeadNext;

}

}

//LeetCode876:鏈表的中間節(jié)點
publicListNodemiddleNode(ListNodehead){

ListNodefast=head;

ListNodeslow=head;

while(fast!=null&&fast.next!=null){

fast=fast.next.next;

slow=slow.next;
}

returnslow;

}

//LeetCode206:反轉(zhuǎn)鏈表
publicListNodereverseList(ListNodehead){

//尋找遞歸終止條件
//1、head指向的結(jié)點為null
//2、head指向的結(jié)點的下一個結(jié)點為null
//在這兩種情況下,反轉(zhuǎn)之后的結(jié)果還是它自己本身
if(head==null||head.next==null)returnhead;

//不斷的通過遞歸調(diào)用,直到無法遞歸下去,遞歸的最小粒度是在最后一個節(jié)點
//因為到最后一個節(jié)點的時候,由于當前節(jié)點head的next節(jié)點是空,所以會直接返回head
ListNodecur=reverseList(head.next);

//比如原鏈表為1-->2-->3-->4-->5
//第一次執(zhí)行下面代碼的時候,head為4,那么head.next=5
//那么head.next.next就是5.next,意思就是去設(shè)置5的下一個節(jié)點
//等號右側(cè)為head,意思就是設(shè)置5的下一個節(jié)點是4

//這里出現(xiàn)了兩個next
//第一個next是「獲取」head的下一節(jié)點
//第二個next是「設(shè)置」當前節(jié)點的下一節(jié)點為等號右側(cè)的值
head.next.next=head;


//head原來的下一節(jié)點指向自己,所以head自己本身就不能再指向原來的下一節(jié)點了
//否則會發(fā)生無限循環(huán)
head.next=null;

//我們把每次反轉(zhuǎn)后的結(jié)果傳遞給上一層
returncur;
}
}

2、C++ 代碼

classSolution{
public:
voidreorderList(ListNode*head){
//a、尋找出原鏈表的中點,把鏈表劃分為兩個區(qū)域
//b、將右邊的鏈表進行反轉(zhuǎn)
//c、把這兩個區(qū)域進行交錯合并

//1、使用快慢指針尋找出鏈表的中點來
//*******************************************************
//對于1->2->3->4->5->6->7->8
//中間節(jié)點值為5
//所以左邊區(qū)域為1->2->3->4->5
//右邊區(qū)域為6->7->8
//但在視頻講解中,我把5歸為了右邊區(qū)域,這是一個錯誤
//雖然這個錯誤并不影響結(jié)果,因為合并過程都是一樣的邏輯
//*******************************************************
ListNode*mid=middleNode(head);

//2、基于mid這個中點,將鏈表劃分為兩個區(qū)域

//左邊的區(qū)域開頭節(jié)點是head
ListNode*leftHead=head;

//右邊的區(qū)域開頭節(jié)點是mid->next
ListNode*rightHead=mid->next;

//將鏈表斷開,就形成了兩個鏈表了
mid->next=nullptr;

//3、將右邊的鏈表進行反轉(zhuǎn)
rightHead=reverseList(rightHead);

//4、將這兩個鏈表進行合并操作,即進行【交錯拼接】
while(leftHead!=nullptr&&rightHead!=nullptr){

//拼接過程如下
//5、先記錄左區(qū)域、右區(qū)域【接下來將有訪問的兩個節(jié)點】
ListNode*leftHeadNext=leftHead->next;

ListNode*rightHeadNext=rightHead->next;

//6、左邊連接右邊的開頭
leftHead->next=rightHead;

//7、leftHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
leftHead=leftHeadNext;

//8、右邊連接左邊的開頭
rightHead->next=leftHead;

//9、rightHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
rightHead=rightHeadNext;

}
}



ListNode*middleNode(ListNode*head){
ListNode*slow=head;
ListNode*fast=head;
while(fast!=nullptr&&fast->next!=nullptr){
slow=slow->next;
fast=fast->next->next;
}
returnslow;
}


public:
ListNode*reverseList(ListNode*head){

//尋找遞歸終止條件
//1、head指向的結(jié)點為null
//2、head指向的結(jié)點的下一個結(jié)點為null
//在這兩種情況下,反轉(zhuǎn)之后的結(jié)果還是它自己本身
if(head==NULL||head->next==NULL)returnhead;

//不斷的通過遞歸調(diào)用,直到無法遞歸下去,遞歸的最小粒度是在最后一個節(jié)點
//因為到最后一個節(jié)點的時候,由于當前節(jié)點head的next節(jié)點是空,所以會直接返回head
ListNode*cur=reverseList(head->next);

//比如原鏈表為1-->2-->3-->4-->5
//第一次執(zhí)行下面代碼的時候,head為4,那么head.next=5
//那么head.next.next就是5.next,意思就是去設(shè)置5的下一個節(jié)點
//等號右側(cè)為head,意思就是設(shè)置5的下一個節(jié)點是4

//這里出現(xiàn)了兩個next
//第一個next是「獲取」head的下一節(jié)點
//第二個next是「設(shè)置」當前節(jié)點的下一節(jié)點為等號右側(cè)的值
head->next->next=head;


//head原來的下一節(jié)點指向自己,所以head自己本身就不能再指向原來的下一節(jié)點了
//否則會發(fā)生無限循環(huán)
head->next=nullptr;

//我們把每次反轉(zhuǎn)后的結(jié)果傳遞給上一層
returncur;

}

};

3、Python 代碼

classSolution:
defreorderList(self,head:ListNode)->None:
#a、尋找出原鏈表的中點,把鏈表劃分為兩個區(qū)域
#b、將右邊的鏈表進行反轉(zhuǎn)
#c、把這兩個區(qū)域進行交錯合并

#1、使用快慢指針尋找出鏈表的中點來
#*******************************************************
#對于1->2->3->4->5->6->7->8
#中間節(jié)點值為5
#所以左邊區(qū)域為1->2->3->4->5
#右邊區(qū)域為6->7->8
#但在視頻講解中,我把5歸為了右邊區(qū)域,這是一個錯誤
#雖然這個錯誤并不影響結(jié)果,因為合并過程都是一樣的邏輯
#*******************************************************
mid=self.middleNode(head)

#2、基于mid這個中點,將鏈表劃分為兩個區(qū)域

#左邊的區(qū)域開頭節(jié)點是head
leftHead=head

#右邊的區(qū)域開頭節(jié)點是mid.next
rightHead=mid.next

#將鏈表斷開,就形成了兩個鏈表了
mid.next=None

#3、將右邊的鏈表進行反轉(zhuǎn)
rightHead=self.reverseList(rightHead)

#4、將這兩個鏈表進行合并操作,即進行【交錯拼接】
whileleftHeadandrightHead:

#拼接過程如下
#5、先記錄左區(qū)域、右區(qū)域【接下來將有訪問的兩個節(jié)點】
leftHeadNext=leftHead.next

rightHeadNext=rightHead.next

#6、左邊連接右邊的開頭
leftHead.next=rightHead

#7、leftHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
leftHead=leftHeadNext

#8、右邊連接左邊的開頭
rightHead.next=leftHead

#9、rightHead已經(jīng)處理好,移動到下一個節(jié)點,即剛剛記錄好的節(jié)點
rightHead=rightHeadNext



defmiddleNode(self,head:ListNode)->ListNode:
slow=fast=head
whilefastandfast.next:
slow=slow.next
fast=fast.next.next
returnslow

defreverseList(self,head):
"""
:typehead:ListNode
ListNode
"""
#尋找遞歸終止條件
#1、head指向的結(jié)點為null
#2、head指向的結(jié)點的下一個結(jié)點為null
#在這兩種情況下,反轉(zhuǎn)之后的結(jié)果還是它自己本身
if(head==Noneorhead.next==None):
returnhead

#不斷的通過遞歸調(diào)用,直到無法遞歸下去,遞歸的最小粒度是在最后一個節(jié)點
#因為到最后一個節(jié)點的時候,由于當前節(jié)點head的next節(jié)點是空,所以會直接返回head
cur=self.reverseList(head.next)

#比如原鏈表為1-->2-->3-->4-->5
#第一次執(zhí)行下面代碼的時候,head為4,那么head.next=5
#那么head.next.next就是5.next,意思就是去設(shè)置5的下一個節(jié)點
#等號右側(cè)為head,意思就是設(shè)置5的下一個節(jié)點是4

#這里出現(xiàn)了兩個next
#第一個next是「獲取」head的下一節(jié)點
#第二個next是「設(shè)置」當前節(jié)點的下一節(jié)點為等號右側(cè)的值
head.next.next=head

#原來的下一節(jié)點指向自己,所以head自己本身就不能再指向原來的下一節(jié)點了
#否則會發(fā)生無限循環(huán)
head.next=None

#我們把每次反轉(zhuǎn)后的結(jié)果傳遞給上一層
returncur

四、復雜度分析

時間復雜度:O(N),其中 N 是鏈表中的節(jié)點數(shù)。

空間復雜度:O(1)。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2958

    瀏覽量

    104544
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4782

    瀏覽量

    84452

原文標題:重排鏈表(LeetCode 143)

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數(shù)據(jù)結(jié)構(gòu)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    數(shù)據(jù)結(jié)構(gòu):鏈表的排序

    給定鏈表的頭結(jié)點head(該結(jié)點有值),長度為n的無序鏈表,對其按升序排序后,返回新
    的頭像 發(fā)表于 11-30 13:56 ?1503次閱讀
    數(shù)據(jù)結(jié)構(gòu):<b class='flag-5'>單</b><b class='flag-5'>鏈表</b>的排序

    約瑟夫環(huán)之循環(huán)鏈表這個程序題目大家知道做嗎

    題目:   n個人圍成圈(編號依次為:0,1,2...n-1),從第一個人開始報數(shù),1,2,……數(shù)到m者出列,再從下一個開始重新報數(shù),數(shù)到m者再出列……。 下面的程序中,用不帶附加表
    發(fā)表于 10-27 11:08

    鏈表的缺陷是什么

    鏈表定的缺陷,就是單向性,只能從結(jié)點到下一個節(jié)點,而不能訪問到上
    發(fā)表于 07-14 08:09

    RT-Thread內(nèi)核中鏈表的使用與實現(xiàn)

    1. 鏈表與數(shù)組數(shù)組:線性數(shù)據(jù)結(jié)構(gòu),存放的數(shù)據(jù)的類型是樣的,而且他們在內(nèi)存中的排布是有序排列的。因此數(shù)組的優(yōu)勢就是數(shù)據(jù)連續(xù),隨機訪問速度快,定義好了就不好在改變大小.
    發(fā)表于 04-01 12:01

    OpenHarmony中的HDF鏈表及其迭代器

    成員的值設(shè)置成第1節(jié)點的地址。因為鏈表只支持往方向查找,不支持往回查找,如上面的錯誤范例。如果root記錄的是第二
    發(fā)表于 08-30 10:31

    如何使用EB tresos自動重新排列和計算端口引腳ID?

    我指的是修改bootloader的附件文檔,只是參考3.4,你能告訴我如何使用EB tresos重新排列和自動計算端口pin ID嗎?而且如紅圈所指,我對新的端口ID很困惑,GPIO1_6_LED
    發(fā)表于 03-17 09:03

    C語言實現(xiàn)鏈表舉例

    所謂鏈表,就是用組任意的存儲單元存儲線性表元素的種數(shù)據(jù)結(jié)構(gòu)。鏈表又分為鏈表、雙向
    發(fā)表于 07-11 16:40 ?87次下載
    C語言實現(xiàn)<b class='flag-5'>單</b><b class='flag-5'>鏈表</b>舉例

    鏈表——求兩城市的距離

    鏈表,鍵盤輸入城市名稱和城市的坐標,可以在菜單中選擇你要進行的內(nèi)容
    發(fā)表于 11-26 15:45 ?1次下載

    合并兩排序的鏈表

    合并兩排序的鏈表、題目要求 輸入兩單調(diào)遞增的鏈表,輸出兩
    發(fā)表于 01-16 22:02 ?576次閱讀

    Linux USB總線的兩鏈表

    USB 總線引出兩首要 的鏈表為 USB 設(shè)備
    發(fā)表于 04-20 10:33 ?963次閱讀

    鏈表學習的超詳細說明(二)

    昨天跟大家分享了鏈表些基本用法,今天接著繼續(xù)和大家分享鏈表的用法,今天分享完,
    的頭像 發(fā)表于 12-24 17:33 ?743次閱讀

    鏈表學習的總結(jié)(

    想必大多數(shù)人和我樣,剛開始學數(shù)據(jù)結(jié)構(gòu)中的鏈表還是蠻吃力的,特別是后面的雙鏈表操作更是如此。還有就是在實踐代碼操作時,你又會感到無從下手,沒有思路。
    的頭像 發(fā)表于 12-24 17:35 ?3388次閱讀

    LeetCode876鏈表的中間結(jié)點介紹

    給定頭結(jié)點為 head 的非空鏈表,返回鏈表的中間結(jié)點。
    的頭像 發(fā)表于 01-11 17:58 ?798次閱讀
    LeetCode876<b class='flag-5'>鏈表</b>的中間結(jié)點介紹

    C語言的鏈表應(yīng)用

    最近在看些開源項目,大佬的思路還是很值得去學習,今天就簡單介紹一下單鏈表的應(yīng)用,配合回調(diào)函數(shù)可以玩出新花樣,廢話不多說直接看代碼!
    的頭像 發(fā)表于 02-20 15:03 ?561次閱讀

    鏈表和雙鏈表的區(qū)別在哪里

    鏈表和雙鏈表的區(qū)別 鏈表的每一個節(jié)點中只有指向下一個
    的頭像 發(fā)表于 07-27 11:20 ?1605次閱讀
    <b class='flag-5'>單</b><b class='flag-5'>鏈表</b>和雙<b class='flag-5'>鏈表</b>的區(qū)別在哪里