两数之和问题是算法入门最经典的题目之一,题目要求在一个整数数组中找到两个数,使它们的和等于给定的目标值。我们先来看最直观的暴力解法:
java复制class Solution {
public int[] twoSum(int[] nums, int target) {
int[] ans = new int[2];
int len = nums.length;
for(int i = 0; i < len-1; i++){
for(int j = i+1; j < len; j++){
if(nums[i] + nums[j] == target){
ans[0] = i;
ans[1] = j;
}
}
}
return ans;
}
}
这个解法使用了双重循环,外层循环固定一个数,内层循环遍历后面的数,检查两数之和是否等于目标值。这种解法虽然简单直接,但效率较低。
注意:在实际面试中,即使你能想到更优解法,也应该先提出暴力解法,然后再进行优化,这展示了你的思考过程。
时间复杂度分析:
空间复杂度分析:
暴力解法的问题在于每次查找第二个数时都需要遍历整个数组,效率太低。我们可以使用哈希表来优化查找过程:
java复制class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashMap = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int complement = target - nums[i];
if(hashMap.containsKey(complement)){
return new int[]{hashMap.get(complement), i};
}
hashMap.put(nums[i], i);
}
return new int[2];
}
}
这个解法的核心思想是:在遍历数组时,对于每个元素nums[i],我们检查哈希表中是否存在target - nums[i]。如果存在,说明找到了解;如果不存在,就把当前元素存入哈希表。
时间复杂度分析:
空间复杂度分析:
实操心得:使用哈希表时要注意处理重复元素的情况。在这个问题中,由于我们是从前往后遍历,当遇到重复元素时,哈希表中存储的是前一个相同元素的位置,这正好符合题目要求(返回两个不同位置的索引)。
存在重复元素问题要求判断一个数组中是否包含重复元素。最直接的解法同样是暴力法:
java复制class Solution {
public boolean containsDuplicate(int[] nums) {
int len = nums.length;
for(int i = 0; i < len-1; i++){
for(int j = i+1; j < len; j++){
if(nums[i] == nums[j]){
return true;
}
}
}
return false;
}
}
这个解法与两数之和的暴力解法类似,都是通过双重循环比较所有可能的元素对。
时间复杂度:O(n²)
空间复杂度:O(1)
我们可以先对数组进行排序,这样相同的元素会相邻,只需一次遍历就能找到重复元素:
java复制class Solution {
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for(int i = 0; i < nums.length-1; i++){
if(nums[i] == nums[i+1]){
return true;
}
}
return false;
}
}
时间复杂度分析:
空间复杂度分析:
注意事项:排序会改变原始数组中元素的位置,如果题目要求不能修改原数组,这种方法就不适用。
使用哈希表可以进一步优化时间复杂度:
java复制class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> hashSet = new HashSet<>();
for(int num : nums){
if(hashSet.contains(num)){
return true;
}
hashSet.add(num);
}
return false;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
实操技巧:在实际应用中,如果数据规模很大,哈希表解法通常是最优选择,因为它的时间复杂度最低。但在内存受限的环境中,可能需要考虑排序解法。
在实现上,HashSet实际上就是使用HashMap的key部分,value部分用一个固定的对象填充。
在实现算法时,特别要注意以下边界条件:
掌握了这两道题目的解法后,可以尝试以下类似题目:
两数之和的应用:
存在重复元素的应用:
在实际开发中,算法不仅仅是解决编程题的工具,更重要的是培养解决问题的思维方式。建议从简单题目入手,逐步建立算法思维,再挑战更复杂的问题。