---
# System prepended metadata

title: '[Codewars] +1 Array'
tags: [解題筆記]

---

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




