前端JavaScript力扣HOT100刷题【51-100】

注:纯手打,如有错误欢迎评论区交流!
转载请注明出处:https://blog.youkuaiyun.com/testleaf/article/details/148953015
编写此文是为了更好地学习前端知识,如果损害了有关人的利益,请联系删除!
本文章将不定时更新,敬请期待!!!
欢迎点赞、收藏、转发、关注,多谢!!!
前端JavaScript力扣HOT100刷题【1-50】:
https://blog.youkuaiyun.com/testleaf/article/details/147258015

目录

九、图论

51、【中等】岛屿数量

题目描述:
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:
grid = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ]
输出:1
示例 2:
输入:
grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ]
输出:3

/**
 * @param {character[][]} grid
 * @return {number}
 */
var numIslands = function(grid) {
   
   
    const m = grid.length, n = grid[0].length;
    function dfs(i, j) {
   
   
        // 出界,或者不是 '1',就不再往下递归
        if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] !== '1') {
   
   
            return;
        }
        grid[i][j] = '2'; // 插旗!避免来回横跳无限递归
        dfs(i, j - 1); // 往左走
        dfs(i, j + 1); // 往右走
        dfs(i - 1, j); // 往上走
        dfs(i + 1, j); // 往下走
    }

    let ans = 0;
    for (let i = 0; i < m; i++) {
   
   
        for (let j = 0; j < n; j++) {
   
   
            if (grid[i][j] === '1') {
   
    // 找到了一个新的岛
                dfs(i, j); // 把这个岛插满旗子,这样后面遍历到的 '1' 一定是新的岛
                ans++;
            }
        }
    }
    return ans;
};

52、【中等】腐烂的橘子

题目描述:
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
0 代表空单元格;
1 代表新鲜橘子;
2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1

示例 1:

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2:
输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。
示例 3:
输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

/**
 * @param {number[][]} grid
 * @return {number}
 */
var orangesRotting = function(grid) {
   
   
    const m = grid.length, n = grid[0].length;
    let fresh = 0;
    let q = [];
    for (let i = 0; i < m; i++) {
   
   
        for (let j = 0; j < n; j++) {
   
   
            if (grid[i][j] === 1) {
   
   
                fresh++; // 统计新鲜橘子个数
            } else if (grid[i][j] === 2) {
   
   
                q.push([i, j]); // 一开始就腐烂的橘子
            }
        }
    }
    let ans = 0;
    while (fresh && q.length) {
   
   
        ans++; // 经过一分钟
        const tmp = q;
        q = [];
        for (const [x, y] of tmp) {
   
    // 已经腐烂的橘子
            for (const [i, j] of [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]]) {
   
    // 四方向
                if (0 <= i && i < m && 0 <= j && j < n && grid[i][j] === 1) {
   
    // 新鲜橘子
                    fresh--;
                    grid[i][j] = 2; // 变成腐烂橘子
                    q.push([i, j]);
                }
            }
        }
    }
    return fresh ? -1 : ans;
};

53、【中等】课程表

题目描述:
你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

/**
 * @param {number} numCourses
 * @param {number[][]} prerequisites
 * @return {boolean}
 */
var canFinish = function(numCourses, prerequisites) {
   
   
    const g = Array.from({
   
    length: numCourses }, () => []);
    for (const [a, b] of prerequisites) {
   
   
        g[b].push(a);
    }
    const colors = Array(numCourses).fill(0);
    // 返回 true 表示找到了环
    function dfs(x) {
   
   
        colors[x] = 1; // x 正在访问中
        for (const y of g[x]) {
   
   
            if (colors[y] === 1 || colors[y] === 0 && dfs(y)) {
   
   
                return true; // 找到了环
            }
        }
        colors[x] = 2; // x 完全访问完毕
        return false; // 没有找到环
    }
    for (let i = 0; i < numCourses; i++) {
   
   
        if (colors[i] === 0 && dfs(i)) {
   
   
            return false; // 有环
        }
    }
    return true; // 没有环
};

54、【中等】实现 Trie (前缀树)

题目描述:
Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。
请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false

示例:
输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"] [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释

Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True
var Trie = function() {
   
   
    this.root = new Node();
};

function Node() {
   
   
    this.son = Array(26).fill(null);
    this.end = false;
}

/** 
 * @param {string} word
 * @return {void}
 */
