N数之和问题-算法题

两数之和

sum=target

给定一组无序数据,返回其中两数之和等于target的二元组的下标

// hash
vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int, int> mp;
    for (int i = 0; i < nums.size(); ++i) {
        if (mp.count(target-nums[i]))
            return {i, mp[target-nums[i]]};
        mp[nums[i]] = i;
    }
    return {};
}

// 双指针
vector<int> twoSum(vector<int>& nums, int target) {
    vector<pair<int,int>> v;
    for (int i = 0; i < nums.size(); ++i)
        v.push_back({nums[i], i});
    sort(v.begin(), v.end());
    int left = 0, right = v.size()-1;
	while (left < right) {
		if (v[left].first + v[right].first < target) 
		    ++left;
		else if(v[left].first + v[right].first > target) 
		    --right;
		else return {v[left].second, v[right].second};
	}
	return {};
}

a+b without +

求两整数a、b的和,不能使用+、-运算符;

int getSum(int a, int b) {
    while (b) {
        unsigned int x = (unsigned int)(a & b) << 1;
        a = a ^ b;
        b = x;
    }
    return a;
}

a2+b2=c

给数字c,问是否存在数字a、b满足a2+b2 == c;

// sqrt
bool judgeSquareSum(int c) {
    for (long a = 0; a * a <= c; a++) {
        double b = sqrt(c - a * a);
        if (b == (int)b) {
            return true;
        }
    }
    return false;
}
// 双指针
bool judgeSquareSum(int c) {
    long left = 0, right = (int)sqrt(c);
    while (left <= right) {
        long sum = left*left + right*right;
        if (sum == c) return true;
        else if (sum > c) right--;
        else left++;
    }
    return false;
}
// 费马平方和定理
// 一个非负整数c如果能够表示为两个整数的平方和,当且仅当c的所有形如4k+3的质因子的幂均为偶数。
bool judgeSquareSum(int c) {
    for (int base = 2; base*base <= c; base++) {
        if (c % base != 0)
            continue;
        int exp = 0;
        while (c % base == 0) {
            c /= base;
            exp++;
        }
        if (base % 4 == 3 && exp % 2 != 0)
            return false;
    }
    return c % 4 != 3;
}

三数之和

sum=target

给定一组数据,返回其中三数之和为0的下标组合

// 二分查找
vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>> ret;
    sort(nums.begin(), nums.end());
    for (int i = 0; i < nums.size(); ++i) {
        if (i && nums[i] == nums[i-1]) continue;
        for (int j = i+1; j < nums.size(); ++j) {
            if (j > i+1 && nums[j] == nums[j-1]) continue;
            int num = -(nums[i]+nums[j]);
            int pos = lower_bound(nums.begin()+j+1, nums.end(), num) - nums.begin();
            if (pos != nums.size() && nums[pos] == num) {
                ret.push_back({nums[i], nums[j], num});
            }
        }
    }
    return ret;
}


// 双指针
vector<vector<int>> threeSum(vector<int>& nums) {
    int n = nums.size();
    sort(nums.begin(), nums.end());
    vector<vector<int>> ans;
    for (int first = 0; first < n; ++first) {
        if (first > 0 && nums[first] == nums[first - 1])
            continue;
        int third = n-1, target = -nums[first];
        for (int second = first + 1; second < n; ++second) {
            if (second > first + 1 && nums[second] == nums[second - 1])
                continue;
            while (second < third && nums[second] + nums[third] > target)
                --third;
            if (second == third)
                break;
            if (nums[second] + nums[third] == target)
                ans.push_back({nums[first], nums[second], nums[third]});
        }
    }
    return ans;
}

min(abs(sum-target))

