【问题标题】:What is a more optimized solution for this algorithm? I feel i can learn more from this question这个算法更优化的解决方案是什么?我觉得我可以从这个问题中学到更多
【发布时间】:2021-01-21 05:43:56
【问题描述】:

首先,我是一个练习我的 JavaScript 的初学者。我对这个问题的解决方案将被发布。我认为值得一提的是这花了将近两天的时间思考才能解决 问题: 我需要编写一个算法,该算法将从给定的输入数组中返回模式。例如:

mode([4, 5, 6, 6, 6, 7, 7, 9, 10]) ➞ [6]

mode([4, 5, 5, 6, 7, 8, 8, 9, 9]) ➞ [5, 8, 9]

mode([1, 2, 2, 3, 6, 6, 7, 9]) ➞ [2, 6]

解决方案:

function mode(nums) {
  let array = [...nums]
  array = array.sort((a, b) => a - b) //sorts the array from lowest value

  // function to figure out the unique numbers and return as an array
  function uniqueNums(array) {
    let uniques = []
    for (let i = 0; i < array.length; i++) {
      if (!uniques.includes(array[i])) {
        uniques.push(array[i])
      }
    }
    return uniques
  }

  //function to return the mode of every unique number

  function counter(array) {
    let modes = []
    for (let i = 0; i < array.length; i++) {
      let count = 1, // keeps track of occurrence's of a number
        track = 1 //variable enables the while loop keep checking
      while (array[i] === array[i + track]) {
        count++
        track++
      }
      modes.push(count)
      i += count - 1
    }
    return modes
  }

  //function to return the highest mode(s)
  function highestMode(uniques, modes) {
    let highest = [],
      max = 0 //tracks our highest number in the array

    //loops to find highest mode
    for (let i = 0; i < modes.length; i++) {
      if (max < modes[i]) {
        max = modes[i]
      }
    }

    //loops to push position of modes equal to the highest mode
    for (let i = 0; i < modes.length; i++) {
      if (max === modes[i]) {
        highest.push(i)
      }
    }

    //uses the position of highest modes to swap them with their 
    //actual values
    let result = highest.map(a => a = uniques[a])
    return result
  }
  return highestMode(uniqueNums(array), counter(array))
}


console.log(mode([4, 4, 4, 6, 8, 9, 10, 10]))

【问题讨论】:

  • 如果您是group the values,则可以按长度对组进行排序并获得前几组。

标签: javascript typescript algorithm


【解决方案1】:

如果您将此视为一种学习练习,这里是来自CertainPerformance 的相同算法的另一种实现,但编写方式完全不同。

const mode = (
  ns, 
  counts = ns .reduce ((m, n) => m .set (n, (m .get (n) || 0) + 1), new Map ()),
  max = Math .max (... counts .values())
) => 
  [...counts] .flatMap (([n, c]) => c == max ? [n] : [])


console .log (mode ([4, 5, 6, 6, 6, 7, 7, 9, 10])) //=> [6]
console .log (mode ([4, 5, 5, 6, 7, 8, 8, 9, 9])) //=> [5, 8, 9]
console .log (mode ([1, 2, 2, 3, 6, 6, 7, 9])) //=> [2, 6]

如果不清楚,我的counts 匹配grouped,我的max 匹配maxCount

与CertainPerformance 的答案的最大区别在于,这是用纯表达式而不是语句编写的。这是我尽可能多地遵循的风格。

它使用默认参数代替其他语言中的let bindings。它不是一个完美的替代品,至少有一个potential problem,但它可能非常有用。这样做让我定义了一些辅助变量,如果没有语句,您无法在函数体中分配这些变量。有其他选择,但当我可以摆脱它时,我发现这个最简单。

reduce 调用与其他答案基本相同。 max 定义也是如此。

但我利用 Map 的默认迭代器是条目列表这一事实,只需使用扩展运算符 (...) 即可将映射转换为 [[4, 1], [5, 1], [6, 3] ...],而无需调用 @987654332 @。

最后,我将调用filtermap 替换为调用flatMap。这感觉更优雅。

我并不是要暗示这段代码比来自CertainPerformance 的代码更好。它的感觉非常相似,尽管排列方式不同。但这是解决问题的不同方法,因此它可能会提供一些东西。

【讨论】:

    【解决方案2】:

    我会将每个元素出现的次数统计到地图中。然后使用Math.max在map中找到最大值,然后取与最大值相等的key:

    const mode = arr => {
      const grouped = new Map();
      for (const item of arr) {
        grouped.set(item, (grouped.get(item) || 0) + 1);
      }
      const maxCount = Math.max(...grouped.values());
      return [...grouped.entries()]
        .filter(([, count]) => count === maxCount)
        .map(([key]) => key);
    };
    
    console.log(mode([4, 5, 6, 6, 6, 7, 7, 9, 10])) // ➞ [6]
    console.log(mode([4, 5, 5, 6, 7, 8, 8, 9, 9])) // ➞ [5, 8, 9]
    console.log(mode([1, 2, 2, 3, 6, 6, 7, 9])) // ➞ [2, 6]

    【讨论】:

    • 您的解决方案利用了我以前没有学过的概念,这正是我希望从这篇文章中得到的。谢谢
    • 地图可能会使事情变得比算法严格需要的更加混乱。您可以使用普通对象来实现相同的目的,除了对象只能具有字符串(或符号)键 - 如果您使用普通对象并将键数组转换为数字数组,则可能会更直观'正在尝试掌握数据结构操作。
    • 如果您不介意,我希望您能解释一下您的最终 return 语句,我很难掌握语法。
    • [...grouped.entries()] 给出一个条目数组,例如[[4, 1], [5, 1], [6, 3] ...:每个子数组包含键(原始数字之一)和该键的出现次数。过滤那些出现次数最多的,你会得到[[6, 3]],然后将每个子数组映射到唯一的键,你会得到[6]
    • 练习和回答问题。您可以通过查看体面的 SO 问题找到大量示例:stackoverflow.com/… 评价问题?我不知道,这很简单,不需要太多思考(IMO)
    【解决方案3】:

    单次迭代的更简单和优化的方法

    https://jsfiddle.net/dv7f9nxr/

    function mode(items) {
      var result = [];
      var count = {};
      var highest= 0;
    
      items.map((item) => {
        var itemCount = (count[item] || 0) + 1;
        count[item] = itemCount;
          if(itemCount > highest) {
            highest = itemCount;
            //reset 
            result = [item];
          } else if (itemCount === highest){
            result.push(item);
        }
    
      })
     
      
      
      return result;
    }
    
    console.log(mode([2, 3, 9, 6, 9]))
    console.log(mode([2, 3,2, 9, 6, 9]))
    console.log(mode([2, 3,2, 9, 6, 9,2]))
    console.log(mode([2, 3, 9, 6, 9,6,2]))

    【讨论】:

    • 谢谢。我确实更喜欢之前的回复,因为它教会了我一些新概念,但你的代码也很棒:)
    • if (itemCount &gt; 1) 的意义何在?这似乎会导致不准确。
    • 斯科特,我删除了那部分。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    相关资源
    最近更新 更多