LeetCode Hot 100~Day3

news2024/11/25 18:26:47

目录

字母异位词分组

最大子数组和 

跳跃游戏

合并区间

不同路径 

最小路径和 

爬楼梯 

颜色分类

子集

单词搜索

二叉树的中序遍历 

不同的二叉搜索树 


字母异位词分组

题目链接:49. 字母异位词分组

 示例

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

解题思路:计数法,遍历每一个字符串,记录其每一个字符出现次数,再按顺序将每个出现次数大于 0 的字母和出现次数拼接成字符串,作为哈希表的键,原字符串作为哈希表的值,将键相同的存入一个链表中,最终将哈希表的值转化为顺序表即可。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> ret = new HashMap<>();
        for (String str : strs) {
            int[] count = new int[26];
            int length = str.length();
            for (int i = 0; i < length; i++) {
                count[str.charAt(i) - 'a']++;
            }
            //按顺序将字符串拼接
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 26; i++) {
                if (count[i] != 0) {
                    sb.append((char) 'a' + i);
                    sb.append(count[i]);
                }
            }
            String key = sb.toString();
            List<String> list = ret.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            ret.put(key, list);
        }
        return new ArrayList<List<String>>(ret.values());
    }
}

最大子数组和 

题目链接:53. 最大子数组和

解题思路:动态规划,列出状态、状态方程、初始值

    状态定义:f(i): 下标为i之前连续子数组的最大和
    状态方程:dp[i]=max{nums[i],dp[i−1]+nums[i]}
    初始值:dp[0] = nums[0]
    返回结果:ret 

class Solution {
    /**
    状态定义:dp(i): 以 nums[i] 结尾的连续子数组的最大和
    状态方程:dp[i]=max{nums[i],dp[i−1]+nums[i]}
    初始值:dp[0] = nums[0]
    返回结果:ret
     */
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        dp[0] = nums[0];
        int ret = nums[0];
        for (int i = 1; i < len; i++) {
            dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
            ret = Math.max(dp[i], ret);
        }
        return ret;
    }
}

跳跃游戏

题目链接:55. 跳跃游戏

 

解题思路:贪心思想,遍历nums数组,如果可以到达该位置,则根据在该位置可以跳跃的长度更新最大可到达位置,如果最大可到达位置大于nums的长度,则返回true,反之遍历结束后返回false。heb

class Solution {
    public boolean canJump(int[] nums) {
        int rightMost = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i <= rightMost) {
                rightMost = Math.max(i + nums[i], rightMost);
                if (rightMost >= nums.length - 1) {
                    return true;
                }
            }
        }
        return false;
    }
}

合并区间

题目链接:56. 合并区间

解题思路:首先对给出的区间按照左边界值进行从小到大的排序, 之后根据每一个区间的左边界和右边界来确定是新增一个区间还是更新当前区间的右边界值。

class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        List<int[]> merged = new ArrayList<>();
        for (int i = 0; i < intervals.length; i++) {
            int l = intervals[i][0];
            int r = intervals[i][1];
            if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < l) {
                merged.add(new int[]{l, r});
            } else {
                merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], r);
            }
        }
        return merged.toArray(new int[merged.size()][]);
    }
}

不同路径 

题目链接:62. 不同路径

 

解题思路:动态规划思想,列出动态规划的状态、状态方程、初始值即可

    状态定义:f(i, j): 从(0, 0)到(i, j)的路径总数

    状态方程:f(i, j) = f(i - 1, j) + f(i, j - 1)

    初始化:f(i, 0) = 1, f(0, i) = 1

    返回值:f(m - 1, n - 1)

class Solution {
    /**
    状态定义:f(i, j): 从(0, 0)到(i, j)的路径总数
    状态方程:f(i, j) = f(i - 1, j) + f(i, j - 1)
    初始化:f(i, 0) = 1, f(0, i) = 1
    返回值:f(m - 1, n - 1)
     */
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for(int i = 0; i < m; i++) {
            dp[i][0] = 1;
        } 
        for (int i = 0; i < n; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
}

最小路径和 

题目链接:64. 最小路径和

 

解题思路:动态规划思想,列出动态规划的状态、状态方程、初始值即可

