橋樑修復
代碼來臨 2024 年第 7 天
第 1 部分
今年第一次遞迴
至少這就是我今天想要贏得一顆金星的方式:
- 從完整清單開始
- 檢查加法和乘法
- 對於每個結果,繼續列表的其餘部分
- 直到我超過或匹配總數
困難在於細節。
讓我們開始吧!
制定我的演算法
首先,我需要將每一行解析為數字列表:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
第一個元素是所需的總數。
其餘的是方程式的有序操作數。
我需要在遞歸函數中考慮到這一點。
這是我的遞迴函數:
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
這是使用它的reduce:
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
正如我所希望但從未預料到的,它為範例輸入產生了正確的答案!
它會完成處理我的拼圖輸入嗎?
如果是這樣,它會產生正確的答案嗎?
老實說我不確定......
確實如此! ! !
哇! ! !
儘管我很興奮,但我擔心下一部分要么會添加更多運算符,要么需要一些高級 CS 來使遞歸不再是可行的解決方案。
第2部分
完全出乎意料!而且難度更高
我該怎麼做?
...
幾天後...
回顧一下我的思考過程:
- 就像在我的退貨條件中添加第三個條款一樣簡單嗎? 不
- 我的第 1 部分遞歸函數是否配置正確才能成功? 不
- 哦,不,透過先前的操作累積金額是否可行? 不
- 我真的需要用新策略來解決這個問題嗎? 是的
考慮所有新的變化
對於這個方程式:
292: 11 6 16 20
給定三個運算符,這些都是可能的方程式:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
也許我可以建立每個方程式的字串,並在遞歸函數中手動對其求值。
例如:
我在最外層函數呼叫中以空字串開始:
""
從那裡,我使用下一個數字創建三個變體:
"" + "+N" "" + "*N" "" + "N"
嗯,但這對第一個數字不起作用。
我需要用第一個數字開始我的第一個函數調用,而不是空字串:
"N"
同樣的事情:
"N" + "+N" "N" + "*N" "N" + "N"
是的,應該可以。
最後,我將獲得這些範例變體,所有這些都可以評估:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
跳至:我對其進行了編碼...並發現了一個更大的問題
我寫的程式碼成功產生了方程式的所有變體。
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
- i 用於沿著數字列表
- 只有當 i 位於倒數第二個索引之前或位於倒數第二個索引時,最後一個子句才會繼續
函數取得四個值:
- 數字清單的副本,減去預期總數
- 下一個索引
- 由三個字串之一連接而成的方程式字串
- 相同的測試號碼
我使用與第 1 部分幾乎相同的簽名來呼叫該函數:
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
差別在於我作為參數傳遞的內容:
- 沒有預期總金額的清單
- 從索引 0 開始
- 包含第一個數字的字串
- 預計總金額
好消息:
- 它產生所有方程式變化
壞消息:
- 它使用 PEMDAS 計算所有方程,而不是從左到右
我應該更清楚...內建的 JavaScript 求值器會預設使用正確的操作順序,而不是從左到右。
這確實給我的演算法帶來了更大的麻煩:
- 我將不得不分解每個方程式並逐個部分評估它
嗚嗚嗚。
謝天謝地,我想我知道該怎麼做。
手動做數學
我需要 JavaScript 來計算這樣的方程式:
292: 11 6 16 20
依此順序:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
我想將方程式分成幾個部分:
""
我了解的唯一方法是使用這個三鏈表達式:
"" + "+N" "" + "*N" "" + "N"
我用空格填充每個運算符,只是將其用作分隔符。
關於這個方程式部分列表的事實:
- 它將始終包含 3 個或更多的奇數項目
如何在迭代每個操作數-運算符-操作數對的循環中利用這一事實?
這是我的想法:
- 刪除前三項
- 將它們作為字串連接,並將其作為數學表達式進行計算
- 將結果重新附加到方程式清單的開頭
- 重複直到方程式列表為空
希望它能起作用!
我在 JavaScript 工作的數學模擬器:
"N"
好消息:
- 它向我顯示了預期的計算值
壞消息:
- 我仍然沒有得到範例輸入中一個方程式的正確答案
範例答案不會錯...可以嗎?
我不斷產生的答案比預期答案少了大約 7k。
這讓我認為我的演算法沒有辨識出這個方程式是正確的:
let eqs = input.split('\n').map(line => { return [...line.matchAll(/\d+/g)].map(el => +el[0]) })
在範例輸入的解釋中,這是獲勝方程式:
function eqChecker(operands, amount, test) { if (amount > test) { return false } else if (amount == test && operands.length == 0) { return true } else if (operands.length) { let copy = operands.slice() let first = copy.shift() return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test) } }
我的演算法評估該方程式並產生以下結果:
let part1 = eqs.reduce((count, eq) => { if (eqChecker(eq.slice(2), eq[1], eq[0])) { count += eq[0] } return count }, 0)
那是因為我的演算法是這樣運作的:
292: 11 6 16 20
我不明白它怎麼可能是其他數字。
所以...我用谷歌搜尋了。
我找到了我的答案,它一如既往地隱藏在簡單的網站解釋中:
所有運算子仍然從左到右計算。
我在每個遞歸函數呼叫中預先連接值。
相反,我的演算法應該要這樣做:
11 11+6 11+6+16 11+6+16+20 11+6+16*20 11+6+1620 11+6*16 11+6*16+20 11+6*16*20 11+6*1620 11+616 11*6 11*6+16 11*6+16+20 11*6+16*20 11*6+1620 11*6*16 11*616 116 116+16 116+16+20 116+16*20 116+1620 116*16 11616
現在我明白了應該發生什麼,我可以調整我的演算法以匹配該處理行為嗎?
從左到右......這次是真的
值得慶幸的是,調整我的演算法相對容易。
我新增了一個replaceAll()子句來解釋||。
我處理每三個項目的新 while 迴圈如下:
""
我調整了退貨聲明的||子句包含這些字符,而不是立即連接兩個數字。
測試和重新測試
我在範例輸入上運行了演算法。
它終於產生了正確的答案! !
多麼輕鬆啊! !
我想知道它是否會完成運行並在我的拼圖輸入上產生正確的答案。
按運行...
...
...
我得到答案了!
它很大,所以這可能是一個好兆頭。
這是正確答案嗎?
...
不。太高了。
真糟糕。
我錯過了一個邊緣案例嗎?
我的獲勝方程式的條件很簡單,就是處理後的數學等於測試量。
但是,如果其中一個變體方程式允許數字子集產生正確答案怎麼辦?
為了捕捉並排除這種情況,我更新了 if 條件以包含另一個子句:
"" + "+N" "" + "*N" "" + "N"
這樣,只有當所有數字都處理完畢且結果數量等於測試數時,方程式才會被計算在內。
大問題:
- 這會改變我得到的答案嗎?
再按下運作...
...
嗯,看起來確實還是一樣的答案。
哦,等等,末尾附近有兩個數字不同!
我的新答案比以前少了 80。
是否有一個以 80 為預期數量的方程式?
是的!
"N"
有沒有一種方法可以在不使用所有數字的情況下得到 80?
是的!
"N" + "+N" "N" + "*N" "N" + "N"
這是我唯一需要排除的邊緣情況嗎?
正在提交我的新答案...
正確! ! !
嗚呼! ! !
我做到了! ! !
那個。曾是。筋疲力盡。令人興奮。而且真的跑了。並且具有挑戰性。
以及我喜歡做這些謎題的所有原因。
繼續下一篇!
以上是橋樑修復的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

實現視差滾動和元素動畫效果的探討本文將探討如何實現類似資生堂官網(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

如何在JavaScript中將具有相同ID的數組元素合併到一個對像中?在處理數據時,我們常常會遇到需要將具有相同ID�...

探索前端中類似VSCode的面板拖拽調整功能的實現在前端開發中,如何實現類似於VSCode...

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。
