怒刷LeetCode的第25天(Java版)

目录

第一题

题目来源

题目内容

解决方法

方法一:闭合为环

第二题

题目来源

题目内容

解决方法

方法一:动态规划

方法二:组合数学

方法三:递归

方法四:数学公式

第三题

题目来源

题目内容

解决方法

方法一:动态规划

方法二:深度优先搜索(DFS)


第一题

题目来源

61. 旋转链表 - 力扣(LeetCode)

题目内容

解决方法

方法一:闭合为环

题目要求将链表中的节点向右移动 k 个位置,我们可以使用如下的思路来解决:

  1. 首先统计链表的长度,并将链表的尾节点与头节点相连,形成一个环状链表。
  2. 确定真正需要断开的位置,即倒数第 k+1 个节点(因为需要将第 k 个节点移动到头节点的位置)。
  3. 找到断开位置的前一个节点 pre,并将 pre 的 next 指针置为 null,这样链表就被切断成两部分。
  4. 将原本的尾节点指向原本的头节点,即完成了链表的旋转。
  5. 返回新的头节点。
/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {// 处理特殊情况if (head == null || head.next == null || k == 0) {return head;}// 统计链表长度int length = 1;ListNode oldTail = head;while (oldTail.next != null) {length++;oldTail = oldTail.next;}// 将链表的尾节点与头节点相连,形成环状链表oldTail.next = head;// 确定真正需要断开的位置int newTailIndex = length - k % length - 1;ListNode newTail = head;for (int i = 0; i < newTailIndex; i++) {newTail = newTail.next;}// 找到断开位置的前一个节点 preListNode newHead = newTail.next;newTail.next = null;return newHead;
}
}

复杂度分析:

  • 时间复杂度:O(N),其中 N 表示链表的长度。我们需要先遍历链表求出链表的长度,然后再遍历链表找到新的尾节点并断开链表。总共需要遍历链表两次,因此时间复杂度是 O(N)。
  • 空间复杂度:O(1),只需要常数的额外空间用于存储一些变量。

LeetCode运行结果:

第二题

题目来源

62. 不同路径 - 力扣(LeetCode)

题目内容

解决方法

方法一:动态规划

由于机器人只能向下或者向右移动一步,因此到达每个格子的路径只可能来自其上方格子或左侧格子。

设 dp[i][j] 表示从起点到 (i,j) 格子的路径数,则有:

dp[i][j] = dp[i-1][j] + dp[i][j-1]

边界条件为 dp[0][j] 和 dp[i][0] 均为 1,因为对于第一行和第一列上的格子,机器人只能一直向右或向下走到终点。

最终答案即为 dp[m-1][n-1],也就是到达终点的路径总数。

class Solution {public int uniquePaths(int m, int n) {int[][] dp = new int[m][n];// 边界条件for (int j = 0; j < n; j++) {dp[0][j] = 1;}for (int i = 0; i < m; i++) {dp[i][0] = 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];}
}

复杂度分析:

时间复杂度:

  • 初始化:需要填充边界条件,即 O(n + m) 的时间复杂度。
  • 状态转移:需要遍历整个矩阵一次,对于每个格子需要常数时间进行计算,因此是 O(mn) 的时间复杂度。

因此总时间复杂度为 O(mn)。

空间复杂度:

使用了一个 m×n 的矩阵来存储中间状态,因此空间复杂度为 O(mn)。由于题目规定 m 和 n 都不超过 100,因此空间复杂度不会太大。

LeetCode运行结果:

方法二:组合数学

除了动态规划,还可以使用组合数学的方法来解决这个问题。

在一个 m×n 的网格中,机器人需要向下移动 m-1 步,向右移动 n-1 步,总共需要移动 m+n-2 步。在这些步骤中,机器人需要选择 m-1 个位置作为向下移动的步骤,并且剩下的 n-1 个位置作为向右移动的步骤。

因此,问题转化为从 m+n-2 个位置中选择 m-1 个位置的组合数。可以使用组合数公式来计算。

class Solution {public int uniquePaths(int m, int n) {// 计算组合数long ans = 1;for (int x = n, y = 1; y < m; ++x, ++y) {ans = ans * x / y;}return (int) ans;}
}

复杂度分析:

