leetcode169 学习

69 阅读3分钟

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。  

示例 1:

输入: nums = [3,2,3]
输出: 3

示例 2:

输入: nums = [2,2,1,1,1,2,2]
输出: 2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109

本人第一思路的解法

先给数组排序,相同的值挨着,遍历时对每个当前数计数,然后比较是否为更大的计数。(其实给根据题目来看,可以不用比较,只要判断计数大于n/2就返回即可)

var majorityElement = function(nums) {
    let maxNum , candidate , count=0 ,maxCount=0
    nums.sort((a,b)=>a-b) // 排序
    nums.forEach((e)=>{
        if(candidate == e){
            count++
            if(maxCount<count){
                maxNum = e
                maxCount = count
            }
        }else{
            count=1
            candidate=e
            if(!maxNum){
                maxNum = e
                maxCount = 1
            }
        }
    })
    return maxNum
};

猴子算法

既然是数组中出现次数大于⌊ n/2 ⌋的元素,那么随机一下大概率就能拿到

// 获得min~max的随机数
Math.floor(Math.random() * (max - min + 1)) + min
var majorityElement = function (nums) {
  while(true){
      let randomDate = Math.floor(Math.random() * (nums.length-1) )
      let numDate = nums[randomDate]
      let count=0
      nums.forEach((e)=>{
          if(e==numDate){
              count++
          }
      })
      if(count>nums.length/2){
          return numDate
      }
  }
}

Boyer-Moore 投票算法

candidate 用于保存当前候选者,count 用于计数,在遍历时,当前值与候选者不等,则计数-1,否则+1,在 count 归零时,更新候选者为当前值,此过程 count 的值一定非负

nums:      [7, 7, 5, 7, 5, 1  ,  5, 7  ,  5, 5, 7, 7  ,  7, 7, 7, 7]
candidate:  7  7  7  7  7  7     5  5     5  5  5  5     7  7  7  7  // 候选者
count:      1  2  1  2  1  0     1  0     1  2  1  0     1  2  3  4  // 计数器
var majorityElement = function (nums) {
    let count = 0 
    let candidate
    nums.forEach((e)=>{
        if(count == 0){
            candidate = e
        }
        count += candidate == e ? 1 : -1
    })
    return candidate
}

分治算法递归求解

感觉整的有点麻烦了,是题解里学到的,把它js化了一下,学学思路挺好。

  // 定义一个方法'countInRange'来计算在'nums'数组的从索引'lo'到'hi'的子数组中'target'的出现次数。
  countInRange(nums, target, lo, hi) {
      // 初始化一个变量'count'来存储'target'的出现次数。
      let count = 0;
      // 遍历从索引'lo'到'hi'的子数组。
      for (let i = lo; i <= hi; ++i) {
          // 如果'nums'数组在索引'i'处的元素等于'target'。
          if (nums[i] === target) {
              // 增加'count'的计数。
              ++count;
          }
      }
      // 返回'target'的出现次数。
      return count;
  }

  // 递归方法'majorityElementRec'来找出数组'nums'中主要元素。
  majorityElementRec(nums, lo, hi) {
      // 如果子数组只有一个元素,则返回该元素作为主要元素。
      if (lo === hi) {
          return nums[lo];
      }
      // 计算子数组的中间索引。
      const mid = Math.floor((lo + hi) / 2);
      // 递归调用'majorityElementRec'来找出左子数组的主要元素。
      const leftMajority = this.majorityElementRec(nums, lo, mid);
      // 递归调用'majorityElementRec'来找出右子数组的主要元素。
      const rightMajority = this.majorityElementRec(nums, mid + 1, hi);
      // 如果左子数组的主要元素在整个数组的范围内出现次数大于一半,则返回该元素。
      if (this.countInRange(nums, leftMajority, lo, hi) > (hi - lo + 1) / 2) {
          return leftMajority;
      }
      // 如果右子数组的主要元素在整个数组的范围内出现次数大于一半,则返回该元素。
      if (this.countInRange(nums, rightMajority, lo, hi) > (hi - lo + 1) / 2) {
          return rightMajority;
      }
      // 如果没有主要元素,则返回-1。
      return -1;
  }
  
  // 主方法'majorityElement'来找出数组'nums'中的主要元素。
  majorityElement(nums) {
      // 调用递归方法'majorityElementRec'来找出主要元素。
      return this.majorityElementRec(nums, 0, nums.length - 1);
  }