[TDD] leet code 219. Contains Duplicate II

用 TDD 來練習完成 leet code 的第 219 題,題目描述如下。

Given an array of integers and an integerk, find out whether there are two distinct indicesiandjin the array such thatnums[i] = nums[j]and theabsolutedifference betweeniandjis at mostk.

題目解釋:給一個int[] nums,以及一正整數k,如果存在著 i 與 j 使得nums[i] = nums[j],且|i-j|<= k,則回傳true。若不然,則回傳 false。

這篇文章要透過 TDD 的方式,來解釋我的思路跟程式碼演進過程。

第一個紅燈,k = 0,應回傳 false

這個測試案例代表的用意,是先用最簡短的路徑,處理實際的商業邏輯,透過測試驅動產生出來產品程式碼的 class 名稱、function 名稱、參數名稱與型別、回傳的型別。

測試程式碼如下:

第一個紅燈

產品程式碼,是由測試程式碼透過 Visual Studio 產生的 class 與 function,內容如下:

從測試程式所產生的產品程式碼的殼

用最簡單的程式碼,符合測試案例關鍵邏輯,迅速通過第一個紅燈,得到綠燈

產品程式碼的處理:針對 k = 0 的情況,return false;

透過 baby step 得到綠燈

新增一個測試案例, nums = {5,5}, k = 1, return true;

這個測試案例代表的用意,是為了找到相同數字,回傳 true。

測試程式碼如下:

相同數字的第一個關鍵測試案例

產品程式碼,相同數字的部分,使用 HashSet<T> 來判斷。

使用 HashSet<T> 判斷是否有相同數字

新增一個測試案例,nums = {5,6}, k = 1, return false;

這個測試案例用意為,當都不存在相同的數字時,該回傳 false。

測試程式碼如下:

數字皆不同時,該回傳 false 的代表測試案例

產品程式碼邏輯,如果每一個數字都不相同,回傳 false。

產品程式碼如下:

數字皆不同,回傳 false,消掉原本 NotImplementedException

還沒用到 k, 新增一個測試案例,nums = {5,6,5}, k = 1, return false;

這個測試案例用意,是假設 nums 中有重複的數字 5, 但其 index 差距大於 k,應回傳 false。目前會 failed, 原因是 HashSet<T> 只要加不進去就回傳 true。

測試程式碼如下:

相同數字距離超過 k 的測試案例

產品程式碼的實作,我這邊使用 slide window 的概念,也就是把 k 當作 window 的 size 基準。(嚴格來說是 k + 1,因為 k 是距離,window size 是 window 裡面的 int 個數),判斷 window 裡面是否存在著重複的數字,若存在則 return true; 否則 return false;

產品程式碼透過 Skip().Take() 取得 window 裡面的 numbers 判斷 window 中是否存在重複數字,如不存在,則往下一個 index 滑動。程式碼如下:

slide window 演算法初步實現

這一步跳比較大,

同時滿足了下面的測試案例:nums = {5,6,5}, k = 2, return true 的情況。

測試案例如下:

多個數字,相同數字符合距離 k 的限制

演算法的主要功能已經完成了,在我提供我的產品程式碼作法與 武可 討論之後,他提出了一個演算法優化的寫法。

目前產品程式碼的作法,是每次 window 要往右滑時,起一個新的 window 去拿框框內的元素,進而檢查是否存在重複數字。

而他的建議是,只保留一個 window 的 instance ,當 window 右滑時,如果有元素的位置已經不在 window size 框框內,就將其從 window 中移除。

重構後的產品程式碼如下:

fix window instance and remove element out of window before sliding

最後通過 leet code 的所有測試案例,並符合執行效能限制。

pass leet code all test cases

結論

1. 拿 leet code 來練 TDD 挺過癮的

2. leet code 通常都會針對演算法而有效能限制,而優化演算法效能的部分,很難從 TDD 來驅動優化的設計過程。

3. 但這並非代表 TDD 無用,因為在一開始使用 TDD 透過一個一個代表關鍵商業邏輯的測試案例,來一步步堆砌成滿足需求的產品程式碼,是很有幫助的。在這個過程中,會一步步釐清自己的想法與需求的複雜性。

到最後如果需要對效能或演算法進行優化,不論是判斷式或迴圈的搬移、合併、調整,甚至整個演算法重寫,透過版本控管的保護,你隨時可以還原到可運作的版本。透過先前完整的關鍵商業邏輯測試案例保護,你不必擔心優化或重寫演算法的過程中,漏了什麼特別的需求。

TDD 是種修煉,也是種習慣的養成。當你茫然毫無頭緒,想理頭緒時,TDD 讓你很容易下手。TDD 可以讓你先求有,再求好。

Commit History

我的 github commit history 可以看到 TDD 的過程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容