  • 对于这种使用组合数公式计算路径数的方法,时间复杂度为 O(min(m, n))。这是因为在计算组合数时,需要进行 m-1 次乘法和除法运算,而 m-1 是较小的值。
  • 空间复杂度是 O(1),因为只需要使用常数级别的额外空间来保存结果。

总结起来,这种方法相对于动态规划而言,在某些情况下可能更高效,尤其是当 m 和 n 较大时。但是需要注意的是,在 m 和 n 较接近时,两种方法的时间复杂度相差不大。

LeetCode运行结果:

方法三:递归

除了动态规划和组合数学,还可以使用递归来解决这个问题。

思路是从起点出发,每次向下或向右移动一步,并将问题转化为到达下一个格子的路径总数。递归的终止条件是到达终点时返回 1,表示找到一条有效路径。递归的过程中,将所有有效路径进行累加,并返回最终结果。

class Solution {public int uniquePaths(int m, int n) {return uniquePathsRecursive(m, n, 0, 0);}private int uniquePathsRecursive(int m, int n, int i, int j) {// 到达终点,返回 1 表示找到一条有效路径if (i == m - 1 && j == n - 1) {return 1;}// 越界情况,返回 0 表示无效路径if (i >= m || j >= n) {return 0;}// 递归向下和向右移动一步,并将结果累加return uniquePathsRecursive(m, n, i + 1, j) + uniquePathsRecursive(m, n, i, j + 1);}
}

复杂度分析:

这种递归方法的时间复杂度较高,是指数级别的。因为在每个格子上,都会有两种选择:向下或向右移动。总共需要递归调用的次数为 2^(m+n-2),其中 m+n-2 是总共需要移动的步数。所以在 m 和 n 较大时,这种方法的效率会非常低。

因此,一般情况下推荐使用动态规划或组合数学的方法来解决路径计数问题。递归方法只在简单情况下使用,或者作为理解动态规划思想的一种辅助手段。

LeetCode运行结果:

方法四:数学公式

除了前面提到的动态规划、组合数学和递归方法外,还可以使用数学公式来计算路径数。

根据题目要求,机器人只能向下或向右移动,且每次只能移动一步。假设机器人需要从起点 (0, 0) 到达终点 (m-1, n-1),总共需要移动 m+n-2 步。

在这 m+n-2 步中,机器人必然需要选择 m-1 个位置作为向下移动的步骤,并且剩下的 n-1 个位置作为向右移动的步骤。

因此,问题可以转化为从 m+n-2 个位置中选择 m-1 个位置的组合数,即 C(m-1, m+n-2) 或 C(n-1, m+n-2)。

import java.math.BigInteger;class Solution {public int uniquePaths(int m, int n) {BigInteger numerator = factorial(m + n - 2);BigInteger denominator = factorial(m - 1).multiply(factorial(n - 1));BigInteger paths = numerator.divide(denominator);return paths.intValue();}// 计算阶乘private BigInteger factorial(int n) {BigInteger result = BigInteger.valueOf(1);for (int i = 1; i <= n; i++) {result = result.multiply(BigInteger.valueOf(i));}return result;}
}

复杂度分析:

时间复杂度:

  • 计算阶乘的复杂度为 O(m+n),其中 m 和 n 分别为矩阵的行数和列数。在计算阶乘时,需要进行 m+n-2 次乘法运算,每次乘法的时间复杂度为 O(1)。
  • 除法运算的复杂度也为 O(m+n),其中 m 和 n 分别为矩阵的行数和列数。在进行除法运算时,需要对阶乘结果进行除法操作,每次除法的时间复杂度为 O(1)。

综合起来,使用数学公式来计算路径数的总体时间复杂度为 O(m+n)。

空间复杂度:

使用数学公式来计算路径数的空间复杂度为 O(1)。

在计算路径数时,只需要创建一个变量来保存阶乘的结果,并进行除法运算得到最终的路径数。因此,不需要额外的空间来存储中间结果或辅助数组,空间复杂度为常数级别的 O(1)。无论输入矩阵的大小如何,所需的额外空间都会保持不变。

需要注意的是,在实际应用中,计算阶乘可能会导致溢出问题。为了处理大数,可以使用大整数类来进行阶乘计算,例如 Java 中的 BigInteger 类。但是,由于大整数运算的效率较低,因此在 m 和 n 较大时,使用动态规划或其他更高效的方法会更合适。

LeetCode运行结果:

第三题

题目来源

63. 不同路径 II - 力扣(LeetCode)

题目内容

解决方法

方法一:动态规划

可以使用动态规划来解决这个问题。定义一个二维数组 dp,其中 dp[i][j] 表示从起始点到达网格位置 (i, j) 的不同路径数。

根据题目要求,如果某个网格位置有障碍物,则路径数为 0。对于其他位置,可以通过动态规划的递推关系求解。具体步骤如下:

1、初始化 dp 数组,将起始点的路径数设为 1。
2、遍历每个网格位置 (i, j),计算其路径数:

  • 如果当前位置有障碍物,将 dp[i][j] 设为 0。
  • 否则,dp[i][j] 可由其左侧位置 (i-1, j) 和上方位置 (i, j-1) 的路径数相加得到,即 dp[i][j] = dp[i-1][j] + dp[i][j-1]。

3、最后,返回终点位置 (m-1, n-1) 的路径数,即 dp[m-1][n-1]。

class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;int n = obstacleGrid[0].length;int[][] dp = new int[m][n];// 初始化起始点路径数dp[0][0] = obstacleGrid[0][0] == 0 ? 1 : 0;// 计算路径数for (int i = 1; i < m; i++) {dp[i][0] = obstacleGrid[i][0] == 0 ? dp[i-1][0] : 0;}for (int j = 1; j < n; j++) {dp[0][j] = obstacleGrid[0][j] == 0 ? dp[0][j-1] : 0;}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {if (obstacleGrid[i][j] == 0) {dp[i][j] = dp[i-1][j] + dp[i][j-1];} else {dp[i][j] = 0;}}}return dp[m-1][n-1];
}}

复杂度分析:

时间复杂度:O(mn),其中m 和n 分别是网格的行数和列数。需要遍历整个网格,对于每个网格位置最多只需要计算两次路径数,因此时间复杂度是O(mn)。

空间复杂度:O(mn),需要创建一个二维数组 dp 来记录每个网格位置的路径数。由于每个位置只与其上方和左侧的位置有关,因此需要使用一个与网格大小相同的二维数组,空间复杂度为 O(mn)。

LeetCode运行结果:

方法二:深度优先搜索(DFS)

从起始点开始递归遍历所有可能的路径,每次向下或向右移动一步。如果当前位置是障碍物或超出边界,则返回0;若已经到达终点,则返回1。通过累加向下和向右的路径数来计算不同的路径数。为了避免重复计算,可以使用记忆数组(memo)记录已经计算过的位置。

class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;int n = obstacleGrid[0].length;return dfs(obstacleGrid, 0, 0, new int[m][n]);}private int dfs(int[][] obstacleGrid, int i, int j, int[][] memo) {// 如果超出边界或遇到障碍物,返回0if (i < 0 || j < 0 || i >= obstacleGrid.length || j >= obstacleGrid[0].length || obstacleGrid[i][j] == 1) {return 0;}// 如果已经到达终点,返回1if (i == obstacleGrid.length - 1 && j == obstacleGrid[0].length - 1) {return 1;}// 如果当前位置已经计算过路径数,直接返回if (memo[i][j] > 0) {return memo[i][j];}// 向下和向右进行搜索,累加不同路径数int paths = dfs(obstacleGrid, i + 1, j, memo) + dfs(obstacleGrid, i, j + 1, memo);// 记录当前位置的路径数memo[i][j] = paths;return paths;}
}

复杂度分析:

  • 时间复杂度:O(m * n),需要遍历整个网格。
  • 空间复杂度:O(m * n),需要使用记忆数组。

LeetCode运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP原理特性详解

文章目录 可靠传输机制1.确认应答2.超时重传2.连接管理1.三次握手2.四次挥手 传输效率1.滑动窗口2.流量控制3.拥塞控制4.延时应答5.捎带应答 面向字节流粘包问题 TCP异常情况 可靠传输机制 可靠性&#xff1a;即发送方知道数据是发送成功了&#xff0c;还是失败了。 1.确认应答…

如何精细化管理嵌入式软件项目?ACT汽车电子与软件技术周演讲回顾

2023 ACT汽车电子与软件技术周已于8月18日在中国上海落下帷幕。展会现场&#xff0c;龙智技术支持部负责人、Atlassian认证专家叶燕秀与龙智技术工程师邱洁玉共同为观众带来了主题为“更好、更快、更安全&#xff1a;嵌入式开发中的最佳实践与工具链构建”的演讲&#xff0c;分…

elasticsearch内存占用详细分析

内存占用 ES的JVM heap按使用场景分为可GC部分和常驻部分。 可GC部分内存会随着GC操作而被回收&#xff1b; 常驻部分不会被GC&#xff0c;通常使用LRU策略来进行淘汰&#xff1b; 内存占用情况如下图&#xff1a; common space 包括了indexing buffer和其他ES运行需要的clas…

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树 前言一. 恢复二叉搜索树二. 有序链表转换二叉搜索树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 恢复二叉搜索树 原题链接 首先&#xff0c;一个正常地二叉搜索树在中序遍历下&#xff0c;遍历…

【2023研电赛】东北赛区一等奖作品:基于FPGA的小型水下无线光通信端机设计

本文为2023年第十八届中国研究生电子设计竞赛东北赛区一等奖作品分享&#xff0c;参加极术社区的【有奖活动】分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&#xff01;&#xff0c;分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&a…

312.戳气球

将戳气球转换到添加气球&#xff0c;记忆搜索slove(i,j)&#xff1a;在开区间(i,j)全部填满气球得到的最多硬币数&#xff0c;两端val[i]、val[j] class Solution { public:vector<vector<int>> ans;vector<int> val;int slove(int left,int right){if(left&…

【java基础学习】之DOS命令

