nSum系列题目总结

超、凢脫俗 2022-06-08 11:28 247阅读 0赞

1、Two Sum

原题地址:https://leetcode.com/problems/two-sum/description/

题目描述:

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,

return [0,1].

思路:设置一个哈希表用来存储元素num及下标,这样可以在o(1)的时候复杂度里面查找到target-num这个元素是否存在。如果存在是接返回两个元素的下标即可。

AC代码:

  1. vector<int> twoSum(vector<int> &numbers, int target)
  2. {
  3. //Key is the number and value is its index in the vector.
  4. unordered_map<int, int> hash;
  5. vector<int> result;
  6. for (int i = 0; i < numbers.size(); i++) {
  7. int numberToFind = target - numbers[i];
  8. //如果numberToFind在哈希表中存在,直接返回两个数的下标
  9. if (hash.find(numberToFind) != hash.end()) {
  10. //+1 because indices are NOT zero based
  11. result.push_back(hash[numberToFind] + 1);
  12. result.push_back(i + 1);
  13. return result;
  14. }
  15. //如果不在哈希表中,则将当前元素放入哈希表中
  16. hash[numbers[i]] = i;
  17. }
  18. return result;
  19. }

(2)3sum

原题地址:https://leetcode.com/problems/3sum/description/

题目描述

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:

[

[-1, 0, 1],

[-1, -1, 2]

]

思路:引用上一题的思路,在遍历到元素num的时候,相当于求后两个元素是否能组成和为-num。但是会出现重复元素的情况,因此需要先排序。

先固定第一个元素first,然后second指向下一个元素,third指向最后一个元素,找出second+third=-first的情况


^ ^ ^

| | |

| +- second third

+-first

如果nums[first] + nums[second] + nums[third] < 0, 这是需要增大sum,所以second++


^ ^ ^

| | |

| +- second third

+-first

如果sum > target,即nums[first] + nums[second] + nums[third] >0,third—。

如果sum = target,直接存起来当前的结果


^ ^ ^

| | |

| +- second third

+-first

循环的条件是second<third

-—————————————————————————-

^ ^ ^

| |

|

|

+- second third

+-first

结束条件first=len-3, second = len-2, third = len-1


^ ^ ^

