LeetCode中数组中三数之和
LeetCode中的数组题目以实际问题背景和算法优化为主要考察方向,经常涉及到常见算法思想。
三数之和(3Sum)问题是数组中常见的问题之一。给定一个整数数组 nums,找出其中三个数满足它们的和为 0。
示例:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
在LeetCode中,我们可以在题库中搜索到三数之和问题,这里以题号15为例。在阅读问题描述后,我们需要考虑问题的解决方式。对于三数之和,我们可以采用暴力破解或使用特定的算法来解决。在算法实现中,我们需要注意优化算法以提高效率。
步骤1: 算法的初步风格检查
首先,我们需要检查算法的初步风格。我们可以先按照伪代码实现算法。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
int len = nums.length;
if(len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
以上是参考官方文档给出的Solution ,其通过先排序,然后枚举第一个数,接着在剩下的数字中使用双指针枚举两个数,时间复杂度为 O(N^2)。
接下来我们对以上代码进行解析,找出其中使用到的算法优化。
步骤2: 算法优化的相关知识点
- 排序
对于三数之和问题,排序是其中一个必经之路。为什么需要排序呢?先排序可以使整个数组变得有序,并使得枚举的过程前后循序一致。
在Java中通过sort()函数可以轻松地对数组进行排序。
Arrays.sort(nums);
- 双指针
双指针算法在LeetCode中也十分常见。对于三数之和的问题,我们在排序后,两层遍历枚举第一层和第二层,第三层通过左右指针进行计算。这其中的双指针算法提供了极大的帮助。
接下来我们看一下在三数之和问题中左右指针如何运用:
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
- 去重
对于三数之和的问题,我们需要注意去重。在对数组进行排序后,可以判断两个数字是否相同。
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
- 数组实现及索引获取
在Java中,数组是最常见的数据类型之一。我们可以通过固定的索引值直接进行数组调用,获取数组的某一项。 例如:
nums[2]
- List
List是Java中常用的容器类,他的主要用途是动态存放集合中的元素。
List中有六种实现方式,每种方式都有特定的优劣,常用的方式有 ArrayList 和 LinkedList。
在大多数场景下,ArrayList 是最常用的 List 实现。它使用动态数组来存储所有的元素,因此它具有通过索引访问元素的能力,并在列表末尾添加和删除元素的良好性能。
在上面的Solution中,我们就使用了ArrayList来存储结果的元素。在Java中实现List可以使用以下代码:
List<List<Integer>> ans = new ArrayList<>();
在这里,我们调用Java中ArrayList的add()方法,将符合条件的三元组添加到ans中。
- 时间复杂度与空间复杂度分析
算法的时间复杂度和空间复杂度是评价算法性能的两个重要指标,需要在算法实现过程中进行分析。 对于三数之和的问题,我们使用了双指针和去重等算法优化,时间复杂度为O(N^2),空间复杂度为O(N),其中N指数组的长度。
步骤3: 算法实现过程
在了解问题及其算法优化之后,我们可以开始着手实现算法解决方案。在编写代码时,需要注意变量名的规范以及代码的清晰易懂。
下面是基于以上算法思路的三数之和问题Java解决方案代码示例:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
int len = nums.length;
if(len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
通过以上代码我们可以看出,在 Java 语言中实现三数之和问题,既有简单的语言特性,又有算法优化的实现,是一个综合能力较高,需要积累学习和实践的算法问题。
总结
三数之和问题是一个常见的算法优化问题,在LeetCode和其他算法题库中经常出现。通过学习和练习,我们可以掌握以下技能:
- 排序算法对于大多数算法问题都是基础且必须掌握的算法思想,可在算法实现过程中体现出排序算法在时间复杂度上的优势。
- 双指针算法在算法实现中有很好的实践价值,可以很好的提高思路的灵活性,有效优化算法时间复杂度。
- 算法去重在算法实现中非常重要,可以有效节省空间复杂度和避免重复计算,需要细心分析和实践。
- 计算数组元素时间复杂度和空间复杂度是评价算法性能的重要指标,需要在实现过程中做到全方位的考虑。