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

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

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

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

基礎算法:差分數(shù)組詳解

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:labuladong ? 作者:labuladong ? 2022-03-16 15:57 ? 次閱讀

讀完本文,可以去力扣解決如下題目:

370. 區(qū)間加法(中等

1109. 航班預訂統(tǒng)計(中等

1094. 拼車中等

PS:這是一年前發(fā)布的論那些小而美的算法技巧:差分數(shù)組/前綴和,我優(yōu)化并添加了很多內(nèi)容,重新發(fā)一遍。

前文說前綴和主要適用的場景是原始數(shù)組不會被修改的情況下,頻繁查詢某個區(qū)間的累加和

這里簡單介紹一下前綴和,核心代碼就是下面這段:

classPrefixSum{
//前綴和數(shù)組
privateint[]prefix;

/*輸入一個數(shù)組,構(gòu)造前綴和*/
publicPrefixSum(int[]nums){
prefix=newint[nums.length+1];
//計算nums的累加和
for(inti=1;i1]+nums[i-1];
}
}

/*查詢閉區(qū)間[i,j]的累加和*/
publicintquery(inti,intj){
returnprefix[j+1]-prefix[i];
}
}
92d3e890-8f11-11ec-952b-dac502259ad0.jpg

prefix[i]就代表著nums[0..i-1]所有元素的累加和,如果我們想求區(qū)間nums[i..j]的累加和,只要計算prefix[j+1] - prefix[i]即可,而不需要遍歷整個區(qū)間求和。

本文講一個和前綴和思想非常類似的算法技巧「差分數(shù)組」,差分數(shù)組的主要適用場景是頻繁對原始數(shù)組的某個區(qū)間的元素進行增減

比如說,我給你輸入一個數(shù)組nums,然后又要求給區(qū)間nums[2..6]全部加 1,再給nums[3..9]全部減 3,再給nums[0..4]全部加 2,再給…

一通操作猛如虎,然后問你,最后nums數(shù)組的值是什么?

常規(guī)的思路很容易,你讓我給區(qū)間nums[i..j]加上val,那我就一個 for 循環(huán)給它們都加上唄,還能咋樣?這種思路的時間復雜度是 O(N),由于這個場景下對nums的修改非常頻繁,所以效率會很低下。

這里就需要差分數(shù)組的技巧,類似前綴和技巧構(gòu)造的prefix數(shù)組,我們先對nums數(shù)組構(gòu)造一個diff差分數(shù)組,diff[i]就是nums[i]nums[i-1]之差

int[]diff=newint[nums.length];
//構(gòu)造差分數(shù)組
diff[0]=nums[0];
for(inti=1;i1];
}
92e64634-8f11-11ec-952b-dac502259ad0.jpg

通過這個diff差分數(shù)組是可以反推出原始數(shù)組nums的,代碼邏輯如下:

int[]res=newint[diff.length];
//根據(jù)差分數(shù)組構(gòu)造結(jié)果數(shù)組
res[0]=diff[0];
for(inti=1;i1]+diff[i];
}

這樣構(gòu)造差分數(shù)組diff,就可以快速進行區(qū)間增減的操作,如果你想對區(qū)間nums[i..j]的元素全部加 3,那么只需要讓diff[i] += 3,然后再讓diff[j+1] -= 3即可:

92fbe9ee-8f11-11ec-952b-dac502259ad0.jpg

原理很簡單,回想diff數(shù)組反推nums數(shù)組的過程,diff[i] += 3意味著給nums[i..]所有的元素都加了 3,然后diff[j+1] -= 3又意味著對于nums[j+1..]所有元素再減 3,那綜合起來,是不是就是對nums[i..j]中的所有元素都加 3 了

只要花費 O(1) 的時間修改diff數(shù)組,就相當于給nums的整個區(qū)間做了修改。多次修改diff,然后通過diff數(shù)組反推,即可得到nums修改后的結(jié)果。

現(xiàn)在我們把差分數(shù)組抽象成一個類,包含increment方法和result方法:

//差分數(shù)組工具類
classDifference{
//差分數(shù)組
privateint[]diff;

/*輸入一個初始數(shù)組,區(qū)間操作將在這個數(shù)組上進行*/
publicDifference(int[]nums){
assertnums.length>0;
diff=newint[nums.length];
//根據(jù)初始數(shù)組構(gòu)造差分數(shù)組
diff[0]=nums[0];
for(inti=1;i1];
}
}

/*給閉區(qū)間[i,j]增加val(可以是負數(shù))*/
publicvoidincrement(inti,intj,intval){
diff[i]+=val;
if(j+11]-=val;
}
}

/*返回結(jié)果數(shù)組*/
publicint[]result(){
int[]res=newint[diff.length];
//根據(jù)差分數(shù)組構(gòu)造結(jié)果數(shù)組
res[0]=diff[0];
for(inti=1;i1]+diff[i];
}
returnres;
}
}

