# [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;
}
```
:::