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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

详解单链表经典OJ题

發(fā)布時(shí)間:2025/3/20 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 详解单链表经典OJ题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 前言
  • 一 刪除鏈表中等于給定值“val”的所有節(jié)點(diǎn)
  • 二 反轉(zhuǎn)一個(gè)單鏈表
  • 三 求中間節(jié)點(diǎn)
  • 四 鏈表倒數(shù)第K個(gè)節(jié)點(diǎn)
  • 五 合并有序鏈表
  • 六 鏈表分割
    • 注意細(xì)節(jié):
  • 七 刪除重復(fù)結(jié)點(diǎn)
  • 八 鏈表的回文結(jié)構(gòu)
  • 九 相交鏈表
  • 十 判斷表中是否有環(huán)
  • 十一 環(huán)形鏈表II
  • OJ題目網(wǎng)址

前言

本篇文章主要就是講述數(shù)據(jù)結(jié)構(gòu)中鏈表有關(guān)的一些經(jīng)典的OJ題,文末也給大家提供了OJ題的具體網(wǎng)址供大家練習(xí),通過(guò)這些OJ題希望對(duì)你理解鏈表有一個(gè)更深層次的理解,最后創(chuàng)作不易,希望大家能夠給予鼓勵(lì),點(diǎn)點(diǎn)贊,評(píng)論交流學(xué)習(xí)!

一 刪除鏈表中等于給定值“val”的所有節(jié)點(diǎn)

例如:
輸入:head = [1,2,6,3,6], val = 6
輸出:[1,2,3]

圖解過(guò)程:


刪除之后

思路有了之后,代碼如下:

public nodelist deletion(int val){if (head==null)return null;nodelist cur=head;while (cur!=null){while(cur.next!=null&&cur.next.val==val){cur.next=cur.next.next;}cur=cur.next;}if(head.val==val){head=head.next;}return head;}

二 反轉(zhuǎn)一個(gè)單鏈表

例如:
輸入:head = [1,2,3,4,5]
輸出:[5,4,3,2,1]



代碼具體實(shí)現(xiàn)

public nodelist fanzhuang(){nodelist prve=null;nodelist cur=head.next;while (cur!=null){head.next=prve;prve=head;head=cur;cur=cur.next;}head.next=prve;return head;}

三 求中間節(jié)點(diǎn)

給定一個(gè)帶有頭結(jié)點(diǎn) head 的非空單鏈表,返回鏈表的中間結(jié)點(diǎn)。如果有兩個(gè)中間結(jié)點(diǎn),則返回第二個(gè)中間結(jié)點(diǎn)。
例如:
head=[1,2,3,4,5] 返回3
head=[1,2,3,4] 返回3

圖解分析

代碼實(shí)現(xiàn):

//中間節(jié)點(diǎn)問題//解決方法快慢指針public nodelist midnode(){nodelist fast=head;nodelist slow=head;while (fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;}return slow;}

對(duì)于兩個(gè)節(jié)點(diǎn)的分析方法可以自己畫圖體會(huì),就能更好的理解這個(gè)題目。在這里我們提出一個(gè)變式,如果有兩個(gè)節(jié)點(diǎn),我們要求要返回第一個(gè)節(jié)點(diǎn)該怎么做?
具體的代碼實(shí)現(xiàn)如下:

public nodelist midnode(){nodelist fast=head;nodelist slow=head;while (fast!=null&&fast.next!=null){fast=fast.next.next;if (fast==null){return slow;}slow=slow.next;}return slow;}

四 鏈表倒數(shù)第K個(gè)節(jié)點(diǎn)


具體代碼實(shí)現(xiàn):

//求倒數(shù)第k個(gè)節(jié)點(diǎn)public nodelist node(int k){if (k<0||head==null)return null;nodelist slow=head;nodelist fast=head;while (k-1!=0){fast=fast.next;if (fast==null){//如果超出了范圍,那么fast應(yīng)該是一個(gè)nullreturn null;}k--;}while (fast.next!=null){fast=fast.next;slow=slow.next;}return slow;}

五 合并有序鏈表

將兩個(gè)有序鏈表合并為一個(gè)新的有序鏈表并返回。新鏈表是通過(guò)拼接給定的兩個(gè)鏈表的所有節(jié)點(diǎn)組成的。



對(duì)于這種題目我們可以采用,創(chuàng)建一個(gè)新的節(jié)點(diǎn),然后把他們都給串起來(lái)具體實(shí)現(xiàn)代碼如下:

//合并有序列表public static nodelist mergeTwoLists(nodelist head, nodelist head1) {nodelist newhead=new nodelist(-1);//創(chuàng)建一個(gè)新的節(jié)點(diǎn)nodelist cur=newhead;while(head!=null&&head1!=null){if(head.val<head1.val){cur.next=head;cur=head;head=head.next;}else{cur.next=head1;cur=head1;head1=head1.next;}}if(head==null){cur.next=head1;}else{cur.next=head;}return newhead.next;}

六 鏈表分割

問題描述:

現(xiàn)有一鏈表的頭指針 ListNode head,給一定值x,編寫一段代碼將所有小于x的結(jié)點(diǎn)排在其余結(jié)點(diǎn)之前,且不能改變?cè)瓉?lái)的數(shù)據(jù)順序,返回重新排列后的鏈表的頭指針。

鏈表分割前:

分割之后:

在這里要注意的是,我們還得要先定義一個(gè)cur去遍歷鏈表,然后再利用這四個(gè)空結(jié)點(diǎn)將他們串起來(lái)。這里要值得注意的是對(duì)于一開始進(jìn)入的as,ae,bs,be,我們需要分開討論。

注意細(xì)節(jié):

1 如果x的值取的合適,對(duì)于分割的鏈表前半部分可能是沒有數(shù)據(jù)的,也就是說(shuō)as=null,那么此時(shí)我們就必須返回bs(如果后半部分也為空,那就說(shuō)明就是一個(gè)空鏈表)
2 判斷完上一個(gè)之后,我們必須要讓ae.next=bs,這樣才能把分割的鏈表鏈接起來(lái)
3 對(duì)于分割鏈表,我們不可能確保最后一個(gè)元素一定是在第二部分,也有可能是在第一部分,那么這個(gè)時(shí)候就會(huì)有一個(gè)問題,那就是這個(gè)鏈表沒有尾巴了,所以我們要把be.next置為null
具體代碼實(shí)現(xiàn):

//鏈表的分割public static nodelist spiltist(nodelist head,int x){nodelist as=null;nodelist ae=null;nodelist bs=null;nodelist be=null;nodelist cur=head;if (head==null)return null;while (cur!=null){if (cur.val<x){//第一次進(jìn)入if (as==null){as=cur;ae=cur;}else{//不是第一次進(jìn)入ae.next=cur;ae=ae.next;}}else{//第一次進(jìn)入if (bs==null){bs=cur;be=cur;}else{//不是第一次進(jìn)入be.next=cur;be=be.next;}}cur=cur.next;}if (as==null){//判斷前半部分是否會(huì)有數(shù)據(jù)return bs;}ae.next=bs;//把前后兩個(gè)部分拼接起來(lái)if (bs!=null&&be.next!=null){//判斷be.next是否為null,不是null,手動(dòng)置為nullbe.next=null;}return as;}

七 刪除重復(fù)結(jié)點(diǎn)

問題描述:

在一個(gè)排序的鏈表中,存在重復(fù)的結(jié)點(diǎn),請(qǐng)刪除該鏈表中重復(fù)的結(jié)點(diǎn),重復(fù)的結(jié)點(diǎn)不保留,返回鏈表頭指針。 例如,鏈表 1->2->3->3->4->4->5 處理后為 1->2->5

刪除前:

刪除后:

通過(guò)以上兩張圖片,我們可以利用一個(gè)傀儡結(jié)點(diǎn),去把那些不重復(fù)的節(jié)點(diǎn)給串起來(lái),然后返回new.next就會(huì)是我們要得到的鏈表。
注意細(xì)節(jié):
1 不能一眼認(rèn)定,newhead.next就是head,這是不對(duì)的,因?yàn)槿绻粋€(gè)鏈表為{1,1,2,3},就可以說(shuō)明這個(gè)錯(cuò)誤的觀點(diǎn)
2 對(duì)于傀儡結(jié)點(diǎn)與鏈表直接的聯(lián)系,我們可以通過(guò)定義一個(gè)temp,讓temp=newhead,當(dāng)cur.val!=cur.next.val的時(shí)候,讓temp.next=cur
具體代碼實(shí)現(xiàn)如下:

//刪除重復(fù)的結(jié)點(diǎn)public nodelist delet(){nodelist newhead=new nodelist(1);nodelist cur=head;nodelist temp=newhead;while (cur!=null){if (cur.next!=null&&cur.val==cur.next.val){while(cur.next!=null&&cur.val==cur.next.val){//存在多個(gè)重復(fù)值的情況cur=cur.next;}cur=cur.next;}else{temp.next=cur;cur=cur.next;temp=temp.next;}}if(temp.next!=null){temp.next=null;}return newhead.next;}

這里要特別提一下最后的if語(yǔ)句,在這個(gè)代碼中,如果鏈表為{1,2,3,3,3},如果沒有if語(yǔ)句那么最后重復(fù)的節(jié)點(diǎn)是刪不去的,根據(jù)上面代碼,我們要得到的就是當(dāng)cur=null的時(shí)候,temp.next=null,所以在這里我們有必要在這里進(jìn)行一個(gè)這樣的判斷。

八 鏈表的回文結(jié)構(gòu)

對(duì)于一個(gè)鏈表,請(qǐng)?jiān)O(shè)計(jì)一個(gè)時(shí)間復(fù)雜度為O(n),額外空間復(fù)雜度為O(1)的算法,判斷其是否為回文結(jié)構(gòu)。給定一個(gè)鏈表的頭指針A,請(qǐng)返回一個(gè)bool值,代表其是否為回文結(jié)構(gòu)
例如:1->2->2->1
返回:true


一 需要利用快慢指針找到中點(diǎn)

二 反轉(zhuǎn)鏈表


在反轉(zhuǎn)鏈表中,我們需要定義一個(gè)cur,讓cur.next=slow,這樣就完成了當(dāng)前slow所在的下一個(gè)節(jié)點(diǎn)的反轉(zhuǎn),我們還需要往下走,需要在定義一個(gè)curNext去記錄cur的下一個(gè)節(jié)點(diǎn),不然后一個(gè)節(jié)點(diǎn)就找不到了,我們?cè)诎裺low=cur,這樣就把slow往后移了一位,我們?cè)诹頲ur=curNext,curNext=curNext.next(這里的要注意要利用一個(gè)if語(yǔ)句判斷一下,curNext是否為null),結(jié)合上述,最終的目的就是反轉(zhuǎn)到最后一個(gè)節(jié)點(diǎn)(就是slow的位置要在最后一個(gè)節(jié)點(diǎn)上),那么我們反轉(zhuǎn)節(jié)點(diǎn)肯定不止一個(gè),所以我們是需要一個(gè)循環(huán)的,那么這個(gè)循環(huán)的終止條件就是cur!=null
三 判斷回文結(jié)構(gòu)
從反轉(zhuǎn)之后的圖片來(lái)看,如果是回文結(jié)構(gòu),那么此時(shí)我們slow與head同時(shí)往后走,那么就會(huì)有head與slow相遇。這里就要特別說(shuō)一下,以上情況是針對(duì)奇數(shù)個(gè)節(jié)點(diǎn)展開的討論,偶數(shù)節(jié)點(diǎn)其實(shí)也是一樣的,只不過(guò)在判斷時(shí),變成head.next=slow,具體的圖可以自己嘗試去畫一畫。在代碼中,我會(huì)把兩種情況的總代碼寫出來(lái)。
代碼展示

public class PalindromeList {public boolean chkPalindrome(ListNode head) {// write code hereif(head==null||head.next==null)return false;//尋找中點(diǎn)ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}//反轉(zhuǎn)鏈表ListNode cur=slow.next;ListNode curNext=cur.next;while(cur!=null){cur.next=slow;slow=cur;cur=curNext;if(curNext!=null){curNext=curNext.next;}}//判斷回文結(jié)構(gòu)while(head!=slow){if(head.val==slow.val){head=head.next;slow=slow.next;if(head.next==slow){return true;}}else{return false;}}return true;} }

九 相交鏈表

題目描述

給你兩個(gè)單鏈表的頭節(jié)點(diǎn) headA 和 headB ,請(qǐng)你找出并返回兩個(gè)單鏈表相交的起始節(jié)點(diǎn)。如果兩個(gè)鏈表不存在相交節(jié)點(diǎn),返回 null 。


對(duì)于相交節(jié)點(diǎn),我們同樣采用快慢指針的做法,設(shè)headA=slow,headB=fast,從圖中我們可以看出B比A長(zhǎng),那么我們就要定義一個(gè)整形,來(lái)表示B與A之間的長(zhǎng)度之差,讓fast多走這個(gè)差步,之后fast與slow一起走,之后就會(huì)相遇,我們就返回相遇的節(jié)點(diǎn)

對(duì)于所給的鏈表,也可以是這種,那么這個(gè)時(shí)候也不要緊,我們可以利用一個(gè)if在前一個(gè)的基礎(chǔ)上來(lái)判斷一下,如果B更長(zhǎng),我們就可以交換一下fast與slow的指向
具體實(shí)現(xiàn)代碼如下:

public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode slow=headA;ListNode fast=headB;int lena = 0;int lenb = 0;while(slow!=null){lena++;slow=slow.next;}while(fast!=null){lenb++;fast=fast.next;}slow=headA;fast=headB;int c=lenb-lena;if(c<0){fast=headA;slow=headB;c=lena-lenb;}while(c!=0){fast=fast.next;c--;}while(fast!=slow){fast=fast.next;slow=slow.next;}return slow;} }

