Java 实现寻找字符串数组中的最长公共前缀及不同路径数量计算(含障碍物)
在计算机科学和软件开发中,经常需要解决一些基本但实用的问题。本文将介绍两种常见问题的解决方案:一是从一组字符串中找出最长公共前缀;二是计算在一个存在障碍物的网格中从起点到终点的不同路径数量。我们将通过具体的 Java 代码实现来探讨这两种问题的解决方法。
寻找字符串数组中的最长公共前缀
在编程领域,我们不时地面临挑战,如从一系列字符串中寻找它们的最长公共前缀。
本篇文章旨在介绍一个既简便又高效的算法来应对这一挑战,并通过Java语言的代码示例进行阐释。
问题描述
给定一个字符串数组 strs
,要求找到其中所有字符串的最长公共前缀。如果不存在公共前缀,则返回空字符串 ""
。
解决方案
为了找到字符串数组中的最长公共前缀,我们可以采用以下策略:
- 首先检查数组是否为空,如果是,则直接返回空字符串。
- 使用一个索引变量
i
逐字符地比较字符串。 - 创建一个
StringBuilder
对象来构建公共前缀。 - 通过一个无限循环
while (true)
来逐字符比较,并在适当的条件下使用break
语句退出循环。 - 在每次循环中,检查当前索引
i
是否超出了数组中任意一个字符串的长度。如果是,则说明已无法找到更长的公共前缀,退出循环。 - 逐个比较字符串数组中的每个字符串,确保当前索引
i
处的字符在所有字符串中都相同。 - 如果当前字符在所有字符串中都相同,则将其添加到
StringBuilder
中,并将索引i
增加 1。 - 如果发现不匹配的字符,则设置标志变量
done
为true
并退出循环。
代码实现
下面是具体的 Java 代码实现:
public class Solution {
public String longestCommonPrefix(String[] strs) {
// 如果字符串数组为空,则返回空字符串
if (strs.length == 0) {
return "";
}
int index = 0;
StringBuilder lcp = new StringBuilder();
// 使用无限循环来逐字符比较
while (true) {
boolean done = false;
// 如果当前索引超出第一个字符串的长度,则停止
if (index >= strs[0].length()) {
break;
}
// 逐个比较字符串数组中的每个字符串
for (int j = 0; j < strs.length; j++) {
// 如果当前索引没有超出字符串的长度
if (index < strs[j].length()) {
// 如果当前字符与第一个字符串的当前字符不同,则停止
if (strs[j].charAt(index) != strs[0].charAt(index)) {
done = true;
break;
}
} else {
// 如果当前索引超出了字符串的长度,则停止
done = true;
break;
}
}
// 如果发现不匹配的字符,则停止
if (done) {
break;
} else {
// 将当前字符添加到公共前缀中
lcp.append(strs[0].charAt(index));
index++;
}
}
// 返回构建好的最长公共前缀
return lcp.toString();
}
}
示例
假设输入的字符串数组为 ["flower","flow","flight"]
。
- 第一个字符
'f'
在所有字符串中都相同,因此加入到lcp
中。 - 第二个字符
'l'
也在所有字符串中相同,因此继续加入到lcp
中。 - 第三个字符
'o'
也在所有字符串中相同,继续加入。 - 第四个字符
'w'
只在"flower"
和"flow"
中出现,但在"flight"
中不是'w'
,因此循环结束。
最终得到的最长公共前缀为 "fl"
。
不同路径数量计算(含障碍物)
在计算机科学中,路径问题是经常遇到的一类问题,特别是在算法和数据结构的学习过程中。本文将探讨如何在一个网格中计算从左上角到右下角的不同路径数量,并考虑某些格子可能存在障碍物的情况。我们将通过具体的 Java 代码实现来解决这个问题。
问题描述
给定一个 m x n
的二维网格 obstacleGrid
,其中 1
表示障碍物,0
表示空地。要求计算从左上角 (0, 0)
到右下角 (m-1, n-1)
的路径数量,只能向下或向右移动。如果路径上有障碍物,则不能通过该路径。
动态规划思路
- 边界条件:如果起点有障碍物,则无解;如果终点有障碍物,则到达终点的路径数为 0。
- 初始化:对于第一行和第一列,如果没有遇到障碍物,则路径数始终为 1;一旦遇到障碍物,后续的所有格子路径数均为 0。
- 递推公式:对于其他格子,如果遇到障碍物,路径数为 0;否则,路径数等于上方格子和左方格子路径数之和。
代码实现
下面是具体的 Java 代码实现:
public class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
// 如果起点有障碍物,直接返回 0
if (obstacleGrid[0][0] == 1) {
return 0;
}
// 初始化路径计数数组
int[][] paths = new int[m][n];
// 初始化第一列
for (int i = 0; i < m; i++) {
if (obstacleGrid[i][0] == 1) {
// 如果遇到障碍物,后续所有格子路径数为 0
break;
}
paths[i][0] = 1;
}
// 初始化第一行
for (int j = 0; j < n; j++) {
if (obstacleGrid[0][j] == 1) {
// 如果遇到障碍物,后续所有格子路径数为 0
break;
}
paths[0][j] = 1;
}
// 计算其他格子的路径数
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1) {
// 如果遇到障碍物,路径数为 0
paths[i][j] = 0;
} else {
// 路径数等于上方格子和左方格子路径数之和
paths[i][j] = paths[i][j - 1] + paths[i - 1][j];
}
}
}
// 返回终点的路径数
return paths[m - 1][n - 1];
}
}
示例
假设输入的网格为:
[
[0, 0, 0],
[0, 1, 0],
[0, 0, 0]
]
- 第一行和第一列的路径数分别为
[1, 1, 1]
和[1, 1, 0]
,因为在(1, 0)
处遇到了障碍物。 - 其他格子的路径数依次计算为:
(1, 1)
处有障碍物,路径数为 0。(2, 1)
处的路径数为paths[1][1] + paths[2][0] = 0 + 1 = 1
。(2, 2)
处的路径数为paths[2][1] + paths[1][2] = 1 + 0 = 1
。
最终结果为 1
。
总结
通过动态规划的方法,我们可以有效地计算出在一个存在障碍物的网格中从起点到终点的不同路径数量。这种方法不仅简洁明了,而且效率高,适用于各种规模的问题。无论是对于学习还是实际应用,这种算法都非常有用。
希望本文能帮助你更好地理解和掌握这两种经典问题的解决方法。通过这两个例子,我们可以看到,通过合理的算法设计和优化,可以解决许多实际问题,并提高程序的性能。