【leetcode X Sum 系列】Two Sum|3Sum|3Sum Closest|4Sum

  终于把leetcode的151题刷完第一遍,第二遍打算在做的过程中,把之前没有记录的题目,分类整合进行解析,首先就是leetcode上的 X Sum问题。


Two Sum 题目:

Given an array of integers, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

解析:在一个数组中找到和为目标值的两个数字下标,该题有三种方法,并且时间复杂度是不断优化的。
方法一:暴力方法,时间复杂度O(N^2),循环数组,获得当前值numbers[i],再遍历数组i~n-1,找到number[j]满足 numbers[i]+numbers[j] = target。
方法二:先进行快速排序,时间复杂度O(NlogN),再定义两个指针p1和p2,分别从头尾向中间移动,如果 numbers[p1]+ numbers[p2] > target,p2向左移动,如果numbers[p1]+numbers[p2] < target,p1向右移动,如果numbers[p1]+numbers[p2] = target,输出p1和p2。
方法三:hash方法,如果是C++,因为map是用红黑树实现,查找时间O(logN),所以时间复杂度O(NlogN),如果是Java,hashMap底层是根据对象的hashCode进行存放的数组结构,查询时间复杂度是O(N)。具体做法是将值和下表存放在map数据结构中,如果当前值number[i]对应的target - nubmer[i]在map中,输出 number[i]和target - nubmer[i],如果当前值number[i]对应的target - nubmer[i]不在map中,将number[i]存入map遍历一次数组即可,C++ AC代码如下:
vector<int > twoSum(vector< int> &numbers , int target) {

                 vector<int > result(2,0);
                 map<int ,int> mapping;
                
                 for (int i = 0; i < numbers.size(); i++){
                                 int temp = numbers [i];
                                 if (mapping[target - temp]>0){
                                                result[0] = mapping[target - temp];
                                                result[1] = i + 1;
                                }
                                 else{
                                                mapping[temp] = i + 1;
                                }
                }
                 return result;
}


3 Sum 题目:

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

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • 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)

解析:这道题目是上一道Two Sum的升级,要求找出数组中满足和为0的三个数字,首先做个快速排序,时间复杂度为O(logN)。循环取出数字num[i]后,针对下标为i~n-1的数字,采取上一题的方法二,其中target等于-num[i],总时间复杂度是O(N^2)。注意代码中可以有多处优化的地方,Java AC代码如下:

	public List<List<Integer>> threeSum(int[] num) {
		
		Arrays.sort(num);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		
		for (int i = 0; i < num.length - 2; i++) {
			
                        //优化一:判断第一个数字是否和上次的第一个数字相同,重复计算
			if (i != 0 && num[i] == num[i - 1]) {
				continue;   
			}
                        
                        //优化二:如果第一个数字为正数,后面的数字更大,三个数字之和不可能为0,这种情况可以不考虑
                        if (num[i] > 0)
				break;

			int tempSum = -num[i];
			int p1 = i + 1;
			int p2 = num.length - 1;
			while (p1 < p2) {
				int temp1 = num[p1];
				int temp2 = num[p2];
				if (temp1 + temp2 == tempSum) {
					List<Integer> tempList = new ArrayList<Integer>();
					tempList.add(-tempSum);
					tempList.add(temp1);
					tempList.add(temp2);
					Collections.sort(tempList);
					if (!result.contains(tempList)) {
						result.add(tempList);
					}
					p1++;
				} else if (temp1 + temp2 > tempSum) {
					p2--;
                                        //优化三:判断第三个数字是否和上一次的第三个数字重复,防止重复计算
					while (num[p2] == num[p2 + 1] && p2 > p1)
						p2--; 
				} else {
					p1++;
                                        //优化三:判断第二个数字是否和上一次的第二个数字重复,防止重复计算
					while (num[p1] == num[p1 - 1] && p2 > p1)
						p1++; 
				}
			}
		}
		return result;
	}

3 Sum  Closet题目:

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).

解析:已知一组数组,找到三个整数的和与目标值target最为接近,并且每个输入只有一个输出。该题的解决方法和3Sum类似,也是先做个快速排序,时间复杂度为O(logN)。循环取出数字num[i]后,针对下标为i~n-1的数字,采取2Sum的方法二做两个指针的移动,总时间复杂度是O(N^2)。不同的是,为了找出最接近target的结果,该题可以定义一个变量mindis,这个变量用于更新当前三个值的和与target的差值,如果当前三个值的和与target的差值等于mindis,当前三个值即所求结果。如果当前三个值的和与target的差值小于mindis,说明当前三个值的和是最优解(最接近target),更新mindis。无论当前三个值的和与target的差值是大于mindis还是小于mindis,都要移动三个指针来更新这三个值的和。Java AC代码如下:

	public int threeSumClosest(int[] num, int target) {
		int result = num[0] + num[1] + num[2];
		int mindis = Math.abs(result - target);
		Arrays.sort(num);
		for (int i = 0; i < num.length; i++) {
			if (i > 0 && num[i] == num[i - 1])
				continue;
			if (i > 0 && num[i - 1] > target && num[i] > target)
				break;
			int p1 = i + 1;
			int p2 = num.length - 1;
			while (p1 < p2) {
				int tempSum = num[p1] + num[p2] + num[i];
				if (Math.abs(tempSum - target) < mindis) {
					result = tempSum;
					mindis = Math.abs(tempSum - target);
				}
				if (tempSum < target) {
					p1++;
					while (num[p1] == num[p1 - 1] && p1 < p2)
						p1++;
				} else if (tempSum > target) {
					p2--;
					while (num[p2] == num[p2 + 1] && p1 < p2)
						p2--;
				} else {
					return result;
				}
			}
		}
		return result;
	}

4 Sum题目:

Given an array S of n integers, are there elements abc, 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:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • 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)


解析:leetcode中的X Sum系列最后一题4 Sum,我的解法比较暴力,将第一个数和第二个数通过迭代取出,第三个数和第四个数做两个指针,时间复杂度O(N^3)。按照这种做法可以实现5 Sum,6 Sum,但是时间复杂度也很高,如果找到更好的方法再进行更新记录吧。Java AC代码如下:

	public List<List<Integer>> fourSum(int[] num, int target) {
		Arrays.sort(num);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for (int i = 0; i < num.length - 3; i++) {
			if (i > 0 && num[i] == num[i - 1])
				continue;
			for (int j = i + 1; j < num.length - 2; j++) {
				if (j > i + 1 && num[j] == num[j - 1])
					continue;
				int p1 = j + 1;
				int p2 = num.length - 1;
				while (p1 < p2) {
					int tempSum = num[i] + num[j] + num[p1] + num[p2];
					if (tempSum < target) {
						p1++;
						while (p1 < p2 && num[p1] == num[p1 - 1])
							p1++;
					} else if (tempSum > target) {
						p2--;
						while (p1 < p2 && num[p2] == num[p2 + 1])
							p2--;
					} else {
						List<Integer> tempList = new ArrayList<Integer>();
						tempList.add(num[i]);
						tempList.add(num[j]);
						tempList.add(num[p1]);
						tempList.add(num[p2]);
						result.add(tempList);
						p1++;
						while (p1 < p2 && num[p1] == num[p1 - 1])
							p1++;
					}
				}
			}
		}
		return result;
	}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值