【筆記】JavaScript版數據結構與算法——基礎算法之“數組類”(914. 卡牌分組)


卡牌分組

歸類運算

914. 卡牌分組 - 力扣(LeetCode)

1.題目

給定一副牌,每張牌上都寫着一個整數。

此時,你需要選定一個數字 X,使我們可以將整副牌按下述規則分成 1 組或更多組:

  • 每組都有 X 張牌。
  • 組內所有的牌上都寫着相同的整數。

僅當你可選的 X >= 2 時返回 true。

示例 1:

輸入:[1,2,3,4,4,3,2,1]
輸出:true
解釋:可行的分組是 [1,1],[2,2],[3,3],[4,4]

示例 2:

輸入:[1,1,1,2,2,2,3,3]
輸出:false
解釋:沒有滿足要求的分組。

示例 3:

輸入:[1]
輸出:false
解釋:沒有滿足要求的分組。

示例 4:

輸入:[1,1]
輸出:true
解釋:可行的分組是 [1,1]

示例 5:

輸入:[1,1,2,2,2,2]
輸出:true
解釋:可行的分組是 [1,1],[2,2],[2,2]

提示:

  • 1 <= deck.length <= 10000
  • 0 <= deck[i] < 10000

測試用例

// [1, 1, 1, 2, 2, 2, 3, 3]
// [1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3,
//     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 8]

2.思路分析

元素的個數組成一個數組,數組元素最大公約數大於1即可

3.所用到的方法

求元素的個數並組成一個數組

Array.reduce

let counts = Object.values(
  deck.reduce((arr, index) => {
    arr[index] = arr[index] + 1 || 1
    return arr
  }, {})
)

Array.forEach

let tmp = {}
deck.forEach(item => {
  tmp[item] = tmp[item] ? tmp[item] + 1 : 1
})
let counts = Object.values(tmp)

求最大公約數

// 兩數求最大公約數
let gcd = (pre, cur) => {
  return cur === 0 ? pre : gcd(cur, pre % cur)
}
// 多個數需要轉爲數組並搭配循環使用
arr.forEach(item => {
  arr[0] = gcd(arr[0], item)
})
console.log(arr[0]) // 這就是最大公約數

4.題解及優化

我的題解

var hasGroupsSizeX = function (deck) {
  // 查找每種元素的個數組成一個數組
  let counts = Object.values(
    deck.reduce((arr, index) => {
      arr[index] = arr[index] + 1 || 1
      return arr
    }, {})
  )

  // 利用輾轉相除法來計算最大公約數
  let gcd = (pre, cur) => {
    return cur === 0 ? pre : gcd(cur, pre % cur)
  }
  // 每兩項之間求最大公約數,並把結果保存到數組第一項來與下一項進行運算
  counts.forEach(item => {
    counts[0] = gcd(counts[0], item)
  })

  // 這個數組的最小公因數存在且大於1即true
  return counts[0] > 1
}

在這裏插入圖片描述
修改reduce爲forEach

var hasGroupsSizeX = function(deck) {
  // 查找每種元素的個數組成一個數組
  let tmp = {} // 臨時變量
  deck.forEach(item => {
    tmp[item] = tmp[item] ? tmp[item] + 1 : 1
  })
  let counts = Object.values(tmp)

  // 利用輾轉相除法來計算最大公約數
  let gcd = (pre, cur) => {
    return cur === 0 ? pre : gcd(cur, pre % cur)
  }
  // 每兩項之間求最大公約數,並把結果保存到數組第一項來與下一項進行運算
  counts.forEach(item => {
    counts[0] = gcd(counts[0], item)
  })

  // 這個數組的最小公因數存在且大於1即true
  return counts[0] > 1
}

在這裏插入圖片描述


課程解法

var hasGroupsSizeX = function (deck) {
  // 存儲每張卡牌的總數
  // 修改排序的方式修改爲直接統計每個相同字符的數量,思路不變(LeetCode測試用例)
  let group = []
  let tmp = {}
  deck.forEach(item => {
    tmp[item] = tmp[item] ? tmp[item] + 1 : 1
  })
  for (let v of Object.values(tmp)) {
    group.push(v)
  }
  // 此時group已經存放的是每張牌的總數了(數組只遍歷一遍,避免了排序和正則的耗時)
  // 求兩個數的最大公約數
  let gcd = (a, b) => {
    if (b === 0) {
      return a
    } else {
      return gcd(b, a % b)
    }
  }
  while (group.length > 1) {
    let a = group.shift()
    let b = group.shift()
    let v = gcd(a, b)
    if (v === 1) {
      return false
    } else {
      group.unshift(v)
    }
  }
  return group.length ? group[0] > 1 : false
}

在這裏插入圖片描述


其他小夥伴的解法

var hasGroupsSizeX = function(deck) {
    // 最大公約數計算公式
    function gcd(num1, num2) {
        // 利用輾轉相除法來計算最大公約數
        return num2 === 0 ? num1 : gcd(num2, num1 % num2); 
    }

    // 相同牌出現次數Map
    let timeMap = new Map();

    // 遍歷牌
    deck.forEach(num => {
        // 統計每張牌出現的次數
        timeMap.set(num, timeMap.has(num) ? timeMap.get(num) + 1 : 1);
    });

    // Map.protype.values()返回的是一個新的Iterator對象,所以可以使用擴展運算符(...)來構造成數組
    let timeAry = [...timeMap.values()];

    /*
    最大公約數
    因爲該數組是出現次數數組,最小值至少爲1(至少出現1次),所以默認賦值爲數組首位對公約數計算無干擾
    */
    let g = timeAry[0];

    // 遍歷出現次數,計算最大公約數
    timeAry.forEach(time => {
        // 因爲需要比較所有牌出現次數的最大公約數,故需要一箇中間值
        g = gcd(g, time);
    });

    // 判斷是否滿足題意
    return g >= 2;
}

在這裏插入圖片描述


最簡解法

var hasGroupsSizeX = function(deck) {
  let t = {}
  deck.forEach(i => { t[i] = t[i] ? t[i] + 1 : 1 })
  let arr = Object.values(t)
  let gcd = (a, b) => (b === 0 ? a : gcd(b, a % b))
  return arr.every(i => (arr[0] = gcd(arr[0], i)) > 1)
}

這裏使用了Array.every來檢測數組經過求最大公約數後的每一項是否符合要求,只要有一項不符合就直接返回false,這樣節省了一部分時間
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章