    状态定义:f(i, j): 从(0, 0)到(i, j)的最小路径和
    状态方程:f(i, j) = min(f(i - 1, j), f(i, j - 1)) + grid[i][j]
    初始值:f(0, i) = grid[0][i] + f(0, i - 1), f(i, 0) = grid[i][0] + f(i - 1, 0) 
    返回值:f(m - 1, n - 1) 

class Solution {
    /**
    状态定义:f(i, j): 从(0, 0)到(i, j)的最小路径和
    状态方程:f(i, j) = min(f(i - 1, j), f(i, j - 1)) + grid[i][j]
    初始值:f(0, i) = grid[0][i] + f(0, i - 1), f(i, 0) = grid[i][0] + f(i - 1, 0) 
    返回值:f(m - 1, n - 1)
     */
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        for (int i = 1; i < n; i++) {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        for (int i = 1; i < m; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[m - 1][n - 1];
    }
}

爬楼梯 

题目链接:70. 爬楼梯

 

解题思路:简单的动态规划问题,由于每次只能跳一个或两个台阶,所以第i阶只能从第i-1阶或者第i-2阶跳上来,因此可以得出状态方程为:f(i) = f(i - 1) + f(i - 2)

    状态定义:f(i): 从0阶到达i阶的跳跃方法数

    状态方程:f(i) = f(i - 1) + f(i - 2)

    初始化:f(0) = 1, f(1) = 2 f(0)代表第一阶,f(1)代表第二阶

    返回值:f(n - 1)

 

class Solution {
    /**
    状态定义:f(i): 从0阶到达i阶的跳跃方法数
    状态方程:f(i) = f(i - 1) + f(i - 2)
    初始化:f(0) = 1, f(1) = 2 f(0)代表第一阶,f(1)代表第二阶
    返回值:f(n - 1)
     */
    public int climbStairs(int n) {
        if (n <= 2) {
            return n;
        }
        int[] dp = new int[n];
        dp[0] = 1;
        dp[1] = 2;
        for (int i = 2; i < n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n - 1];
    }
}

颜色分类

题目链接:75. 颜色分类

 

解题思路:双指针思想,用指针p0来交换0, 指针p1来交换1,遍历数组,如果找到了1,将其与nums[p1]交换,交换结束后p1++;如果找到了0,则先将其与nums[p0]交换,交换结束后判断p0与p1的大小,如果p1大于p0,则将nums[p1]与nums[i]再进行交换,交换结束后p0++,p1++。

例如2,0,2,1,1,0,再经过几次遍历交换后,此时数组的值为0,1,1,2,2,0,此时p0 = 1,p1 = 3,此时i = 5, 首先将i与p0的值进行交换,交换结束后为0,0,1,2,2,1,此时再将i与p1的值进行交换,就得到最终结果0,0,1,1,2,2

class Solution {
    public void sortColors(int[] nums) {
        int n = nums.length;
        int p0 = 0;
        int p1 = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] == 1) {
                swap(nums, i, p1);
                p1++;
            } else if (nums[i] == 0) {
                swap(nums, i, p0);
                if (p0 < p1) {
                    swap(nums, i, p1);
                }
                p0++;
                p1++;
            }
        }
    }
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

子集

题目链接:78. 子集

 

解题思路:回溯思想,当cur == nums.length时,说明深度优先搜索已经走到了尽头,此时就将当前结果加入结果集中,将每一种可能都尝试一遍即可

class Solution {
    List<List<Integer>> ret = new ArrayList<>();
    List<Integer> curRet = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        dfs(0, nums);
        return ret;
    }
    private void dfs(int cur, int[] nums) {
        if (cur == nums.length) {
            ret.add(new ArrayList<Integer>(curRet));
            return;
        }
        curRet.add(nums[cur]);
        dfs(cur + 1, nums);
        curRet.remove(curRet.size() - 1);
        dfs(cur + 1, nums);
    }
}

单词搜索

题目链接:79. 单词搜索

 

解题思路:回溯思想,先在网格中找到单词的第一个字符,之后开始对其上下左右进行查找,看是否存在第二个字符,如果存在则继续判断,反之返回false。由于本题规定不允许字母重复使用,因此定义一个标记数组visited,已经使用过的字母设为1,未使用过的设为0,注意在搜索结束后需要将标记数组置为0. 

class Solution {
    public boolean exist(char[][] board, String word) {
        int m = board.length;
        int n = board[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == word.charAt(0)) {
                   int[][] visited = new int[m][n]; 
                   if (dfs(board, word, visited, 0, i, j)) {
                       return true;
                   }
                }
            }
        }
        return false;
    }
    private boolean dfs(char[][] board, String word, int[][] visited, int index, int i, int j) {
        if (index == word.length()) {
            return true;
        }
        //判断是否越界
        if (i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word.charAt(index) || visited[i][j] == 1) {
            return false;
        }
        if (board[i][j] == word.charAt(index)) {
            visited[i][j] = 1;
            index++;
        }
        boolean ret = false;
        if (dfs(board, word, visited, index, i + 1, j)
            || dfs(board, word, visited, index, i - 1, j)
            || dfs(board, word, visited, index, i, j + 1)
            || dfs(board, word, visited, index, i, j - 1)
        ) {
            ret = true;
        }
        visited[i][j] = 0;
        return ret;
    }
}

