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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

给定数组 求和等于固定值 算法_别人家的面试题:不可变数组快速范围求和

發布時間:2024/9/19 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 给定数组 求和等于固定值 算法_别人家的面试题:不可变数组快速范围求和 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(給算法愛好者加星標,修煉編程內功)

來源:十年蹤跡的博客

h5jun.com/post/range-sum-query-immutable.html

這是一道翻譯小組的同學問我的題目,這道題很有意思,在 leetcode 上標記的難度為 Easy, 然而正確率出奇地低,只有不到 25%,看來這是一道看似簡單實際上頗有挑戰性的題目。

不可變數組的范圍求和

給定一個整數數組 nums,計算出從第 i 個元素到第 j 個元素的和 ( i ≤ j ),包括 nums[ i ] 和 nums[ j ]。

例子:

const?nums?=?Object.freeze([-2,?0,?3,?-5,?2,?-1]);sumRange(0, 2) -> 1sumRange(2, 5) -> -1sumRange(0, 5) -> -3

注意:

1、假定數組的值不會改變(如上面代碼,nums 因為 Object.freeze 的緣故可讀不可寫)

2、sumRange 可能會被使用很多次,求不同范圍的值

3、數組可能規模很大(比如超過 10000 個數),注意運行時間

解題思路

這道題看起來十分簡單對吧,簡單寫一個函數應該誰都會:

簡單實現

function sumRange(i, j){ var sum = 0; for(; i <= j; i++){ sum += nums[i]; } return sum;}

不過呢,這么寫,對照上面的注意事項,尤其是后兩條:

  • sumRange 可能會被使用很多次

  • 數組的規模可能會很大

如果考慮這兩條,那么上面的方法可以說是十分慢的,這也是為什么很多人在 leetcode 提交代碼通不過,因為簡單這么算的話,跑 leetcode 的大數組 case 肯定超時。

那么,我們要怎么做才能更快呢?注意到前面說的這是不可變數組了吧?也就是說數組初始化完成之后,它的值不會改變,因此我們可以對它進行拷貝,同時“重新編碼”。

具體怎么做,大家心里是不是已經隱隱有答案了?讓我們思考30秒鐘然后繼續 ——

重構數組

我們可以重新創建一個數組類,用新的數組來計算 sumRange:

重構數組

const Immutable = Sup => class extends Sup { constructor(...args){ super(...args); Object.freeze(this); }}class NumArray extends Immutable(Array){ sumRange(i, j){ let sum = 0; for(; i <= j; i++){ sum += this[i]; } return sum; }}上面的代碼里面我們重構了數組,這里我用了一點點小技巧來讓數組元素不可變,這個技巧在我之前的一篇譯文“六個漂亮的 ES6 技巧”中被提到,很多同學不理解那篇文章的第6個技巧,在這里我使用了一下,當然這無關我們今天討論的主題。

于是我們可以用新的數組對象來計算 sumRange:

var?nums?=?new?NumArray(-2,?0,?3,?-5,?2,?-1);nums.sumRange(0, 2) -> 1nums.sumRange(2, 5) -> -1nums.sumRange(0, 5) -> -3

到這里為止,我們似乎并沒有改變什么,我們只是繼承了 Array 類,把 sumRange 改成了對象的方法而已,它還是一樣很慢。

那接下來我們要怎么做呢?

因為前面說過了,sumRange 要被調用很多次,所以我們要盡可能減少 sumRange 調用的復雜度對嗎?按照前面的方式,我們用一個循環來對從 i 到 j 進行求和,有沒有更快的方法?答案是:空間換時間,查表!

查表

查表不是查水表,因為 sumRange 要計算很多次,所以我們可以事先在 NumArray 構造的時候將 sumRange 需要查的值算好存入一個表中。

二維表?

R/C012345
0-2-21-4-2-3
103-20-1
23-20-1
3-5-3-4
421
5-1

二維表可以將每一對 i, j 完全映射一個值,這樣的話,空間復雜度變成了 O( n2?),記得我們前面說了,這個數組可能會很大,有 10000 個元素,如果用這樣的映射表,內存就溢出了。實際上,使用二維表是愚蠢的,因為我們可以很容易找到以下對應關系:

sumRange(i, j) === sumRange(0, j) - sumRange(0, i - 1); //(i > 0)

一維表

我們只需要將 NumArray 的每一個元素對應從第 1 元素開始求和,將結果保存成一個一維表,我們就可以用 O( 1 ) 時間復雜度來計算 sumRange( i, j ) !

以下是經過優化之后的 NumArray:

使用一維表

const UniqueID = Sup => class extends Sup { constructor(...args){ super(...args); Object.defineProperty(this, "id", { value: Symbol(), writable: false, enumerable: false }); }}const Immutable = Sup => class extends Sup { constructor(...args){ super(...args); Object.freeze(this); }}const NumArray = (function(){ let sumTable = {}; return class extends Immutable(UniqueID(Array)){ constructor(...args){ super(...args); let sum = 0; let table = [0]; for(let i = 0; i < this.length; i++){ sum += this[i]; table.push(sum); } sumTable[this.id] = table; } sumRange(i, j){ let table = sumTable[this.id]; return table[j + 1] - table[i]; } }})();

上面的代碼里,我們在構造 NumArray 的時候同時創建了一個私有屬性 sumTable,它的第 1 個元素是 0,第 i + 1 個元素等于 sumRange(0, i),因此我們就可以快速通過:

sumRange(i, j){ let table = sumTable[this.id]; return table[j + 1] - table[i]; }

來計算出 sumRange(i, j) 的值了。

進一步優化

上面的代碼通過查表大大加快了 sumRange 的執行速度,由于數組 NumArray 是不可變的,因此我們在它被構造的時候創建好 sumTable,那么 sumRange 就完全只需要查表加上一次減法運算就可以完成了。這么做提升了 sumRange 的性能,代價是構造 NumArray 對象的時候帶來額外的建表開銷。

不過,我們可以不在構造對象的時候建表,而在對象的 sumRange 方法第一次被使用的時候建表。這樣的話,我們就將性能開銷延從構造對象時遲到了第一次使用 sumRange 時,如果恰巧某種原因,NumArray 對象沒有被使用,那么 sumTable 就永遠也不會被創建。看下面的代碼:

將創建 sumTable 的工作放在 sumRange 第一次被調用時

const UniqueID = Sup => class extends Sup { constructor(...args){ super(...args); Object.defineProperty(this, "id", { value: Symbol(), writable: false, enumerable: false }); }};const Immutable = Sup => class extends Sup { constructor(...args){ super(...args); Object.freeze(this); }};const NumArray = (function(){ let sumTable = {}; return class extends Immutable(UniqueID(Array)){ sumRange(i, j){ if(!sumTable[this.id]){ let table = [0], sum = 0; for(let i = 0; i < this.length; i++){ sum += this[i]; table.push(sum); } sumTable[this.id] = table; } let table = sumTable[this.id]; return table[j + 1] - table[i]; } }})();

以上是今天我們討論的內容。上面的代碼其實還可以優化,因為我們將建表的工作推遲到 sumRange 第一次被調用時執行,這很好,但這給 sumRange 帶來了一次 if 判斷操作的額外開銷,實際上我們應該也有辦法消除這個開銷,我把這個問題留給大家吧,歡迎大家討論。

推薦閱讀

(點擊標題可跳轉閱讀)

從一個無序數組中查詢最大值的最快算法是什么?

算法數據結構-B樹

覺得本文有幫助?請分享給更多人

關注「算法愛好者」加星標,修煉編程內功

好文章,我在看??

總結

以上是生活随笔為你收集整理的给定数组 求和等于固定值 算法_别人家的面试题:不可变数组快速范围求和的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲综合久久av一区二区三区 | www日韩在线| 免费在线观看黄网站 | 婷婷视频 | 日韩精品视频久久 | 蜜桃一二三区 | 欧美一区二区三区免费在线观看 | 偷啪自啪| 亚洲性综合 | 日韩xxxxxxxxx| 欧美性生交xxxxx久久久 | 久草青青草 | 亚州精品毛片 | jjzz国产 | 日本日韩欧美 | 日本成人黄色片 | 久一视频在线观看 | 午夜视频免费看 | 日韩美女激情 | 亚洲午夜av | 亚洲人掀裙打屁股网站 | 欧美丝袜一区二区三区 | www一区 | 91视频看看 | 夜晚福利视频 | 青青超碰 | 欧美一级黄色片网站 | 成人午夜精品无码区 | 好吊妞在线观看 | 黄色大片日本 | 无码精品一区二区三区在线 | 午夜免费小视频 | ass亚洲熟妇毛耸耸pics | 成人小视频在线看 | 欧美一区二区三区免费在线观看 | 国产精品久久久久久久一区二区 | tube国产麻豆 | 国产在线一级 | 国产欧美视频一区二区三区 | 超碰公开在线观看 | 国产视频一区二区 | 影音先锋啪啪资源 | 欧美大片免费高清观看 | 久久夜靖品2区 | www日日| 老司机午夜影院 | 日韩成人在线视频观看 | 一区二区免费在线播放 | 美国一级片网站 | 日韩jizz| 日韩综合中文字幕 | 影音先锋制服 | 亚洲欧洲免费无码 | 一区二区三区视频免费看 | 中文字幕一区二区人妻痴汉电车 | 欧美婷婷六月丁香综合色 | 美女光屁屁露胸胸 | 性喷潮久久久久久久久 | 亚洲国产精品一区二区久久hs | 综合天堂av久久久久久久 | 草久在线视频 | 国内精品久久久 | 西野翔之公侵犯中文字幕 | 蜜臀少妇久久久久久久高潮 | 操欧美女人 | 蜜桃臀一区二区三区 | 亚洲国产精品二区 | 姐姐你真棒插曲快来救救我电影 | 美女张开腿让男人操 | 午夜在线| 91免费网站在线观看 | 亚洲精品视频一区二区 | 亚洲 欧美 激情 另类 | 久久人人爽人人爽人人片av高清 | 日本黄色免费网址 | 一区二区三区中文字幕在线观看 | 精品九九在线 | 久草热线 | 国产精品178页 | 91免费高清 | 天天干天天天 | www色| 婷婷伊人网 | 国产伦精品一区二区三区视频1 | 爽好多水快深点欧美视频 | 亚洲国产精品福利 | 中文字幕无产乱码 | 老妇女性较大毛片 | 久久久久久久黄色片 | 日韩一区二区三区久久 | 三上悠亚久久精品 | 黑帮大佬和我的三百六十五天 | 日韩在线视频你懂的 | 超碰av免费 | 日韩avav | 大片视频免费观看视频 | 亚洲人成网址 | 大黑人交交护士xxxxhd | 国产精品免费av一区二区三区 |