leetcode 1.Two Sum 、167. Two Sum II - Input array is sorted 、15. 3Sum 、16. 3Sum Closest 、 18. 4Sum 、653. Two Sum IV - Input is a BST

时间:2023-03-08 16:17:09

1.two sum

用hash来存储数值和对应的位置索引,通过target-当前值来获得需要的值,然后再hash中寻找

错误代码1:

Input:
[3,2,4]
6
Output:
[0,0]
Expected:
[1,2]

同一个数字不能重复使用,但这个代码没排除这个问题

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
unordered_map<int,int> m;
for(int i = ;i < nums.size();i++)
m[nums[i]] = i;
for(int i = ;i < nums.size();i++){
int num = target - nums[i];
if(m.count(num)){
result.push_back(i);
result.push_back(m[num]);
break;
}
}
return result;
}
};

错误代码2:

Input:
[3,3]
6
Output:
[]
Expected:
[0,1]

可以使用相同的数字,但不能使用同一位置的数字,这个错误代码实际上是针对相同数字,而不是同一位置的数字

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
unordered_map<int,int> m;
for(int i = ;i < nums.size();i++)
m[nums[i]] = i;
for(int i = ;i < nums.size();i++){
int num = target - nums[i];
if(m.count(num) && num != nums[i]){
result.push_back(i);
result.push_back(m[num]);
break;
}
}
return result;
}
};

正确代码:

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
unordered_map<int,int> m;
for(int i = ;i < nums.size();i++)
m[nums[i]] = i;
for(int i = ;i < nums.size();i++){
int num = target - nums[i];
if(m.count(num) && m[num] != i){
result.push_back(i);
result.push_back(m[num]);
break;
}
}
return result;
}
};

说白了错误2是判断数值相等,正确的写法是判断索引是否相等,就直接拒绝了这种同一个数字重复两次的情况

167. Two Sum II

数组是有序的,所以用两个指针从两侧向中间滑动就可以解决

class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> result;
int start = ;
int end = numbers.size() - ;
while(start < end){
int tmp = numbers[start] + numbers[end];
if(tmp == target){
result.push_back(start+);
result.push_back(end+);
break;
}
else if(tmp < target)
start++;
else
end--;
}
return result;
}
};

15. 3Sum

先将数组排序,然后固定一个数,再将剩下两个数类似于two sumII的方法在数组开始和末尾进行滑动。

因为不求重复的,所以在滑动的过程中:1.在for循环中遇到相同的数字直接continue

                  2.在while循环中也是直接++或者--

                          3.另外如果当便利到的第一个数大于0了,那后面的数都会大于0,也就没有了计算的意义,所以可以直接break掉

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
if(nums.size() < )
return result;
sort(nums.begin(),nums.end());
for(int i = ;i <= nums.size() - ;i++){
if(nums[i] > )
break;
if(i > && nums[i] == nums[i-])
continue;
int target = - nums[i];
int start = i + ;
int end = nums.size() - ;
while(start < end){
int sum = nums[start] + nums[end];
if(sum == target){
vector<int> res;
res.push_back(nums[i]);
res.push_back(nums[start]);
res.push_back(nums[end]);
result.push_back(res);
while(start < end && nums[start] == nums[start+])
start++;
while(start < end && nums[end-] == nums[end])
end--;
start++;
end--;
}
else if(sum < target)
start++;
else
end--;
}
}
return result;
}
};

# 这个题必须有if(nums.size() < 3),不然在nums为[]时就会报错。
原因在于https://*.com/questions/47947956/reference-binding-to-null-pointer-of-type-value-type
size()函数返回的是无符号的,0-3会得到一个很大的数

leetcode 1.Two Sum 、167. Two Sum II - Input array is sorted  、15. 3Sum  、16. 3Sum Closest  、 18. 4Sum 、653. Two Sum IV - Input is a BST

16. 3Sum Closest

与3Sum类似的思路,先排序,然后固定其中一个值,再滑动另外两个值。3Sum相等时还需要继续移动start、end,但这个时候的比较是比较diff的最小值,滑动判断的条件是根据sum与target的值在判断

错误写法:

认为初始sum的时候计算了第一个位置,即index=0,for循环就从index=1开始,但实际上只计算了前三个,index=0还有很多其他的和的情况,比如index=0、index=1、index=3

class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int sum = nums[] + nums[] + nums[];
int res = sum;
int diff = abs(target - sum);
for(int i = ;i <= nums.size() - ;i++){
int start = i + ;
int end = nums.size() - ;
while(start < end){
int sum = nums[i] + nums[start] + nums[end];
int new_diff = abs(target - sum);
if(new_diff < diff){
diff = new_diff;
res = sum;
}
if(sum < target)
start++;
else
end--;
}
}
return res;
}
};