#java基础学习 1.常用的DOS命令&#xff1a; dir:列出当前目录下的文件以及文件夹 md: 创建目录 rd:删除目录cd:进入指定目录 cd.. :退回到上级目录 cd\ : 退回到根目录 del:删除文件 exit:退出dos命令行 1.dir:列出当前目录下的文件以及文件夹 2.md: 创建目录 …

假期AI新闻热点:亚运会Al技术亮点;微软GPT-4V论文精读;Perplexity推出pplx-api;DALL-E 3多渠道测评 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f525; 科技感拉满&#xff0c;第19届杭州亚运会中的Al技术亮点 八年筹备&#xff0c;杭州第19届亚运会开幕式于9月23日晚隆重举行&#xff0…

输入电压转化为电流性 5~20mA方案

输入电压转化为电流性 5~20mA方案 方案一方案二方案三 方案一 XTR111是一款精密的电压-电流转换器是最广泛应用之一。原因有二&#xff1a;一是线性度非常好、二是价格便宜。总结成一点&#xff0c;就是性价比高。 典型电路 最终电路 Z1二极管处输出电流表达式&#xff1a;…

【Redis】基础数据结构-quicklist

Redis List 在Redis3.2版之前&#xff0c;Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时&#xff0c;Redis使用压缩列表实现&#xff0c;否则Redis使用双向链表实现。 ziplist存在问题 不能保存过多的元素&#xff0c;否则查找复杂度…

Google-CTF-2016-Stego.pcap数据包解析

Google-CTF-2016&#xff08;a-cute-stegosaurus-100&#xff09; 前言&#xff1a;别人发的题目 随便看看 记录一下解题过程&#xff01; 知识点: 在报文段中有 6Bit 的状态控制码&#xff0c; 分别如下tcp URG&#xff1a;紧急比特&#xff08;urgent&#xff09;&#x…

echarts 中如何将 legend 设置成「直线」

Thinking系列&#xff0c;旨在利用10分钟的时间传达一种可落地的编程思想。 echarts 中如何将 legend 设置成「直线」&#xff1f; 所有图例均为直线 可以通过 itemHeight 和 itemWidth 来统一控制 legend: {itemHeight: 2,itemWidth: 20,data: [Expenses, Income]}部分是直线…

【数据结构-字符串 三】【字符串转换】字符串解码

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【字符串转换】&#xff0c;使用【字符串】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

Linux CentOS7 yum仓库

在windows下安装一个软件很轻松&#xff0c;只要双击setup或者.exe的文件&#xff0c;安装提示连续“下一步”即可&#xff0c;然而linux系统下安装一个软件似乎并不那么轻松&#xff0c;因为我们不是在图形界面下。 本文我们将讨论如何在linux下安装一个软件。 一、linux软件…

Netron【.pt转.onnx模型展示】

接着上一篇写哈&#xff0c;如何转.onnx的。 因为是转.onnx类型的&#xff0c;需要先安装onnx的包。 这是直接pip install onnx后转onnx报的错&#xff1a; 很显然是版本问题导致的&#xff0c;so: 将export.py的脚本拉到最下面的parse_opt函数&#xff0c;把“17”改为“12”…

C# .net创建一个MVC框架工程

二、C# .net创建一个MVC框架工程 1.步骤 首先打开VS &#xff0c;然后点击创建新项目 在三个选项框中输入我们需要的项目条件 最后一步创建完毕 创建会在资源解决方案生成如图&#xff1a;

vulnhub_driftingblues7靶机渗透测试

Driftingblues7靶机 文章目录 Driftingblues7靶机信息收集web渗透获取权限另外思路靶机总结 信息收集 使用nmap扫描得到靶机ip为192.168.78.174&#xff0c;开放发端口有很多&#xff0c;而且开放了443端口&#xff0c;所以访问网站是需要https协议的 再对该网站进行目录扫描&…

如何查看端口占用(windows,linux,mac)

如何查看端口占用&#xff0c;各平台 一、背景 如何查看端口占用&#xff1f;网上很多&#xff0c;但大多直接丢出命令&#xff0c;没有任何解释关于如何查看命令的输出 所谓 “查端口占用”&#xff0c;即查看某个端口是否被某个程序占用&#xff0c;如果有&#xff0c;被哪…

【List-Watch】

List-Watch 一、定义二、工作机制三、调度过程 一、定义 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件&#xff0c;向 APIServer 发送命令&#xff0c;在 …

2023/10/7 -- ARM

【程序状态寄存器读写指令】 1.指令码以及格式 mrs:读取CPSR寄存器的值 mrs 目标寄存器 CPSR&#xff1a;读取CPSR的数值保存到目标寄存器中msr:修改CPSR寄存器的数值msr CPSR,第一操作数:将第一操作数的数值保存到CPSR寄存器中//修改CPSR寄存器&#xff0c;也就表示程序的状…