這里注意一下increment方法中的 if 語句:

publicvoidincrement(inti,intj,intval){
diff[i]+=val;
if(j+11]-=val;
}
}

j+1 >= diff.length時,說明是對nums[i]及以后的整個數(shù)組都進行修改,那么就不需要再給diff數(shù)組減val了。

算法實踐

首先,力扣第 370 題「區(qū)間加法」 就直接考察了差分數(shù)組技巧:

930d8cb2-8f11-11ec-952b-dac502259ad0.png

那么我們直接復用剛才實現(xiàn)的Difference類就能把這道題解決掉:

int[]getModifiedArray(intlength,int[][]updates){
//nums初始化為全0
int[]nums=newint[length];
//構(gòu)造差分解法
Differencedf=newDifference(nums);

for(int[]update:updates){
inti=update[0];
intj=update[1];
intval=update[2];
df.increment(i,j,val);
}

returndf.result();
}

當然,實際的算法題可能需要我們對題目進行聯(lián)想和抽象,不會這么直接地讓你看出來要用差分數(shù)組技巧,這里看一下力扣第 1109 題「航班預訂統(tǒng)計」:

932b45b8-8f11-11ec-952b-dac502259ad0.png

函數(shù)簽名如下:

int[]corpFlightBookings(int[][]bookings,intn)

這個題目就在那繞彎彎,其實它就是個差分數(shù)組的題,我給你翻譯一下:

給你輸入一個長度為n的數(shù)組nums,其中所有元素都是 0。再給你輸入一個bookings,里面是若干三元組(i,j,k),每個三元組的含義就是要求你給nums數(shù)組的閉區(qū)間[i-1,j-1]中所有元素都加上k。請你返回最后的nums數(shù)組是多少?

PS:因為題目說的n是從 1 開始計數(shù)的,而數(shù)組索引從 0 開始,所以對于輸入的三元組(i,j,k),數(shù)組區(qū)間應該對應[i-1,j-1]

這么一看,不就是一道標準的差分數(shù)組題嘛?我們可以直接復用剛才寫的類:

int[]corpFlightBookings(int[][]bookings,intn){
//nums初始化為全0
int[]nums=newint[n];
//構(gòu)造差分解法
Differencedf=newDifference(nums);

for(int[]booking:bookings){
//注意轉(zhuǎn)成數(shù)組索引要減一哦
inti=booking[0]-1;
intj=booking[1]-1;
intval=booking[2];
//對區(qū)間nums[i..j]增加val
df.increment(i,j,val);
}
//返回最終的結(jié)果數(shù)組
returndf.result();
}

這道題就解決了。

還有一道很類似的題目是力扣第 1094 題「拼車」,我簡單描述下題目:

你是一個開公交車的司機,公交車的最大載客量為capacity,沿途要經(jīng)過若干車站,給你一份乘客行程表int[][] trips,其中trips[i] = [num, start, end]代表著有num個旅客要從站點start上車,到站點end下車,請你計算是否能夠一次把所有旅客運送完畢(不能超過最大載客量capacity)。

函數(shù)簽名如下:

booleancarPooling(int[][]trips,intcapacity);

比如輸入:

trips=[[2,1,5],[3,3,7]],capacity=4

這就不能一次運完,因為trips[1]最多只能上 2 人,否則車就會超載。

相信你已經(jīng)能夠聯(lián)想到差分數(shù)組技巧了:trips[i]代表著一組區(qū)間操作,旅客的上車和下車就相當于數(shù)組的區(qū)間加減;只要結(jié)果數(shù)組中的元素都小于capacity,就說明可以不超載運輸所有旅客

但問題是,差分數(shù)組的長度(車站的個數(shù))應該是多少呢?題目沒有直接給,但給出了數(shù)據(jù)取值范圍:

0<=?trips[i][1]?

車站個數(shù)最多為 1000,那么我們的差分數(shù)組長度可以直接設置為 1001:

booleancarPooling(int[][]trips,intcapacity){
//最多有1000個車站
int[]nums=newint[1001];
//構(gòu)造差分解法
Differencedf=newDifference(nums);

for(int[]trip:trips){
//乘客數(shù)量
intval=trip[0];
//第trip[1]站乘客上車
inti=trip[1];
//第trip[2]站乘客已經(jīng)下車,
//即乘客在車上的區(qū)間是[trip[1],trip[2]-1]
intj=trip[2]-1;
//進行區(qū)間操作
df.increment(i,j,val);
}

int[]res=df.result();

//客車自始至終都不應該超載
for(inti=0;iif(capacityreturnfalse;
}
}
returntrue;
}

至此,這道題也解決了。

最后,差分數(shù)組和前綴和數(shù)組都是比較常見且巧妙的算法技巧,分別適用不同的常見,而且是會者不難,難者不會。所以,關于差分數(shù)組的使用,你學會了嗎?

