# [Codewars] +1 Array ###### tags `解題筆記` <div style="display: flex; justify-content: flex-end"> > created: 2024/05/31 </div> ## 練習資訊 等級:6 kyu 題目:[+1 Array](https://www.codewars.com/kata/5514e5b77e6b2f38e0000ca9) 練習時間: - 2024/05/31(想了快 90 分鐘,中途還跑去睡午覺 ...) ## 題目說明 ### 中文 給一組陣列,必須回傳一個陣列為該陣列數字表面 + 1 的結果。 比如 `[4, 3, 2, 5]` => `[4, 3, 2, 6]` 因為 4325 + 1 = 4326 ### 英文 Given an array of integers of any length, return an array that has 1 added to the value represented by the array. - the array can't be empty - only non-negative, single digit integers are allowed Return `nil` (or your language's equivalent) for invalid inputs. **Valid arrays** `[4, 3, 2, 5]` would return `[4, 3, 2, 6]` `[1, 2, 3, 9]` would return `[1, 2, 4, 0]` `[9, 9, 9, 9]` would return `[1, 0, 0, 0, 0]` `[0, 1, 3, 7]` would return `[0, 1, 3, 8]` **Invalid arrays** `[1, -9]` is invalid because `-9` is **not a non-negative integer** `[1, 2, 33]` is invalid because `33` is **not a single-digit integer** ## 我的方法 ### 思路 ~~一開始想說直接暴力把陣列搞回表面上的數字,然後再進行表面數字的加總,最後再搞回陣列。但是當陣列數字太大時,會超出 JavaScript 運算的限制,無法正確地 + 1(比如說 12345678901234567890 + 1 會得出 12345678901234567000)...~~ 1. 無法拆出成數字已數字加總,就只好針對陣列操作,比較特別的情況只有 `[9]`, `[0, 9]` 若為 9 加總時必須強制拆出,要不然就會是不正確的數字 `[10]`, `[0, 10]`(應為 `[1, 0]`) 2. + 1 而已,所以從陣列的最尾端操作 3. 把 9 視為要跳位,且跳位後該位置就是 0 4. 若跳位的數量為陣列的長度,則代表是 `[9]`, `[9, 9 ,9]` 之類的情境,所以可以安心強制換成 `[1, 0]` 5. 反之就必須針對目標數字加總(不需跳位的數) 5.1 因為 length 及 index 的差別是 1,所以若需要跳位還需要再 + 1 才可得到正確的 index 6. Array.slice(startIndex, endIndex?) => 是不包含 endIndex 的,所以要正確過濾跳位的數得額外扣除(因為 `[9]` 這種情況已經特別處理了,剩下就是處理 `[0, 9]` 這類的畸形種 ### 程式碼 ```javascript= function upArray(arr){ /** * 排除不合 input 條件的 arr * */ if (arr.length === 0 || arr.some((ele) => { return ele >= 10 || ele < 0 })) { return null } let shouldMove = true let movedTimes = 0 /** * 計算跳位的數量 * * [0, 9, 9] => 因為是 + 1,按照進位規則 9, 9 須跳位給下一個數 * */ while(shouldMove) { const currentVal = arr[arr.length - 1 - movedTimes] if (currentVal + 1 > 9) { movedTimes += 1 } else { shouldMove = false } } /** * 跳位數 === arr 的長度 * [9, 9] => 手動拼成 [1, 0, 0] * */ if (movedTimes === arr.length) { return [(arr[0] + 1 > 9 ? 1 : arr[0] + 1 ), ...Array(movedTimes).fill(0)] } /** * index 及 length 是 1 的關係,所以從尾巴拿的時候要判斷是否要額外扣除關係 1 * */ const tempResult = arr[arr.length - (movedTimes === 0 ? 1 : (movedTimes + 1))] + 1 /** * Array.slice(startIndex, endIndex?) 不包含 endIndex,所以要扣除跳位數量 * [0, 9, 9] => [] => [1, ...Array(2).fill(0)] => [1, 0, 0] * */ return [...arr.slice(0, arr.length - 1 - movedTimes), ...[tempResult, ...Array(movedTimes).fill(0)]] } ``` ## 厲害的解答 ### 思路 1. 注意力放在是否要進位以及是否要手動推 1(因為只要 + 1,所以 `[9, 9]` => 可以想成手動推 1 把 9 要進位就洗成 0) :::spoiler ```javascript= /** * [0, 9, 9] => 在第 0 個是後就會被 if(arr[j] !== 9) 洗成 1 了 => [1, 0, 0] * [9, 9] => 第 0 個雖然也是 9 會被洗成 0,但是最後有額外判斷是否真的到底,到底就手動推 1 => [1, 0, 0] * */ function upArray(arr) { if ((typeof arr === 'undefined') || (arr === null) || (arr.length === 0)) { return null; } for (var i = 0; i < arr.length; i++) { if ((arr[i] < 0) || (typeof arr[i] !== 'number') || (arr[i] > 9)) { return null; } } // if its 9 and more than one digit we have to check all previous digits // whether they are also a 9 /** * 從最後取 * */ for (var j = arr.length - 1; j > -1; j--) { /** * 非 9 就安心 + 1 就好 * */ if (arr[j] !== 9) { arr[j] = arr[j] + 1; break; } else { /** * 要進位得把該次 9 變成 10 * */ arr[j] = 0; } /** * 上方的 if else 已經控制是否為 9 了,若第 0 個也是 9,就代表需要直接推 1 * */ if (j === 0) { arr.unshift(1); } } return arr; } ``` :::