正确写法:

class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int sum = nums[] + nums[] + nums[];
int res = sum;
int diff = abs(target - sum);
for(int i = ;i <= nums.size() - ;i++){
int start = i + ;
int end = nums.size() - ;
while(start < end){
int sum = nums[i] + nums[start] + nums[end];
int new_diff = abs(target - sum);
if(new_diff < diff){
diff = new_diff;
res = sum;
}
if(sum < target)
start++;
else
end--;
}
}
return res;
}
};

18. 4Sum

这个题和3Sum很像,但3Sum的target是固定为0,4Sum是任意target。

两者都是先排序,3Sum是固定一个数,4Sum类似于固定两个数,即有两个数是外层for循环。两者都需要去重。

错误写法:

j > 1,这种情况就要报错:

Input:
[-1,0,1,2,-1,-4]
-1
Output:
[[-4,0,1,2]]
Expected:
[[-4,0,1,2],[-1,-1,0,1]]

j > 1这种写法会把之后所有的j > 1相同的都去掉,让后面的根本没有进行比较

class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
if(nums.size() < )
return result;
sort(nums.begin(),nums.end());
for(int i = ;i <= nums.size() - ;i++){
if(i > && nums[i] == nums[i-])
continue;
for(int j = i + ;j <= nums.size() - ;j++){
if(j > && nums[j] == nums[j-])
continue;
int start = j + ;
int end = nums.size() - ;
while(start < end){
int sum = nums[i] + nums[j] + nums[start] + nums[end];
if(sum == target){
vector<int> res;
res.push_back(nums[i]);
res.push_back(nums[j]);
res.push_back(nums[start]);
res.push_back(nums[end]);
result.push_back(res);
while(start < end && nums[start] == nums[start+])
start++;
while(start < end && nums[end] == nums[end-])
end--;
start++;
end--;
}
else if(sum < target)
start++;
else
end--;
}
}
}
return result;
}
};

正确写法:

class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
if(nums.size() < )
return result;
sort(nums.begin(),nums.end());
for(int i = ;i <= nums.size() - ;i++){
if(i > && nums[i] == nums[i-])
continue;
for(int j = i + ;j <= nums.size() - ;j++){
if(j > + && nums[j] == nums[j-])
continue;
int start = j + ;
int end = nums.size() - ;
while(start < end){
int sum = nums[i] + nums[j] + nums[start] + nums[end];
if(sum == target){
vector<int> res;
res.push_back(nums[i]);
res.push_back(nums[j]);
res.push_back(nums[start]);
res.push_back(nums[end]);
result.push_back(res);
while(start < end && nums[start] == nums[start+])
start++;
while(start < end && nums[end] == nums[end-])
end--;
start++;
end--;
}
else if(sum < target)
start++;
else
end--;
}
}
}
return result;
}
};

653. Two Sum IV - Input is a BST

只要是两数之和的题,一定要记得先尝试用Hash来做,这道题只不过是把数组变成了一棵二叉树而已,换汤不换药。

还是用递归的思想,遍历到每个节点的时候,用target-当前节点的值,看hash里面是否存储了值。如果没有就递归遍历,同时将此节点的值存储在hash中,以便后面的值去寻找。

class Solution {
public:
bool findTarget(TreeNode* root, int k) {
unordered_set<int> container;
return findTarget(root,k,container);
}
bool findTarget(TreeNode* root,int k,unordered_set<int>& container){
if(root == NULL)
return false;
int val = k - root->val;
if(container.count(val))
return true;
container.insert(root->val);
return findTarget(root->left,k,container) || findTarget(root->right,k,container);
}
};

一种错误写法:

如果在函数定义的时候不加引用,就会报错。这是因为,你先遍历了左子树然后才去遍历的右子树,遍历右子树的时候container应该已经存储了左子树的值才对,只有加引用才能改变container

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool findTarget(TreeNode* root, int k) {
unordered_set<int> container;
return findTarget(root,k,container);
}
bool findTarget(TreeNode* root,int k,unordered_set<int> container){
if(!root)
return false;
int target = k - root->val;
if(container.find(target) != container.end())
return true;
container.insert(root->val);
return findTarget(root->left,k,container) || findTarget(root->right,k,container);
}
};

454. 4Sum II

https://www.cnblogs.com/grandyang/p/6073317.html

class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
unordered_map<int,int> m;
for(int i = ;i < A.size();i++){
for(int j = ;j < B.size();j++){
m[A[i] + B[j]]++;
}
}
int res = ;
for(int i = ;i < C.size();i++){
for(int j = ;j < D.size();j++){
int tmp = -(C[i] + D[j]);
if(m.find(tmp) != m.end())
res += m[tmp];
}
}
return res;
}
};