• 【LeetCode选讲·第五期】「盛最多水的容器」「有效的括号」


    T11 盛最多水的容器

    题目链接:leetcode.cn/problems/co…

    朴素解法

    我们可以采用暴力枚举的朴素解法直接得出答案。

    代码如下:

    function maxArea(heights) {
        let len = heights.length;
        let ans = 0
        for(let i = 0; i < len; i++) {
            for(let j = i + 1; j < len; j++) {
                let height = Math.min(heights[i], heights[j]);
                let w = j - i;
                ans = Math.max(ans, height * w);
            }
        }
        return ans;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这种解法的缺陷也很明显,即枚举次数庞大,程序效率低下。

    双指针+贪心

    我们不妨先设双指针ij,使之分别指向heights数组的两端。现在让我们来分析一下,当指针向数组内侧移动时会发生什么。

    我们知道,盛水的面积Area = w * h,其中w = j - ih = min(heights[i], heights[j])。因此当指针向内侧移动时,w必然减小,因而如果我们希望Area取值尽可能地大,那么就必须使得h取值尽可能大。

    下面我们来分析一下每一次指针移动时,h的变化情况。为了分析的便利,我们不妨假设heights[i]小于heights[j],即h = min(heights[i], heights[j]) = heights[i]

    i向右移动,j不变时:

    • heights[i + 1] < heights[i]时,w减小,h减小,Area减小
    • heights[i + 1] = heights[i]时,w减小,h不变,Area减小
    • heights[i + 1] > heights[i]时,w减小,h变大,Area变大

    i不变,j向左移动时:

    • heights[j - 1] < heights[j]
    • heights[j - 1] ≥ heights[i]w减小,h不变,Area减小
    • heights[j - 1] < heights[i]w减小,h减小,Area减小
    • heights[j - 1] = heights[j]时,w减小,h不变,Area减小
    • heights[j - 1] > heights[j]时,w减小,h不变,Area减小

    综上所述,为了尽可能使Area取得较大的值,我们应时刻尝试将指向高度较小的指针向内测移动。因为由上分析,除此之外我们别无更佳的选择,前述的便已经是最佳的贪心策略!

    代码如下:

    function maxArea(heights) {
        let ans = 0
        let i = 0;
        let j = heights.length - 1;
        while(i < j) {
            let height = Math.min(heights[i], heights[j]);
            let w = j - i;
            ans = Math.max(ans, height * w);
            if(heights[i] < heights[j]) {
                i++;
            } else {
                j--;
            }
        }
        return ans;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在本题中,经过对贪心策略的分析,我们极大简化了枚举的范围,将原本需要双重循环的算法压缩到了只需遍历数组至多一次即可得出结果,实现了程序效率的提升。

    T20 有效的括号

    题目链接:leetcode.cn/problems/va…

    错解释疑

    这是一道简单的模拟题。

    我们拿到题目的第一个想法或许是先获取一个左括号,然后向右检查检查是否在对应位置存在的右括号。这样的想法正确吗?

    假如我们需要检测的字符串是类似于{[()]}这般的,这样做当然没问题;但是假如像题目中给出的例子()[]{},这么做可就不行了!

    栈+哈希表

    栈是本题公认的正确解法。由于题目较为简单,下面直接给出代码:

    function isValid(str) {
        const hash = new Map( [[')', '('], [']', '['], ['}', '{']] );
        const stack = [];
        for(let i = 0; i < str.length; i++) {
            let s = str[i];
            if (s === '(' || s === '[' || s === '{') {
               stack.push(s);
            } else if(hash.get(s) === stack[stack.length - 1]) {
               stack.pop(); 
            } else {
                return false;
            }
        }
        return stack.length === 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    拓展:栈+ASCII码

    想必有强迫症的同学已经注意到了,我们在上面的代码中反复写了两遍([{,看着的确很不舒服,有没有避免这么做的办法?

    OK,现在请你打开浏览器DevToolsConsole面板,将下面的代码粘贴进去,看看会输出什么:

    console.log( '}'.charCodeAt(0) - '{'.charCodeAt(0) );
    console.log( ')'.charCodeAt(0) - '('.charCodeAt(0) );
    console.log( ']'.charCodeAt(0) - '['.charCodeAt(0) ); 
    
    • 1
    • 2
    • 3

    尝试过的你一定惊喜地发现,两种对应括号之间的内码值不会超过2,而又由于题目中已经明确说明字符串中只会出现这三类括号,所以我们可以放心地运用这个结论来改造我们的代码。

    改造后的代码如下:

    function isValid(str) {
        const stack = [];
        for(let i = 0; i < str.length; i++) {
            let s = str[i];
            if (s === '(' || s === '[' || s === '{') {
               stack.push(s);
            } else if(stack.length > 0) {
                let delta = s.charCodeAt(0) - stack[stack.length - 1].charCodeAt(0);
                if(delta > 0 && delta <= 2) {
                    stack.pop(); 
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        return stack.length === 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这样就不需要写两遍括号了吧,哈哈!

  • 相关阅读:
    IDEA阿里云OSS实现文件上传·解决苍穹外卖图片回显
    vue3中使用 tui-image-editor进行图片处理,并上传
    变电站指针式仪表示数识别方法研究
    超适合练手的一套JavaWeb项目 (保安管理系统)
    Linux常用工具及服务(ssh,rsync)
    alexnet pytorch模型和onnx模型速度对比
    企业级流程平台的全功能链路说明
    JDK动态代理为什么必须要基于接口?
    c++编写简易版2048小游戏
    macOS - 处理系统更新红点
  • 原文地址:https://blog.csdn.net/weixin_53312997/article/details/125900021