Lintcode: 两数之和two sum, 三数之和 three sum, 最接近的三数之和, 四数之和

1. 两数之和

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 :

1
2
3
4
> Given nums = [2, 7, 11, 15], target = 9,
> Because nums[0] + nums[1] = 2 + 7 = 9,
> return [0, 1].
>

思路:

首先,这一题有如下要求:

  1. 得到的index要是有序的
  2. 假设只有一组解满足要求,大大降低了难度
  3. 相同的元素是不可以用两次的。(ps:一开始我是没有注意到这点的,结果有个测试用例【5 5 7 8】,导致没有通过)

其实最简单的就是通过一个二层循环来解决,但这肯定不是最优解,

所以我们可以考虑用HashMap来存储这些元素,如键:nums中的元素,值为元素的index。之后用一次循环来解决这个问题

代码:

import java.util.Map;
import java.util.HashMap;

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] temp = new int[2];
        HashMap<Integer,Integer> hs = new HashMap<Integer,Integer>();
        for(int i=0;i<numbers.length;i++){
            if(hs.containsKey(target-numbers[i])){
                temp[1] = i;   //之前存进去的值肯定是index较小的,所以放在第一位
                temp[0] = hs.get(target-numbers[i]);
                return temp;
            }
            hs.put(numbers[i],i);
        }
       return temp;
    }
    
}

从三数之和开始,我采用的方法并不是最优解,下面这个链接中的解法认为是比较好的:

https://blog.csdn.net/zkyzq/article/details/78038631

2.三数之和

给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。

在三元组(a, b, c),要求a <= b <= c。

结果不能包含重复的三元组。

样例

如S = {-1 0 1 2 -1 -4}, 你需要返回的三元组集合的是:

(-1, 0, 1)

(-1, -1, 2)

思路: 我是利用回溯,一个个地去探查的,时间复杂度有点高。 

           时间复杂度低地讲解: 

    public static List<List<Integer>> res = new ArrayList<>();
    public static List<List<Integer>> threeSum(int[] numbers) {
        // write your code here

        List<Integer> list = new ArrayList<>();
        int sum = 0;
        backtracing(numbers, 0, list, sum);
        return res;
    }

    public static void backtracing(int[] nums, int start, List<Integer> list, int sum){
        if(list.size()==3){
            if(sum==0){
                ArrayList<Integer> temp = new ArrayList<>(list); // zhuyi
                Collections.sort(temp);
                if(!res.contains(temp)){
                    res.add(temp);
                }
            }
            return;
        }
        for (int i = start; i < nums.length; i++) {
            list.add(nums[i]);
            backtracing(nums, i+1, list, sum+nums[i]);
            list.remove(list.size()-1);
        }
    }

3.最接近的三数之和

给一个包含 n 个整数的数组 S, 找到和与给定整数 target 最接近的三元组,返回这三个数的和。

只需要返回三元组之和,无需返回三元组本身
样例

例如 S = [-1, 2, 1, -4] and target = 1. 和最接近 1 的三元组是 -1 + 2 + 1 = 2.

思路:跟上面一样,采用的是回溯遍历,只是判断条件改了

代码:

    public static int flag = Integer.MAX_VALUE;
    public static int res = Integer.MAX_VALUE;
    public static int threeSumClosest(int[] numbers, int target) {
        // write your code here
        List<Integer> list = new ArrayList<>();
        int sum = 0;
        backtracing(numbers, 0, list, 0, target);
        return res;
    }

    public static void backtracing(int[] nums, int start, List<Integer> list, int sum, int target){
        if(list.size()==3){
            if(Math.abs(sum-target)<flag){
                flag = Math.abs(sum-target);
                res = sum;
            }
            return;
        }
        for (int i = start; i < nums.length; i++) {
            list.add(nums[i]);
            backtracing(nums, i+1, list, sum+nums[i], target);
            list.remove(list.size()-1);
        }
    }

3.四数之和

给一个包含n个数的整数数组S,在S中找到所有使得和为给定整数target的四元组(a, b, c, d)。

四元组(a, b, c, d)中,需要满足a <= b <= c <= d

答案中不可以包含重复的四元组。

样例

例如,对于给定的整数数组S=[1, 0, -1, 0, -2, 2] 和 target=0. 满足要求的四元组集合为:

(-1, 0, 0, 1)

(-2, -1, 1, 2)

(-2, 0, 0, 2)

思路:一开始采用了上述的回溯遍历,但是时间超了,下面是比较好的解:

代码:

    public List<List<Integer>> fourSum(int[] num, int target) {
		List<List<Integer>> rst = new ArrayList<List<Integer>>();
		Arrays.sort(num);

		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 left = j + 1;
				int right = num.length - 1;
				while (left < right) {
					int sum = num[i] + num[j] + num[left] + num[right];
					if (sum < target) {
						left++;
					} else if (sum > target) {
						right--;
					} else {
						ArrayList<Integer> tmp = new ArrayList<Integer>();
						tmp.add(num[i]);
						tmp.add(num[j]);
						tmp.add(num[left]);
						tmp.add(num[right]);
						rst.add(tmp);
						left++;
						right--;
						while (left < right && num[left] == num[left - 1]) {
							left++;
						}
						while (left < right && num[right] == num[right + 1]) {
							right--;
						}
					}
				}
			}
		}

		return rst;
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值