Trie.prototype.insert = function(word) {
   
   
    let cur = this.root;
    for (let c of word) {
   
   
        c = c.charCodeAt(0) - 'a'.charCodeAt(0);
        if (cur.son[c] === null) {
   
   
            cur.son[c] = new Node();
        }
        cur = cur.son[c];
    }
    cur.end = true;
};

Trie.prototype._find = function(word) {
   
   
    let cur = this.root;
    for (let c of word) {
   
   
        c = c.charCodeAt(0) - 'a'.charCodeAt(0);
        if (cur.son[c] === null) {
   
   
            return 0;
        }
        cur = cur.son[c];
    }
    return cur.end ? 2 : 1;
};

/** 
 * @param {string} word
 * @return {boolean}
 */
Trie.prototype.search = function(word) {
   
   
    return this._find(word) === 2;
};

/** 
 * @param {string} prefix
 * @return {boolean}
 */
Trie.prototype.startsWith = function(prefix) {
   
   
    return this._find(prefix) !== 0;
};

/** 
 * Your Trie object will be instantiated and called as such:
 * var obj = new Trie()
 * obj.insert(word)
 * var param_2 = obj.search(word)
 * var param_3 = obj.startsWith(prefix)
 */

十、回溯

55、【中等】全排列

题目描述:
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
   
   
    const res = [], path = [];
    backtracking(nums, []);
    return res;
    
    function backtracking(nums, used) {
   
   
        const k = nums.length
        if(path.length === k) {
   
   
            res.push(Array.from(path));
            return;
        }
        for (let i = 0; i < k; i++ ) {
   
   
            if(used[i]) continue;
            path.push(nums[i]);
            used[i] = true;
            backtracking(nums, used);
            path.pop();
            used[i] = false;
        }
    }
};

56、【中等】子集

题目描述:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) {
   
   
    let result = []
    let path = []
    backtracking(0)
    return result

    function backtracking(startIndex) {
   
   
        result.push([...path])
        for(let i = startIndex; i < nums.length; i++) {
   
   
            path.push(nums[i])
            backtracking(i + 1)
            path.pop()
        }
    }
};

57、【中等】电话号码的字母组合

题目描述:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = ""
输出:[]
示例 3:
输入:digits = "2"
输出:["a","b","c"]

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
   
   
    const k = digits.length;
    const map = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"];
    if(!k) return [];
    if(k === 1) return map[digits].split("");

    const res = [], path = [];
    backtracking(digits, k, 0);
    return res;

    function backtracking(n, k, a) {
   
   
        if(path.length === k) {
   
   
            res.push(path.join(""));
            return;
        }
        for(const v of map[n[a]]) {
   
   
            path.push(v);
            backtracking(n, k, a + 1);
            path.pop();
        }
    }
};

58、【中等】组合总和

题目描述:
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[

### 关于 LeetCode Hot 100 策略 #### 制定学习计划 为了高效完成 LeetCode Hot 100 的练习,制定合理的学习计划至关重要。可以根据不同类型的目来安排每天的任务量,比如先集中攻克某一类问如数组操作或是链表处理等[^1]。 #### 掌握基础数据结构与算法概念 深入理解和掌握基本的数据结构(例如 数组、链表、哈希表 和 字符串)以及常用算法(例如 双指针法、栈与队列的应用、二叉树遍历),这有助于更轻松地解决复杂度较高的挑战性问。 #### 注重实践并反复练习 对于每一种类型的问都应多做几次类似的实例,尤其是那些被标记为困难级别的习;通过不断重复加深记忆,并尝试不同的解法提高灵活性和创造性思维能力[^2]。 #### 学会总结归纳 每次做完一道新之后都要认真思考其背后的原理是什么?有没有更好的方法去实现它呢?将遇到过的难整理成笔记形式保存下来以便日后查阅复习之用。 ```python def solve_problem(problem_id, solution_approach): """ A function to simulate the process of solving a problem with given approach. Args: problem_id (int): The ID or index number associated with each specific coding challenge on platforms like LeetCode. solution_approach (str): Description about how this particular issue will be tackled including any relevant algorithms used. Returns: str: Confirmation message indicating successful completion along with brief explanation regarding chosen methodology applied during resolution phase. Example Usage: >>> print(solve_problem(55,"Using Greedy Algorithm")) Problem No.55 solved using greedy algorithm which ensures optimal choice at every step leading towards overall best outcome possible within constraints provided by question statement itself. """ return f"Problem No.{problem_id} solved {solution_approach}." ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

testleaf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值