二叉树的中序遍历 

题目链接:94. 二叉树的中序遍历

递归

class Solution {
    List<Integer> ret = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if (root == null) {
            return ret;
        }
        inorder(root);
        return ret;
    }
    private void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        inorder(root.left);
        ret.add(root.val);
        inorder(root.right);
    }
}

非递归:利用栈的特性来实现二叉树的中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if (root == null) {
            return ret;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            ret.add(node.val);
            node = node.right;
        }
        return ret;
    }
}

不同的二叉搜索树 

题目链接:96. 不同的二叉搜索树

 

class Solution {
    public int numTrees(int n) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[i - j] * dp[j - 1];
            }
        }
        return dp[n];
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/116180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[DonkeyCar][树莓派]基础01 - 首次配置 - WIFI

2022年圣诞节到来啦&#xff0c;疫情把刚刚起来的工作似乎又慢了下来&#xff0c;在冲刺决赛圈的同时&#xff0c;也许开一个新的领域&#xff0c;写一个博客是比较好的方式。 一、前言 拿到树莓派开发板的时候&#xff0c;一般&#xff0c;供应商都会配合烧录的镜像。但是&am…

《图解TCP/IP》阅读笔记(第七章 7.6)—— BGP 边界网关协议

7.6 BGP BGP&#xff08;Border Gateway Protocol&#xff09;&#xff0c;边界网关协议&#xff0c;是用于连接不同组织机构&#xff08;或者说不同自治系统&#xff09;的一种协议&#xff0c;其属于EGP&#xff08;外部网关协议&#xff09;&#xff0c;我们在7.2节中了解过…

01)FastDFS文件服务器安装和测试可用性

FastDFS简介 ​ FastDFS是一个轻量级的开源分布式文件系统。2008年4月份开始启动。类似google FS的一个轻量级分布式文件系统,纯C实现,支持Linux、FreeBSD、AIX等UNIX系统。 ​ 主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。实现了软件方式的…

PicoRV32 笔记 06 压缩指令集

PicoRV32 中实现压缩指令集选项 COMPRESSED_ISA&#xff0c;当设置COMPRESSED_ISA1开启支持16位指令集。压缩指令有很多优点&#xff0c;当我们在FPGA中实现PicoRV32的时候&#xff0c;使用RISCV的C扩展能有效的增大代码密度&#xff0c;原本32位1条指令变为16位一条指令&#…

synchronized 和 ReentrantLock 的区别

&#x1f388;专栏链接:多线程相关知识详解 synchronized和ReentrantLock的 区别 缺点 优势 synchronized和ReentrantLock两者都是可重入锁 ReentrantLock的三个核心方法: Ⅰ.lock(加锁) Ⅱ.unlock(解锁) Ⅲ.tryLock(尝试加锁) import java.util.concurrent.locks.Reentrant…

Android并发编程里的线程原理

1.进程和线程的概念 抛开那些官方的概念&#xff0c;我们可以大致理解为:进程就是手机里运行的一个个应用&#xff0c;他们都是一个个的进程&#xff08;当然&#xff0c;有些App是多进程的&#xff0c;这个先不谈&#xff09;。线程则是进程中对应的一个任务的执行控制流。如果…

广播机制-案例

广播机制-案例 1.静态注册案例-接收开机广播 1.案例&#xff1a;接收开机的广播 创建自定义的BroadcastReceiver用于处理监听到的系统广播。//接收系统开机的广播事件 public class BootCompleteReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context co…

2023跨境出海指南:马来西亚网红营销白皮书

当前的东南亚市场可谓是是企业出海的大热门&#xff0c;马来西亚作为东南亚地区的第三大经济体&#xff0c;其发展形势也是一片大好。疫情出现后&#xff0c;马来西亚的娱乐和消费转移到线上&#xff0c;对社媒的依赖也催发了网红经济的发展。本文Nox聚星就和大家探讨一下&…

海康威视人脸识别设备对接(一)环境搭建

需要对接海康威视人脸识别设备&#xff0c;这里选择明眸门禁&#xff0c;还有其他的没研究过 打开海康威视开放平台 https://open.hikvision.com/ 选择开放体系&#xff0c;一直选择到设备集成SDK 这里我选择设备网络SDK 点击查看详情 选择对应的版本&#xff0c;我用笔记…

AD入门学习—原理图的绘制3

