(https://leetcode.com/problems/two-sum/) 详细题解:https://www.acwing.com/solution/LeetCode/content/47/
题目描述 给定一个整型数组,要求返回两个数的**下标**,使得两数之和等于给定的目标值,要求同一个下标不能使用两次。 数据保证有且仅有一组解。 样例 给定数组 nums = [2, 7, 11, 15],以及目标值 target = 9, 原始思路: 用两个for循环遍历数组,找出结果,时间复杂度为O(n2) //优化思路1:(这里需要返回下标,此思路不好) //排序后双指针做,时间复杂度为O(nlogn) 优化思路2: 使用hash表,建立HashMap<Integer, Integer> map,键值对为<nums[i],i>。遍历数组nums,对每个数nums[i],查询hash表中是否有key等于target-nums[i]的记录,若有,则找到;否则,将num[i]和下标i存入hash表。因为hash表的查找时间复杂度可以看作是O(1),所以算法时间复杂度就降为O(n)了.代码:
vector<int> twoSum(vector<int>& nums, int target) { vector<int> res; int len = nums.size(); if (!len) return res; unordered_map<int, int> hash; for (int i = 0; i < len; i++){ if (hash.find(target - nums[i]) != hash.end()){ return vector<int>({hash[target-nums[i]], i}); } hash[nums[i]] = i; } return res; }(https://leetcode.com/problems/3sum/) 详细题解:https://www.acwing.com/solution/LeetCode/content/60/
题目描述 类似于Two Sum,给定一个整型数组,要求返回所有不重复的三元组,且每个三元组的和等于0。 样例 给定数组 nums = [-1, 0, 1, 2, -1, -4],返回 [ [-1, 0, 1], [-1, -1, 2] ]。 原始思路: 3个for循环,但会超时 优化思路: 使用双指针,首先将数组排序(防止重复),然后一重循环**无重复**枚举第一个数字,然后接下来采用 两头向里寻找的方式无重复的构造剩下的两个数字,具体在循环中: 1. 初始化l为st+1,r为n-1。 2. 当l<r时,如果当前nums[l] + nums[r] + nums[i]== target,则增加答案并同时向后**无重复移动**l,向前**无重复移动**r; 否则根据nums[l] + nums[r]+ nums[i]与target的关系判断移动l还是移动r。这种方法的时间复杂度可以控制在O(n2)。代码:
vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; if (nums.size() < 3) return res; sort(nums.begin(), nums.end()); int len = nums.size(); for (int i = 0; i < len; i++){ while(i && i < len && nums[i] == nums[i - 1]) i++; // 无重复地枚举每一个数字 + 判边界 int l = i + 1, r = len - 1; while(l < r){ if (nums[l] + nums[r] + nums[i] == 0){ res.push_back(vector<int>({nums[i], nums[l], nums[r]})); while(l < r && nums[l + 1] == nums[l]) l++; // 无重复地移动 while(l < r && nums[r - 1] == nums[r]) r--; // 无重复地移动 l++; r--; } else if (nums[l] + nums[r] + nums[i] > 0) r--; else l++; } } return res; }(https://leetcode.com/problems/3sum-closest/) 详细题解: https://www.acwing.com/solution/LeetCode/content/64/
题目描述 给定一个整型数组和一个目标值target,要求从数组中选出三个数使得它们的和与target最接近,返回这个和。数据保证仅有一个最优解。 样例 给定数组 nums = [-1, 2, 1, -4],以及目标值 target = 1。 由于 nums[0] + nums[1] + nums[2] = -1 + 2 + 1 = 2,与 target 最接近,所以返回 2。 原始思路: 3个for循环,但会超时 优化思路: 使用双指针,首先将数组排序(防止重复),然后一重循环**无重复**枚举第一个数字,然后接下来采用 两头向里寻找的方式无重复的构造剩下的两个数字,具体在循环中: 1. 初始化l为**st+1**,r为n-1。 2. 当l<r时,如果当前nums[l] + nums[r] + nums[i]== target,直接返回答案target。 否则根据nums[l] + nums[r]与target的关系判断移动l还是移动r。这种方法的时间复杂度可以控制在O(n2)。代码:
int threeSumClosest(vector<int>& nums, int target) { if (nums.size() < 3) return 0; int len = nums.size(); sort(nums.begin(), nums.end()); int sum = nums[0] + nums[1] + nums[2]; // 选0会Bug,选INT_MAX或INT_MIN有溢出风险 for (int i = 0; i < len; i++){ while(i && i < len && nums[i] == nums[i - 1]) i++; int l = i + 1, r = len - 1; while(l < r){ int tmp = nums[l] + nums[r] + nums[i]; if (tmp == target) return target; else if (tmp > target) r--; else l++; if (abs(target - tmp) < abs(target - sum)) sum = tmp; } } return sum; }(https://leetcode.com/problems/4sum/) 详细题解: https://www.acwing.com/solution/LeetCode/content/66/
题目描述 类似于 3Sum,给定一个整型数组和 targettarget,要求返回所有不重复的四元组,且每个四元组的和等于 target。 样例 给定数组 nums = [1, 0, -1, 0, -2, 2] 和 target = 0 返回 [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]。 原始思路: 4重枚举,超时 优化思路: 首先将数组排序(防止重复),然后2重**无重复**枚举第一个数字和第二个数字。接下来采用两头向里寻找的方式无重复的构造剩下的两个数字,具体在循环中: 1. 初始化l为**st+1**,r为n-1。 2. 当l<r时,如果当前nums[l] + nums[r] + nums[i] + nums[j] == target,直接返回答案target。 否则根据nums[l] + nums[r] + nums[i] + nums[j]]与target的关系判断移动l还是移动r。这种方法的时间复杂度可以控制在O(n2)。 特别注意: 如何做到**无重复**枚举,详见代码。范围设置很重要代码:
vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> res; if (nums.size() < 4) return res; int len = nums.size(); sort(nums.begin(), nums.end()); for (int i = 0; i < len; i++){ while(i && i < len && nums[i] ==nums[i - 1]) i++; // 无重复枚举 for (int j = i + 1; j < len; j++){ while(j > i + 1 && j < len && nums[j] == nums[j - 1]) j++; // 无重复枚举 int l = j + 1, r = len - 1; while(l < r){ int tmp = nums[i] + nums[j] + nums[l] + nums[r]; if (tmp == target){ res.push_back(vector<int>({nums[i], nums[j], nums[l], nums[r]})); while(l < r && nums[l + 1] == nums[l]) l++; while(l < r && nums[r - 1] == nums[r]) r--; l++; r--; } else if (tmp > target) r--; else l++; } } } return res; }4Sum II (https://leetcode.com/problems/4sum-ii/submissions/) 详细题解:https://www.acwing.com/solution/LeetCode/content/358/
题目描述 给定四个整型数组 A、B、C和D,计算有多少四元组 (i, j, k, l) 使得 A[i] + B[j] + C[k] + D[l] 等于0。 为了使问题简单一些,A、B、C和D长度相同且为N,0≤N≤5000≤N≤500。所有的整数在−228−228到228−1228−1内,答案个数保证不超过231−1231−1。 样例 Input: A = [ 1, 2] B = [-2,-1] C = [-1, 2] D = [ 0, 2] Output: 2 解释: 两个四元组为: 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 原始思路: 4重循环,超时 优化思路: 先两重循环。将中间答案用哈希表记录。然后再循环剩下两个数组,看他们的相反数是否已经存在在hash 表中,如果存在,则将对应的次数累加到答案中。代码:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) { int res = 0; int len = A.size(); unordered_map<int, int> hash; for (int i = 0; i < len; i++){ for (int j = 0; j < len; j++){ hash[A[i] + B[j]] ++; } } for (int i = 0; i < len; i++){ for (int j = 0; j < len; j++){ if (hash.find(-C[i] - D[j]) != hash.end()) res += hash[-C[i] - D[j]]; } } return res; }