// 二分
int threeSumClosest(vector<int>& nums, int target) {
    sort(nums.begin(), nums.end());
    int dif = 1000000, ret;
    for (int i = 0; i < nums.size(); ++i) {
        int l = i+1, r = nums.size()-1;
        while (l < r) {
            if (abs(nums[i]+nums[l]+nums[r]-target) < dif) {
                ret = nums[i]+nums[l]+nums[r];
                dif = abs(nums[i]+nums[l]+nums[r]-target);
            }
            if (nums[i]+nums[l]+nums[r] < target) ++l;
            else if (nums[i]+nums[l]+nums[r] > target) --r;
            else return target;
        }
    }
    return ret;
}
// 双指针
int threeSumClosest(vector<int>& nums, int target) {
    sort(nums.begin(), nums.end());
    int n = nums.size();
    int best = 1e7;

    auto update = [&](int cur) {
        if (abs(cur - target) < abs(best - target)) {
            best = cur;
        }
    };
    for (int i = 0; i < n; ++i) {
        if (i > 0 && nums[i] == nums[i - 1])
            continue;
        int j = i + 1, k = n - 1;
        while (j < k) {
            int sum = nums[i] + nums[j] + nums[k];
            if (sum == target)
                return target;
            update(sum);
            if (sum > target) {
                int k0 = k - 1;
                while (j < k0 && nums[k0] == nums[k])
                    --k0;
                k = k0;
            } 
            else {
                int j0 = j + 1;
                while (j0 < k && nums[j0] == nums[j])
                    ++j0;
                j = j0;
            }
        }
    }
    return best;
}

四数之和

给定一组数据,返回其中四数之和为target的下标组合

sum=target

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    vector<vector<int>> ret;
    if (nums.size() < 4) return ret;
    sort(nums.begin(), nums.end());
    int n = nums.size();
    for (int i = 0; i < n-3; i++) {
        if (i > 0 && nums[i] == nums[i-1])
            continue;
        if (1LL*nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target)
            break;
        if (1LL*nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target)
            continue;
        for (int j = i+1; j < n-2; j++) {
            if (j > i+1 && nums[j] == nums[j-1])
                continue;
            if (1LL*nums[i] + nums[j] + nums[j+1] + nums[j+2] > target)
                break;
            if (1LL*nums[i] + nums[j] + nums[n-2] + nums[n-1] < target)
                continue;
            int left = j+1, right = n-1;
            while (left < right) {
                int sum = 1LL*nums[i] + nums[j] + nums[left] + nums[right];
                if (sum == target) {
                    ret.push_back({nums[i], nums[j], nums[left], nums[right]});
                    while (left < right && nums[left] == nums[left+1])
                        left++;
                    left++;
                    while (left < right && nums[right] == nums[right-1])
                        right--;
                    right--;
                } 
                else if (sum < target) left++;
                else right--;
            }
        }
    }
    return ret;
}

sum[a.b.c]=num[d]

给定一组数据,返回nums[a]+nums[b]+nums[c] == nums[d],其中a<b<c<d;

// n^4,暴力枚举
int countQuadruplets(vector<int>& nums) {
    int ret = 0, n = nums.size();
    for (int i = 0; i < n-3; ++i) {
        for (int j = i+1; j < n-2; ++j) {
            for (int k = j+1; k < n-1; ++k) {
                for (int x = k+1; x < n; ++x) {
                    ret += (nums[i]+nums[j]+nums[k] == nums[x]);
                }
            }
        }
    }
    return ret;
}
// n^3,枚举c,哈希d,暴力a、b
int countQuadruplets(vector<int>& nums) {
    int n = nums.size(), ret = 0;
    unordered_map<int, int> cnt;
    for (int c = n - 2; c >= 2; --c) {
        ++cnt[nums[c+1]];
        for (int a = 0; a < c; ++a) {
            for (int b = a+1; b < c; ++b) {
                if (cnt.count(nums[a]+nums[b]+nums[c])) {
                    ret += cnt[nums[a]+nums[b]+nums[c]];
                }
            }
        }
    }
    return ret;
}
// nums[a]+nums[b]+nums[c]==nums[d] => nums[a]+nums[b]==nums[d]-nums[c]
// n^2,遍历b,哈希nums[d]-nums[c],遍历a
int countQuadruplets(vector<int>& nums) {
    int n = nums.size(), ret = 0;
    unordered_map<int, int> cnt;
    for (int b = n-3; b >= 1; --b) {
        for (int d = b+2; d < n; ++d)
            ++cnt[nums[d]-nums[b+1]];
        for (int a = 0; a < b; ++a) {
            if (cnt.count(nums[a]+nums[b]))
                ret += cnt[nums[a]+nums[b]];
        }
    }
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值