目录 2.4 CAN&24C02及DS18B20温度传感单元的绘制 2.5 USB单元的绘制 2.6 SD卡及TFT单元的绘制 2.7 NRF24L01单元的绘制 2.8 COM口及PS/2接口的绘制 2.9 DCDC电源输入单元的绘制 2.10 原理图的统一编号及编译检查 学习目录 2.4 CAN&24C02及DS18B20温度传感单元的绘制…

Vue基本指令

1、前端技术的发展&#xff08;html、CSS、JavaScript&#xff09; ​ &#xff08;1&#xff09;jQuery&#xff1a;是对JavaScript进行了封装&#xff0c;使得操作DOM、事件处理、动画处理、ajax交互变得非常简洁、方便。是JavaScript的 库。 ​ &#xff08;2&#xff09…

Moonbeam与Wormhole的Relayer Engine之间的跨链互连合约

如果您不了解Moonbeam&#xff0c;用一句话简单概括来说Moonbeam是跨链通信的中心枢纽。像Axelar、LayerZero和Hyperlane等的协议允许不同EVM上的智能合约互相通信&#xff0c;为Web3 dApp解锁功能方面前所未见的规模。但就目前来说&#xff0c;上述的几个协议的智能合约通信仅…

计算机网络——数据报与虚电路

简介 本篇接上一篇数据交换的内容继续 分组交换其实包含数据报交换和虚电路交换 数据报方式&#xff1a;为网咯层提供外连接服务 虚电报&#xff1a;为网络层提供连接服务 无连接服务&#xff1a;不事先为分组传输确定传输的路径&#xff0c;每个分组独立确定传输路径&#x…

如何实现带动画的动态面包屑,来看看?

大家好&#xff0c;我是派大星&#xff0c;最近在自己手动搭建一个后台管理平台&#xff0c;将其命名为 “雷达行动 Radar-Solution” &#xff0c;在开发的过程中对比了一下其他已经成型的后台解决方案&#xff0c;发现都存在一个共性&#xff0c;就是在Layout的头部都有一个面…

分布式理论之分布式事务

写在前面 我们知道&#xff0c;像MySQL的InnoDB存储引擎提供了事务的能力&#xff0c;严格遵守AICD的事务要求&#xff0c;但是在分布式环境中&#xff0c;一个请求会在多个服务实例存在多个事务&#xff0c;如购物&#xff0c;会有订单系统&#xff0c;支付系统&#xff0c;物…

springboot够用就好系列-1.自定义LengthJudge注解校验字段长度

类似NonNull注解标注在参数之上&#xff0c;表示对应的值不可以为空&#xff0c;利用java的元注解及注解处理器实现检查属性长度的功能。 目录 程序效果 实现过程 样例代码 参考资料 程序效果 截图1.用户名超长提示 检查登录时“用户名”、“密码”字段的长度&#xff0c;此…

安全智能分析 环境迁移

环境迁移 Platfor m Ops for AI 作为整合了 DataOps、MLOps、ModelOps 的复杂技术平台&#xff0c;在项目开发时仅使用一套系统无法支撑平台的稳定搭建&#xff0c;往往需要开发系统、集成测试系统、正式 环境系统在项目生命周期 中协作配合。将表、索引、并发程序、配置内容等…

新手想做短视频可以选择什么领域,这三个可以无脑尝试

大家好&#xff0c;我是蝶衣王的小编 对于小白来说&#xff0c;如果你想通过短视频来赚钱&#xff0c;你不能在流行的领域去做。因为坑不是你能接受的&#xff0c;而且有太多的同行&#xff0c;你的竞争优势没法显现出来。下面分享一下新手适合做的短视频领域​。 一、盘点类型…

海思嵌入式开发-001-基于Ubuntu20.04搭建开发环境

海思嵌入式开发-001-基于Ubuntu20.04搭建开发环境一、虚拟机安装ubuntu20.041、安装虚拟机VMware2、基于虚拟机安装ubuntu20.04二、开发环境配置1、参考资料2、问题汇总一、虚拟机安装ubuntu20.04 1、安装虚拟机VMware 主机配置为Windows 10系统&#xff0c;CPU为i7-8550U 4核…

虹科新闻|ATTO 宣布支持 Apple 最新操作系统 macOS® 13 Ventura

一、即时发布 近期&#xff0c;虹科的合作伙伴ATTO公司宣布支持Apple最新操作系统macOS13 Ventura&#xff0c;所有HK-ATTO适配器、软件和实用程序都已经过新操作系统的测试和验证。 ATTO 34年来为数据密集型计算环境提供网络、存储连接和基础架构解决方案的全球领导者&#…