这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战
数组中出现次数超过一半的数字
剑指Offer 39.数组中出现次数超过一半的数字
难度:简单
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:1 <= 数组长度 <= 50000
题解
由本题可知,数字出现的次数超过数组长度的一半(这里简称“众数”)可得出关键三个解法:
- 哈希表法:遍历数组nums,用Map统计出数字的数量,即可找出众数,时间空间复杂度均为O(N)。
- 数组排序法:将数组nums排序,数组中点一定为众数。
- 摩尔投票法:核心理念为票数正负抵消,时间复杂度为O(N),空间复杂度为O(1)。
法一 哈希表法
/**
* @param {number[]} nums
* @return {number}
*/
var majorityElement = function(nums) {
var map = new Map();
for(let i = 0;i < nums.length;i++){
// 将数组元素和出现次数都存进map中
if(map[nums[i]] === undefined){
map[nums[i]] = 1;
}else{
map[nums[i]]++;
}
}
// 遍历map中对应个数超过nums长度一半都元素
for(let item in map){
if(map[item] >= Math.ceil(nums.length/2)){
return item;
}
}
};
法二 数组排序法
var majorityElement = function(nums) {
let num = nums.sort();
return num[Math.floor(num.length/2)];// 四舍,避免只输入一个数字时,五入是undefined
}
法三 摩尔投票法
原理类似于同归于尽,众数与非众数间一一抵消,最终留下的将会是众数(votes > 0)。
var majorityElement = function(nums) {
let x = 0, votes = 0; // x为众数,votes为合计数
for(let i = 0;i < nums.length;i++){
if(!votes){ // 若votes为0,则将众数设为当前下标值
x = nums[i];
votes++;
}else{ // 下标值是否为众数,是则加1,否则减1
votes += nums[i] === x ? 1 : -1;
}
}
return x;
}
最小的k个数
剑指Offer 40.最小的k个数
难度:简单
输入整数数组arr,找出其中最小的k个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4.
示例1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
- 0 <= k <= arr.length <= 10000
- 0 <= arr[i] <= 10000
题解
法一 直接调api
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
var getLeastNumbers = function(arr, k){
// sort使用快排
return arr.sort((a, b) => a - b).slice(0, k);
}
- 时间复杂度:O(NlogN)
- 空间复杂度:O(logN)
法二 快排数组划分
由题目知,我们只需要找出TopK,因此相对于法一,我们不需要对全部元素进行排序,而且对k个元素的顺序也没有要求,所以对快排进行优化,使其不用排序整个数组。
步骤:
- 哨兵划分:
- 通过一趟排序,对数组进行划分,基准数为arr[i],左数组区间为[ ,],右数组区间为[ ,]。
- 递归或返回:(k+1代表的是前k小后的那一个数字)
- 若,代表第小的数字在左子数组中,则递归左子数组
- 若,代表第小的数字在右子数组中,则递归右子数组
- 若,代表arr[k]为第小的数字,则返回数组前k个数字即可
var getLeastNumbers = function(arr, k){
if(k >= arr.length) return arr;
return quickSort(arr, k, 0, arr.length - 1);
}
function quickSort(arr, k, l, r){
let i = l, j = r;
while(i < j){
while(i < j && arr[j] >= arr[l]) j--;
while(i < j && arr[i] <= arr[l]) i++;
[arr[i],arr[j]] = [arr[j],arr[i]];
}
[arr[i],arr[l]] = [arr[l],arr[i]];
if(i > k) return quickSort(arr, k, l, i - 1);
if(i < k) return quickSort(arr, k, i + 1, r);
return arr.slice(0, k);
}
- 时间复杂度:O(N)
- 空间复杂度:O(logN)
坚持每日一练!前端小萌新一枚,希望能点个赞
哇~