算法连载(第五期)

126 阅读3分钟

hello大家好我是django今天给大家分享的算法是《前 K 个高频元素》、《快乐数》、《二叉树的直径》、《有效的字母异位词》、《最长回文串》

前 K 个高频元素(桶排序)

  • 要求

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

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

  • 思路

先使用map记录每个数出现的次数,然后在以出现的次数作为下标创建一个新的数组,并从后往前便利k个不为undefined的值就是我们要找到值

  • 实现
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var topKFrequent = function(nums, k) {
    const countMap = {};
    const countArr = [];
    for(let i = 0; i< nums.length; i++) {
        countMap[`${nums[i]}`] = (countMap[`${nums[i]}`] || 0) + 1
    }

    const keys = Object.keys(countMap);
    for(let i = 0; i< keys.length; i++) {
        const count = countMap[keys[i]];
        if(!countArr[count])countArr[count] = []
        countArr[count].push(keys[i]);
    }
    const result = [];
  	// 从后往前遍历
    for(let i = countArr.length - 1; i>=0; i--) {
        if(countArr[i]) {
            result.push(...countArr[i])
        }
        if(result.length === k) break;
    }

    return result;
};

快乐数

  • 要求

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果 可以变为 1,那么这个数就是快乐数。 如果 n 是快乐数就返回 true ;不是,则返回 false

示例 1:

输入:19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1

示例 2:

输入:n = 2 输出:false

  • 思路

使用快慢指针的方法,去查看比较是否会生成无线循环。根据题目要求,快乐数不会无线的增大所以我们只需要判断慢指针和快指针是否相遇。如果相遇则返回false否则返回true

  • 实现
/**
 * @param {number} n
 * @return {boolean}
 */
var isHappy = function(n) {
    let low = n;
    let hight = getNext(n);
    while(true) {
        if(low === 1 || hight === 1) return true;
        if(low === hight) {
            return false;
        }
        low = getNext(low);
        hight = getNext(getNext(hight))
    }
};

function getNext(n) {
    const arr = `${n}`.split('')
    const sum = arr.reduce((acc, curr)=> acc+ curr * curr,0);
    return sum;
}

二叉树的直径

  • 要求

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 : 给定二叉树

      1
     / \
    2   3
   / \     
  4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

注意:两结点之间的路径长度是以它们之间边的数目表示。

  • 思路

递归遍历每个子节点的高度,并在递归时记录左右子节点的个数。即有直径 = 左节点 + 根节点 + 右节点 - 1所以记录每个节点的子节点个数就能得到最大的直径

  • 实现
/**
 * @param {TreeNode} root
 * @return {number}
 */
var diameterOfBinaryTree = function(root) {
    let maxLength = 1;

    function getHeight(node) {
        if(!node) return 0;
        const left = getHeight(node.left);
        const right = getHeight(node.right);
  			// 左右节点的总数
      	maxLength = Math.max(maxLength, left+right + 1)
        return Math.max(left,right) + 1;
    }
  
    getHeight(root);

    return maxLength - 1;
};



有效的字母异位词

  • 要求

给定两个字符串 st ,编写一个函数来判断t是否是 s 的字母异位词。

注意:若 st 中每个字符出现的次数都相同,则称 s t 互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

提示:

1 <= s.length, t.length <= 5 * 104

st 仅包含小写字母

  • 思路

使用两个map记录两个字符串字符出现的次数,最后循环比较出现的次数是否是一致的

  • 实现
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    if(s.length !== t.length) return false;
    const sarr = s.split('');
    const tarr = t.split('');
    const sMap = {};
    const tMap = {};
    for(let i = 0; i < sarr.length; i++) {
        sMap[sarr[i]] = (sMap[sarr[i]] || 0) + 1;
        tMap[tarr[i]] = (tMap[tarr[i]] || 0) + 1;
    }

    const keys = Object.keys(sMap);
    for(let i = 0; i < keys.length; i++) {
        if(sMap[keys[i]] !== tMap[keys[i]]) return false;
    }

    return true;

};

最长回文串

  • 要求

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

注意: 假设字符串的长度不会超过 1010

示例 1:

输入:
"abccccdd"

输出:
7

解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
  • 思路

记录每一个字符串出现的次数,既有maxLength = Math.floor(count / 2) * 2得到回文数的两边数值,最后在判断是否有中心字符,有则+1

  • 实现
/**
 * @param {string} s
 * @return {number}
 */
var longestPalindrome = function(s) {
    let maxLength = 0;
    const sMap = {};
    const arr = s.split('');
    for(let i = 0; i < arr.length; i++) {
        sMap[arr[i]] = (sMap[arr[i]] || 0) +1;
    }

    const keys = Object.keys(sMap);

    for(let i = 0; i < keys.length; i++) {
        maxLength += Math.floor(sMap[keys[i]] >> 1) << 1;
        if(sMap[keys[i]] % 2 !== 0 && maxLength % 2 === 0) maxLength++;
    }

    return maxLength;
};