【前端刷题Day4】多数元素和轮转数组

56 阅读3分钟

今日题目:

image.png

这两天刷了这4道题,买卖股票的是动态规划的题目,之前总结过就不再总结了,直接放链接: 【前端er每日算法】动态规划--买卖股票一二

剩余2道总结一下,每道题都不止一种解法。

题目一 169. 多数元素

这道题目容易想起来的前2种解法:map计数和排序。后面的就不好想了。

解法一 map计数

遍历数组,map记录数字出现的次数,找到出现次数最多的值就是所求的值。

// map方法
var majorityElement = function(nums) {
    const map = {};
    let maxCount = 0;
    let result = 0;
    for (let i = 0; i < nums.length; i++) {
        if (!map[nums[i]]) {
            map[nums[i]] = 1;
        } else {
            map[nums[i]] += 1;
        }
        if (map[nums[i]] > maxCount) {
            result = nums[i];
            maxCount = map[nums[i]];
        }
    }
    return result;
}

解法二 排序

数组排序,直接取n/2的值。

// 排序
var majorityElement = function(nums) {
    nums.sort((a, b) => a - b);
    return nums[Math.floor(nums.length / 2)];
};

解法三 Boyer-Moore 投票算法

看了题解后,发现还有好几种做法,觉得投票算法挺好的,所以记录下Boyer-Moore 投票算法

算法思路

  1. 维护一个候选数candicate和出现的次数。

  2. 遍历数组,对于每个元素

    • 如果count为0,将元素赋值给candicate,该元素做为候选值。
    • 然后将x和candidate判断
      • 如果相等,则count+1
      • 如果不等,count-1
  3. 遍历完成后,candicate就是数组的众数。

var majorityElement = function(nums) {
    let candicate = -1;
    let count = 0;
    for (let i = 0; i < nums.length; i++) {
        // 选一个作为候选值
        if (count === 0) {
            candicate = nums[i];
        }
        if (candicate === nums[i]) {
            count++;
        } else {
            count--;
        }
    }
    return candicate;
}

189. 轮转数组

这个题目也是多种解法,最简单的使用一个新数组的解法。这个简单就不写了,另外两种值得记录下:

解法一 反转再反转

  1. 先整体反转:后k个变成了前k个了
  2. 前k个反转:把前k个顺序变回来
  3. 后面剩余的元素反转:剩余的顺序再变回来。

齐活!完事,这个算法思路还是很有意思的。

function reverseStr(arr, left, right) {
    while (left < right) {
        [arr[left], arr[right]] = [arr[right], arr[left]];
        left++;
        right--;
    }
}
var rotate = function(nums, k) {
    const len = nums.length;
    if (k > len) {
        k = k % len;
    }
    reverseStr(nums, 0, len - 1);
    reverseStr(nums, 0, k - 1);
    reverseStr(nums, k, nums.length - 1);
    return nums;
};

环状替换

image.png

这个还不太好想。就是循环替换,每次计算下一个位置赋值过去,将被替换的值保存下来,难的地方在于

  1. 啥时候停止?增加一个count计数,如果都替换过了跳出循环。

  2. 一次循环后如何啥时候停止?以为一圈到头可能还有元素没替换,所以转一圈到达起始位置后要加一,从下个元素开始,同时更新本圈的start值。

var rotate = function(nums, k) {
    const len = nums.length;
    if (k > len) {
        k = k % len;
    }
    let count = 0;
    let index = 0;
    let last = nums[index];
    let start = index;
    // 记录移动的个数,如果不够长度,循环移动
    while (count < len) {
        // 计算应该移动到的位置,并保存下一个值
        let next = (index + k) % len;
        let temp = nums[next];
        nums[next] = last;
        last = temp;
        index = next;
        count++;
        // 转回该圈起点的位置后index++,更新start和上一次的值
        if (index === start) {
            index++;
            start = index;
            last = nums[index];
        }
    }
    return nums;
}