| | `- third

| +- second

+-first

AC代码:

  1. class Solution {
  2. public:
  3. vector<vector<int>> threeSum(vector<int>& nums) {
  4. int len = nums.size();
  5. vector<vector<int> > res;
  6. sort(nums.begin(), nums.end());
  7. for(int index = 0;index < len;index++){
  8. int target = -nums[index];
  9. int front = index+1;
  10. int back = len-1;
  11. while(front < back){
  12. int sum = nums[front] + nums[back];
  13. if(sum < target){
  14. front++;
  15. }else if(sum > target){
  16. back--;
  17. }else{
  18. vector<int> triplet(3, 0);
  19. triplet[0] = nums[index];
  20. triplet[1] = nums[front];
  21. triplet[2] = nums[back];
  22. res.push_back(triplet);
  23. while(front < back && nums[front] == triplet[1])
  24. front++;
  25. while(front < back && nums[back] == triplet[2])
  26. back--;
  27. }
  28. }//while
  29. while(index+1 < len && nums[index+1] == nums[index]){
  30. index++;
  31. }
  32. }//for
  33. return res;
  34. }
  35. };

(3)3Sum Closest

原题地址:https://leetcode.com/problems/3sum-closest/description/

题目描述:

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

For example, given array S = {-1 2 1 -4}, and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

思路:

前面和上一题思路一样,只是在算的过程中存一下差diff,每算出来一个结果的时候和diff进行比较,如果比diff还小,用当前结果覆盖之前算出来的结果

AC代码:

  1. class Solution {
  2. public:
  3. int threeSumClosest(vector<int>& nums, int target) {
  4. int len = nums.size();
  5. if(len<3){
  6. return 0;
  7. }
  8. sort(nums.begin(), nums.end());
  9. int first,second,third;
  10. int diff =INT_MAX; //间隔
  11. int value; //值
  12. for(first=0;first<len-2;++first){
  13. second = first+1;
  14. third = len-1;
  15. while(second < third){
  16. int sum = nums[first]+nums[second]+nums[third];
  17. if(sum == target){
  18. return sum;
  19. }else if(sum < target){
  20. if((target-sum) < diff){
  21. diff = target-sum;
  22. value = sum;
  23. }
  24. second++;
  25. }else{
  26. if((sum-target) < diff){
  27. diff = sum-target;
  28. value = sum;
  29. }
  30. third--;
  31. }
  32. }//while
  33. }//for
  34. return value;
  35. }
  36. };

(4)4Sum

原题地址:https://leetcode.com/problems/4sum/description/

题目描述:

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note: The solution set must not contain duplicate quadruplets.

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:

[

[-1, 0, 0, 1],

[-2, -1, 1, 2],

[-2, 0, 0, 2]

]

思路:

先固定前两个数,后两个数跟前面题同样的思路

AC代码:

  1. class Solution {
  2. public:
  3. vector<vector<int>> fourSum(vector<int>& nums, int target) {
  4. vector<vector<int> > res;
  5. int len = nums.size();
  6. if(len<4){
  7. return res;
  8. }
  9. sort(nums.begin(), nums.end());
  10. for(int i=0;i<len-3;++i){
  11. if(i>0 && nums[i] == nums[i-1]) continue; //去掉重复的数
  12. if((nums[i]+nums[i+1]+nums[i+2]+nums[i+3]) > target) break; //做一些剪枝,最小的四个数相加都比target大时,肯定无解
  13. if((nums[i]+nums[len-1]+nums[len-2]+nums[len-3]) < target) continue; //做一些剪枝,当i固定时,当前最大的相加都比target小i++
  14. for(int j=i+1;j<len-1;++j){
  15. //再固定第二个数
  16. if(j>i+1 && nums[j] == nums[j-1]) continue;
  17. if((nums[i] + nums[j] + nums[j+1] + nums[j+2]) > target) break;
  18. if((nums[i] + nums[j] + nums[len-1] + nums[len-2]) < target) continue;
  19. int left = j+1;
  20. int right = len-1;
  21. while(left < right){
  22. int sum = nums[i]+nums[j]+nums[left]+nums[right];
  23. if(sum == target){
  24. res.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
  25. do{left++;}while(left<right && nums[left] == nums[left-1]);
  26. do{right--;}while(left<right && nums[right] == nums[right+1]);
  27. }else if(sum < target){
  28. left++;
  29. }else{
  30. right--;
  31. }
  32. }
  33. }
  34. }//for
  35. return res;
  36. }
  37. };

(5)今年腾讯的一道笔试题:拼凑硬币

题目描述:小Q十分富有,拥有非常多的硬币,小Q拥有的硬币是有规律的,对于所有的非负整数K,小Q恰好各有两个面值为2^k的硬币,所有小Q拥有的硬币就是1,1,2,2,4,4,8,8…..小Q有一天去商店购买东西需要支付n元钱,小Q想知道有多少种方案从他拥有的硬币中选取一些拼凑起来恰好是n元(如果两种方案某个面值的硬币选取的个数不一样就考虑为不一样的方案)

输入:

输入包括一个整数n(1<=n<=10^18),表示小Q需要支付多少钱,注意n的范围

输出:

输出一个整数,表示小Q可以拼凑出n元钱的方案数

样例输入:6

样例输出:3 (例如4+2, 4+1+1, 2+2+1+1)

常规方法:使用动态规划

使用数组dp[n, i]表示使用1,1,2,2,4,4, …, 2^i, 2^i可以组合成n的方案数

dp[0, i] = 1,当n=0时,即所有面值的硬币都不选,所以只有一种方案

dp[1, i] = 1, 当n=1时,只能选取一个一元的硬币,所以只有一种方案

res[2, 0]=1,即只选取两个一元硬币,所以只有一种方案

res[n, 0] = 0,当n>=3时,无法只使用1组成大于2的数,所以方案数为0

res[n, i] = sum(num[n-2^i*m, i-1]), n, i取其他,0<=m<=2

代码:

  1. #include <iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. int n;
  7. while(cin>>n){
  8. //一些特殊情况处理
  9. if(n == 0 || n == 1){
  10. return 1;
  11. }
  12. int m = log(n)/log(2) + 1;
  13. //dp[n,m]
  14. int i,j;
  15. int** dp = new int*[n+1];
  16. for(i=0;i<=n;++i){
  17. dp[i] = new int[m];
  18. }
  19. //初始化二维数组
  20. for(i=0;i<m;++i){
  21. dp[0][i] = 1;
  22. dp[1][i] = 1;
  23. }
  24. dp[1][0] = 1;
  25. dp[2][0] = 1;
  26. for(i=1;i<=n;++i){
  27. for(j=1;j<m;++j){
  28. int sum = 0;
  29. for(int m=0;m<3;++m){
  30. int rest = (int)(i-pow(2, j)*m);
  31. if(rest >= 0){
  32. sum+=dp[rest][j-1];
  33. }
  34. }
  35. dp[i][j] = sum;
  36. }
  37. }
  38. cout<<dp[n][m-1]<<endl;
  39. }
  40. return 0;
  41. }

一个很秒的思路

将硬币分为两份:1,2,4,8,16,… 和1,2,4,8,16,…

组成两个数值为a, b的两个数,他们的和是a+b=n;

a在第一份中只有可能有一种组合方式(采用二进制的思想,任何一个数都可以由若干个2^i的数相加的和组成),而b = n-a也只会有一种组合形式。

将a和b使用二进制表示,举个例子n=11,有a=101, b=110这种组合,即a = 1+0+4=5,b=0+2+4=6。但是注意到会有重复的情况,比如111+100和101+110本质上是同一种组合方法,所以需要将二个数做二进制异或然后去重。

代码:

  1. #include <iostream>
  2. #include<set>
  3. using namespace std;
  4. int main()
  5. {
  6. int n;
  7. while(cin>>n){
  8. set<int> countset;
  9. for(int i=1;i<=n/2;i++){
  10. int result =i^(n-i);
  11. countset.insert(result);
  12. }
  13. cout<<countset.size()<<endl;
  14. }
  15. return 0;
  16. }

发表评论

表情:
评论列表 (有 0 条评论,247人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java基础题目总结

    有些基础题目由于工作中用的比较少但却又是不可少的,这样回答起来就会反应慢,不确定,不准确,特此开了文章记录遇到的不确定或者回答比较拗口的问题。 1.servlet是单例的吗,

    相关 面试题目总结

    马上又到了金九银十是招聘的旺季:博主这里收集了一些相应的面试题目,提供给大家参考学习!!!!!!!!当然这里也仅仅是参考,更多的知识还是自己不断的去积累学习掌握!!! St

    相关 MySQL题目总结

    1.数据库三范式是什么? 1. 第一范式(1NF):字段具有原子性,不可再分。(所有关系型数据库系统都满足第一范式数据库表中的字段都是单一属性的,不可再分) 2. 第二范