「力扣」1. 两数之和

博客围绕力扣1.两数之和题目展开,给出题目描述,即从整数数组中找出和为目标值的两个整数并返回下标。介绍了两种题解,一是暴力解法,两层循环比较和;二是Hash表解法,借助hash表存储数据,是空间换时间的方法,还对比了两种解法的复杂度。

1. 两数之和

「力扣」1. 两数之和

题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104

  • -109 <= nums[i] <= 109

  • -109 <= target <= 109

  • 只会存在一个有效答案

**进阶:**你可以想出一个时间复杂度小于 O(n2) 的算法吗?

题解

「暴力解法」

两层循环,第一层循环定义指针i指向每一个元素,第二层循环定义指针j指向每一个元素,比较nums[i] + nums[j]target,如果相等则退出循环,返回[i, j]

class Solution {
    public int[] twoSum(int[] nums, int target) {
       for (int i = 0; i < nums.length - 1; i++) { //如果是最后一个元素,则无需再向后比较,所以此处i < nums.length - 1
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    return new int[]{i, j};
                }
            }
        }
        return new int[0];
    }
}

时间复杂度是O(n²),空间复杂度是O(1)

提交看下:

提交记录

时间复杂度太高。

「Hash表」

我们可以借助hash表,以一个具体的用例来解答解释。

hash解法

使用for循环:

  1. i = 0的时候,计算target - nums[i] = 7在hash表中有没有,此时肯定是没有的,那么就将数据存储到hash表中,KV如何存储呢?K=(nums[i] = 2)value=i
  2. i = 1的时候,同样计算target - nums[i] = 2,再次查看hash表中有没有2,此时hash表中有2,所以通过key=2,获取hash中对应的value,与当下的i做成一个数组,得到[0, 1]。
class Solution {
    public int[] twoSum(int[] nums, int target) {
        // map存储`[nums[i], i]
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int v = target - nums[i];
            // 去hash表中查询是否存在v
            if (map.containsKey(v)) {
                return new int[]{map.get(v), i};
            }
            map.put(nums[i], i);
        }
        return new int[0];
    }
}

提交:

运行结果

可以看到时间上确实是快了,但是空间占用多了点,这是典型的空间换时间的方法,空间复杂度是O(n),时间复杂度也是O(n)。

### 解决 LeetCode 15 题:三数之和问题 LeetCode 15 题要求找出数组中所有满足三数之和为 0 的唯一组合。为了避免重复的三元组,需要对数组进行排序,并在遍历时跳过重复值。 #### 算法思路 1. **排序数组**:将输入数组排序,这样有助于在查找过程中跳过重复值,并且可以通过双指针法高效地找到符合条件的三元组。 2. **遍历数组**:将当前元素作为第一个数,使用双指针法查找剩余两个数,使得三者的和为 0。 3. **避免重复**:在遍历过程中,如果当前元素与前一个元素相同,则跳过,以避免重复的三元组。 4. **双指针法**:对于当前元素后的子数组,使用左右指针分别从两端向中间移动,寻找符合条件的组合。如果三数之和小于 0,则左指针右移;如果大于 0,则右指针左移;如果等于 0,则记录当前三元组,并继续移动指针以寻找其他组合。 #### C++ 实现代码 ```cpp #include <vector> #include <algorithm> class Solution { public: std::vector<std::vector<int>> threeSum(std::vector<int>& nums) { std::vector<std::vector<int>> result; int n = nums.size(); // 对数组进行排序 std::sort(nums.begin(), nums.end()); for (int i = 0; i < n - 2; ++i) { // 跳过重复的 nums[i] if (i > 0 && nums[i] == nums[i - 1]) continue; int left = i + 1, right = n - 1; while (left < right) { int sum = nums[i] + nums[left] + nums[right]; if (sum < 0) { ++left; // 和过小,左指针右移 } else if (sum > 0) { --right; // 和过大,右指针左移 } else { // 找到符合条件的三元组 result.push_back({nums[i], nums[left], nums[right]}); // 跳过重复的 nums[left] while (left < right && nums[left] == nums[left + 1]) ++left; // 跳过重复的 nums[right] while (left < right && nums[right] == nums[right - 1]) --right; ++left; // 继续寻找下一个可能的组合 --right; } } } return result; } }; ``` #### 代码说明 - **排序**:通过 `std::sort` 对数组排序,使后续的双指针操作能够更高效地进行。 - **外层循环**:遍历数组,将当前元素 `nums[i]` 作为第一个数。 - **内层双指针**:在 `left` 和 `right` 指针之间寻找满足 `nums[i] + nums[left] + nums[right] == 0` 的组合。 - **去重处理**:通过比较当前元素与前一个元素是否相同,跳过重复值,确保结果中没有重复的三元组。 这种方法的时间复杂度为 $O(n^2)$,因为外层循环是 $O(n)$,而内层双指针操作也是 $O(n)$。空间复杂度取决于结果存储,最坏情况下为 $O(n^2)$。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值