原文標題:小而美的算法技巧:差分數(shù)組

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


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

    關注

    23

    文章

    4600

    瀏覽量

    92646
  • 代碼
    +關注

    關注

    30

    文章

    4750

    瀏覽量

    68357
  • 數(shù)組
    +關注

    關注

    1

    文章

    416

    瀏覽量

    25910

原文標題:小而美的算法技巧:差分數(shù)組

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

收藏 人收藏

    評論

    相關推薦

    C語言中的數(shù)組詳解

    數(shù)組:只能存放一種數(shù)據(jù)類型,比如int類型的數(shù)組、float類型的數(shù)組,里面存放的數(shù)據(jù)稱為“元素”。
    發(fā)表于 09-09 10:54 ?1592次閱讀

    數(shù)組與指針詳解

    數(shù)組與指針詳解分享,請多指教!
    發(fā)表于 12-15 11:21

    SVPWM的原理推導和控制算法詳解

    SVPWM的原理推導和控制算法詳解,不錯的資料,值得一看
    發(fā)表于 01-28 15:09

    算法篇(PID詳解)

    算法篇(PID詳解)
    發(fā)表于 05-19 10:30

    AVS分數(shù)像素插值算法的VLSI實現(xiàn)

    基于AVS運動補償分數(shù)像素插值算法,提出了一種新的VLSI結(jié)構(gòu),滿足了AVS基準檔次6.2級別(1920×1080,4:2:2,30 f/s)高清視頻實時解碼的要求。介紹了AVS分數(shù)像素插值
    發(fā)表于 10-15 09:38 ?0次下載

    Java數(shù)組算法試題

    Java數(shù)組算法試題Java數(shù)組算法試題Java數(shù)組算法試題
    發(fā)表于 01-15 16:16 ?0次下載

    PID算法詳解

    PID算法詳解
    發(fā)表于 12-17 20:48 ?12次下載

    C語言數(shù)組詳解

    上述的語句把數(shù)組中第五個元素的值賦為 50.0。所有的數(shù)組都是以 0 作為它們第一個元素的索引,也被稱為基索引,數(shù)組的最后一個索引是數(shù)組的總大小減去 1。以下是上面所討論的
    的頭像 發(fā)表于 09-25 15:43 ?1.5w次閱讀
    C語言<b class='flag-5'>數(shù)組</b><b class='flag-5'>詳解</b>

    分數(shù)階原始對偶去噪模型及其數(shù)值算法

    目的結(jié)合分數(shù)階微積分理論和對偶理論,提出了一種與分數(shù)階ROF去噪模型等價的分數(shù)階原始對偶模型。從理論上分析了該模型與具有鞍點結(jié)構(gòu)的優(yōu)化模型在結(jié)構(gòu)上的相似性,從而可使用求解鞍點問題的數(shù)值算法
    發(fā)表于 12-06 16:02 ?13次下載
    <b class='flag-5'>分數(shù)</b>階原始對偶去噪模型及其數(shù)值<b class='flag-5'>算法</b>

    面向分數(shù)據(jù)挖掘隱私保護的隨機森林算法

    數(shù)據(jù)挖掘中的隱私保護問題是目前信息安全領域的研究熱點之一。針對隱私保護要求下的分類問題,提出一種面向分隱私保護的隨機森林算法 REDPP-Gini。將隨機森林與分隱私保護相結(jié)合,在隱私信息得到
    發(fā)表于 05-12 14:14 ?1次下載

    分數(shù)據(jù)線的ESD保護-PESDXUSB3S_SER

    分數(shù)據(jù)線的ESD保護-PESDXUSB3S_SER
    發(fā)表于 02-20 20:18 ?0次下載
    <b class='flag-5'>差</b><b class='flag-5'>分數(shù)</b>據(jù)線的ESD保護-PESDXUSB3S_SER

    分數(shù)據(jù)線的ESD保護-PESDXUSB3B_C_SER

    分數(shù)據(jù)線的ESD保護-PESDXUSB3B_C_SER
    發(fā)表于 02-20 20:19 ?1次下載
    <b class='flag-5'>差</b><b class='flag-5'>分數(shù)</b>據(jù)線的ESD保護-PESDXUSB3B_C_SER

    分數(shù)據(jù)線的ESD保護-PESDXUSB30_SER

    分數(shù)據(jù)線的ESD保護-PESDXUSB30_SER
    發(fā)表于 02-21 19:33 ?0次下載
    <b class='flag-5'>差</b><b class='flag-5'>分數(shù)</b>據(jù)線的ESD保護-PESDXUSB30_SER

    [源代碼]Python算法詳解

    [源代碼]Python算法詳解[源代碼]Python算法詳解
    發(fā)表于 06-06 17:50 ?0次下載

    怎么增加分對的線性范圍?

    算法的基本原理是將一個序列中的相鄰元素的差值存儲在另一個數(shù)組中。這個數(shù)組稱為分數(shù)組,它
    的頭像 發(fā)表于 09-17 16:25 ?523次閱讀