leetcode(http://leetcode.com/onlinejudge)上有好几道关于数组中几个数据和为target的题目。恰好正在看剑指offer中“和为s的两个数组这章”,据此思想,leetcode上的三道题目都被我解决了。总结一下。
1.twoSum:输入一个递增数组和一个数字s,在数组中查找两个数使得它们的和正好是s。
既然题目中已经提到了“递增数组”,那么肯定不会暴力了。因此肯定有<O(n*n)的办法了。
算法:最初我们找到数组的第一个数字和最后一个数字。当两个数字的和大于输入的数字时,把较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。
链接:http://zhedahht.blog.163.com/blog/static/2541117420072143251809/
2.threeSum: 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:
- 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.
首先是求解:因为要求3个数,如果我们固定其中1个数,再用求“和为某值的2个数的组合”的解法,就能把剩下的2个数求出来。因
此,先对数组进行非递减排序,这样整个数组的数就由小到大排列。i 的取值由 0 至 n-1,对每一个i,我们求当num[i]是解当中的其
中一个数时,其他的2个数。设有指针p指向数组头(实际只要p从i+1开始),q指向数组尾,sum = num[i] + num[p]+ num[q],因为num[i]
是一定在解中的,所以如果sum < 0,因为num[q]已经不能增大,所以说明num[p]太小了,这时p需要向后移动,找一个更大的数。
同理,sum > 0,说明num[q]太大了,需要q向前移动。当sum == 0时,说明找到了一个解。但找到了一个解,并不说明解中有num[i]的
所有解都找到了,因此p或q还需要继续移动寻找其他的解,直到p == q为止。
上面是求解的过程,那么去重怎么做?去重就在于和之前的解进行比较,但我们不需要比较所有的解,这里有一个技巧。
1. 如果num[i] = num[i - 1],说明刚才i-1时求的解在这次肯定也会求出一样的,所以直接跳过不求;
2. 其实指针p不需要从数组头开始,因为如果num[i]所在的解中如果有i之前的数,设其位置为j,那么我们求num[j]时,肯定把num[i]
也找出来放到和num[j]一起的解里了,所以指针p其实应该从i+1开始,即初始时p = i + 1, q = num.size() - 1;
3. 当sum == 0,我们保存了当前解以后,需要num[i]在解中的其他的2个数组合,这个时候,肯定是p往后或者q往前,如果++p,发
现其实num[p] == num[p-1],说明这个解肯定和刚才重复了,再继续++p。同理,如果--q后发现num[q] == num[q+1],继续--q。
这个去重操作主要针对这种有多个同值的数组,如:-3, 1,1,1, 2,2,3,4。
- import java.util.ArrayList;
- import java.util.Arrays;
- public class ThreeSumSolution2 {
- private ArrayList<ArrayList<Integer>> list;
- public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
- list = new ArrayList<ArrayList<Integer>>();
- Arrays.sort(num);
- int i = 0;
- for (i = 0; i <= num.length - 3; i++) {
- if (i != 0 && num[i] == num[i - 1]) {
- continue;
- }
- judgeAndPut(num, i, i + 1, num.length - 1);
- }
- return list;
- }
- private void judgeAndPut(int[] num, int i, int p, int q) {
- while (p < q) {
- if (num[p] + num[q] < -num[i]) {
- p++;
- } else if (num[p] + num[q] > -num[i]){
- q--;
- } else if (num[p] + num[q] == -num[i]) {
- ArrayList<Integer> tmpList = new ArrayList<Integer>();
- tmpList.add(num[i]);
- tmpList.add(num[p]);
- tmpList.add(num[q]);
- list.add(tmpList);
- p++;
- q--;
- while (p < q && num[p] == num[p - 1]) {
- p++;
- }
- while (p < q && num[q] == num[q + 1]) {
- q--;
- }
- }
- }
- }
- public static void main(String[] args) {
- int num[] = {-1,0,1,2,-1,-4};
- System.out.println(new ThreeSumSolution2().threeSum(num));
- }
- }
- import java.util.Arrays;
- public class ThreeSumClosest {
- private int closest;
- private boolean needInit;
- public int threeSumClosest(int[] num, int target) {
- closest = 0;
- needInit = true;
- Arrays.sort(num);
- int i = 0;
- for (i = 0; i <= num.length - 3; i++) {
- if (i != 0 && num[i] == num[i - 1]) {
- continue;
- }
- judgeAndPut(num, i, i + 1, num.length - 1, target);
- }
- return closest;
- }
- private void judgeAndPut(int[] num, int i, int p, int q, int target) {
- while (p < q) {
- int sum = num[i] + num[p] + num[q];
- if (needInit || Math.abs(sum - target) < Math.abs(closest - target)) {
- closest = sum;
- }
- needInit = false;
- if (sum <= target) {
- p++;
- while (p < q && num[p] == num[p - 1]) {
- p++;
- }
- } else if (sum > target){
- q--;
- while (p < q && num[q] == num[q + 1]) {
- q--;
- }
- }
- }
- }
- public static void main(String[] args) {
- int num[] = {0,1,2};
- System.out.println(new ThreeSumClosest().threeSumClosest(num, 3));
- }
- }
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:
- 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.
- import java.util.ArrayList;
- import java.util.Arrays;
- public class FourSum {
- private ArrayList<ArrayList<Integer>> list;
- public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
- list = new ArrayList<ArrayList<Integer>>();
- Arrays.sort(num);
- int i = 0;
- int j = 0;
- for (i = 0; i <= num.length - 4; i++) {
- if (i != 0 && num[i] == num[i - 1]) {
- continue;
- }
- for (j = i + 1; j <= num.length - 3; j++) {
- if (j != i + 1 && num[j] == num[j - 1]) {
- continue;
- }
- judgeAndPut(num, i, j, j + 1, num.length - 1, target);
- }
- }
- return list;
- }
- private void judgeAndPut(int[] num, int i, int j, int p, int q, int target) {
- while (p < q) {
- int sum = num[i] + num[j] + num[p] + num[q];
- if (sum < target) {
- p++;
- } else if (sum > target){
- q--;
- } else if (sum == target) {
- ArrayList<Integer> tmpList = new ArrayList<Integer>();
- tmpList.add(num[i]);
- tmpList.add(num[j]);
- tmpList.add(num[p]);
- tmpList.add(num[q]);
- list.add(tmpList);
- p++;
- q--;
- while (p < q && num[p] == num[p - 1]) {
- p++;
- }
- while (p < q && num[q] == num[q + 1]) {
- q--;
- }
- }
- }
- }
- public static void main(String[] args) {
- int num[] = {-1,0,1,0,-2,2};
- System.out.println(new FourSum().fourSum(num, 0));
- }
- }