十 判斷表中是否有環(huán)


對(duì)于是否成環(huán)問題,我們采用快慢指針前去解決,我們讓fast一次走兩步,slow一次走一步,那么slow與fast終究會(huì)相遇的,可不敢讓fast走三次,如果只有兩個(gè)節(jié)點(diǎn),那么是永遠(yuǎn)不會(huì)相遇的
具體代碼實(shí)現(xiàn)如下

public class Solution {public boolean hasCycle(ListNode head) {if(head==null||head.next==null)return false;ListNode fast=head.next;ListNode slow=head;while(fast!=null&&fast.next!=null){if(fast==slow){return true;}slow=slow.next;fast=fast.next.next;}return false;} }

十一 環(huán)形鏈表II

給定一個(gè)鏈表,返回鏈表開始入環(huán)的第一個(gè)節(jié)點(diǎn)。 如果鏈表無(wú)環(huán),則返回 null。

如圖我們就是要返回2這個(gè)節(jié)點(diǎn),對(duì)于這種題,我們也是利用快慢指針前去解決
1 先找到fast與slow的相遇點(diǎn)
2 令fast與slow其中一個(gè)置為頭結(jié)點(diǎn)的位置,兩個(gè)一起走,就會(huì)走到入環(huán)的第一個(gè)節(jié)點(diǎn)
代碼實(shí)現(xiàn):

public class Solution {public ListNode detectCycle(ListNode head) {ListNode slow=head;ListNode fast=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;//假如環(huán)中相遇if(fast==slow){break;}}//沒有相遇if(fast==null||fast.next==null){return null;}slow=head;while(slow!=fast){slow=slow.next;fast=fast.next;}return fast;} }

OJ題目網(wǎng)址

1 刪除鏈表中等于給定值 val 的所有節(jié)點(diǎn)
2 反轉(zhuǎn)一個(gè)單鏈表
3 給定一個(gè)帶有頭結(jié)點(diǎn) head 的非空單鏈表,返回鏈表的中間結(jié)點(diǎn)。如果有兩個(gè)中間結(jié)點(diǎn),則返回第二個(gè)中間結(jié)點(diǎn)。
4 輸入一個(gè)鏈表,輸出該鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)。
5 將兩個(gè)有序鏈表合并為一個(gè)新的有序鏈表并返回。新鏈表是通過(guò)拼接給定的兩個(gè)鏈表的所有節(jié)點(diǎn)組成的。
6 編寫代碼,以給定值x為基準(zhǔn)將鏈表分割成兩部分,所有小于x的結(jié)點(diǎn)排在大于或等于x的結(jié)點(diǎn)之前
7 在一個(gè)排序的鏈表中,存在重復(fù)的結(jié)點(diǎn),請(qǐng)刪除該鏈表中重復(fù)的結(jié)點(diǎn),重復(fù)的結(jié)點(diǎn)不保留,返回鏈表頭指針。
8 鏈表的回文結(jié)構(gòu)
9 輸入兩個(gè)鏈表,找出它們的第一個(gè)公共結(jié)點(diǎn)。
10 給定一個(gè)鏈表,判斷鏈表中是否有環(huán)
11 給定一個(gè)鏈表,返回鏈表開始入環(huán)的第一個(gè)節(jié)點(diǎn)。 如果鏈表無(wú)環(huán),則返回 null

總結(jié)

以上是生活随笔為你收集整理的详解单链表经典OJ题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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