问题描述

在整数数组中,如果一个整数的出现频次和它的数值大小相等,我们就称这个整数为「幸运数」。

给你一个整数数组 arr,请你从中找出并返回一个幸运数。

如果数组中存在多个幸运数,只需返回 最大 的那个。 如果数组中不含幸运数,则返回 -1 。

示例 1:

输入:arr = [2,2,3,4]
输出:2
解释:数组中唯一的幸运数是 2 ,因为数值 2 的出现频次也是 2 。

示例 2:

输入:arr = [1,2,2,3,3,3]
输出:3
解释:1、2 以及 3 都是幸运数,只需要返回其中最大的 3 。

示例 3:

输入:arr = [2,2,2,3,3]
输出:-1
解释:数组中不存在幸运数。

示例 4:

输入:arr = [5]
输出:-1

示例 5:

输入:arr = [7,7,7,7,7,7,7]
输出:7
力扣原题目地址:https://leetcode.cn/problems/...

思路分析

题目简单,就是统计数组中每一项出现的次数(统计谁出现了几次),看看谁正好等于出现的次数;当然可能正好有多个 谁 等于 其对应出现的次数,这个时候,就看谁更大即可

  1. 一想到要统计数组中每一项出现的次数,我们就会想到使用Map集合进行统计

    1. 比如for循环数组,然后往map里追加,map中存储的键值对中的key为数组中的项,value为数组中这一项出现的次数。代码:

      let map = new Map()
      for (let i = 0; i < arr.length; i++) {
          if (map.has(arr[i])) {
              let count = map.get(arr[i])
              count = count + 1
              map.set(arr[i], count)
          } else {
              map.set(arr[i], 1)
          }
      }
      1. 然后再使用forof遍历map集合,做次数判断即可
  2. 或者想到使用对象Object统计

    1. 比如for循环数组,然后往对象中去添加。对象中的key为数组中的项,value为数组中这一项出现的次数。代码

      let obj = {}
      for (let i = 0; i < arr.length; i++) {
          let item = arr[i]
          if (item in obj) {
              let count = obj[item]
              count = count + 1
              obj[item] = count
          } else {
              obj[item] = 1
          }
      }
      console.log(obj);
    2. 或者使用reduce循环去统计操作次数

      let res = arr.reduce((tempObj, item) => {
          if (item in tempObj) {
              let count = tempObj[item]
              count = count + 1
              tempObj[item] = count
          } else {
              tempObj[item] = 1
          }
          return tempObj
      }, {})
      console.log(res);
    3. 然后再使用forin遍历对象,做次数判断即可

代码

使用Map

var findLucky = function (arr) {
    // 1. 统计次数
    let map = new Map()
    for (let i = 0; i < arr.length; i++) {
        if (map.has(arr[i])) {
            let count = map.get(arr[i])
            count = count + 1
            map.set(arr[i], count)
        } else {
            map.set(arr[i], 1)
        }
    }
    // 2. 定义初始luckyNum,比如没有(没有返回-1)
    let luckyNum = -1 
    // 3. 遍历map集合
    for (const [key, value] of map) {
        if (key === value) { // 若某一项也等于其对应出现次数
            key > luckyNum ? luckyNum = key : '' // 就做一个大小的判断(因为要取最大的那个)
        }
    }
    return luckyNum // 最后返回之即可
};

使用Object

var findLucky = function (arr) {
    // 1. 使用对象的方式 reduce函数
    let res = arr.reduce((tempObj, item) => {
        if (item in tempObj) {
            let count = tempObj[item]
            count = count + 1
            tempObj[item] = count
        } else {
            tempObj[item] = 1
        }
        return tempObj
    }, {})
    let luckyNum = -1
    for (const key in res) {
        /* 注意这里不能直接判断key === res[key],因为对象中的key直接循环默认为字符串
          但是value(res[key])是数字类型的。所以要把数字类型也转换为字符串类型的 */ 
        /* 或者使用双等于号,不使用三等于号。毕竟js会做类型转换。字符串'1'是弱等于数字1的
         if (key == res[key]) { ...... } */ 
        if (key === res[key] + '') {
            res[key] > luckyNum ? luckyNum = res[key] : ''
        }
    }
    return luckyNum
};

总结

如果leetcode题目刷多了,会发现,一些题目是另外一些简单题目的变形。

比如这一题考查的还是数组中统计项出现的次数(使用Map集合统计、使用Object统计)

以及Map的循环forof的使用,或者reduce函数的使用、forin的使用...

个人愚见:前端同学刷力扣算法题,建议只刷简单和中等类型就行了。至于困难题目,应该不用去研究,毕竟咱们也不是应聘算法工程师这一个岗位。

而刷算法的目的,一方面是去提升开发中数据加工组装的能力(如:后端返回的数据结构很奇葩,且不愿意修改;只能前端自己加工成能用的结构啦)

另一方面就是可能在某个地方,使用某种算法操作,能够提升性能加快效率

再一个就是为了应付面试啦


水冗水孚
1.1k 声望585 粉丝

每一个不曾起舞的日子,都是对生命的辜负