Lintcode:56 两数之和 VS 57 三数之和 VS 58 四数之和 VS 59 最接近的三数之和

题目:

分析:

解法一:暴力O(n^2)时间复杂度求解。

/**
 * 解法1:时间复杂度O(n^2),空间复杂度O(1)
 * 遍历求两数之和等于target,返回两数下标(从1开始)
 * http://www.lintcode.com/zh-cn/problem/two-sum/
 * @author yzwall
 */
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] results = new int[2];
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    results[0] = i + 1;
                    results[1] = j + 1;
                    return results;
                }
            }
        }
        return results;
    }
}

解法二:双指针O(nlog(n))时间复杂度求解

思路:首先保存数组排序前的元素位置,可以使用hashmap保存(空间复杂度为O(n)),然后将数组排序(时间复杂度为O(nlogn),然后通过双指针分别指向排序后的数组头和尾,两端同时遍历,如果两指针数组元素之和小于target,则头指针往后移,若之和大于target,则尾指针往前移,若之和正好等于target,则输出下标位置即可。注意,可能存在数组中有相同元素的情况,即对应于hashmap中同key值下有多value的情况,用list保存,故在取出时,应同时删除对应list中的记录。同时要保证第一个下标小于第二个下标。

复杂度分析:时间复杂度O(nlog(n)),空间复杂度O(n).

//解法一:双指针O(nlog(n))时间复杂度求解
    public int[] twoSum(int[] numbers, int target) {
        // write your code here
        if(numbers.length==0)   return null;
        int[] num=new int[2];
        //通过hashmap记录数组排序前的下标
        HashMap<Integer,ArrayList<Integer>> hashMap=new HashMap<>();
        for(int i=0;i<numbers.length;i++){
            if(hashMap.containsKey(numbers[i])){
                hashMap.get(numbers[i]).add(i);
            }else{
                hashMap.put(numbers[i],new ArrayList<>());
                hashMap.get(numbers[i]).add(i);
            }
        }
        Arrays.sort(numbers);  //排序
        int low=0;
        int high=numbers.length-1;
        while(low<high){
            int sum=numbers[low]+numbers[high];
            if(sum==target){
                int index1=hashMap.get(numbers[low]).get(0);
                //把上一步取出的值从hashmap中去掉,防止数组中存在相同元素的情况,这种情况下不去除掉就会取得同样的下标值
                hashMap.get(numbers[low]).remove(0);
                int index2=hashMap.get(numbers[high]).get(0);
                //保证index1<index2;
                num[0]=Math.min(index1,index2);
                num[1]=Math.max(index1,index2);
                return num;
            }else if(sum>target){
                high--;
            }else{
                low++;
            }
        }
        return num;
    }

解法三:HashMap的O(n)时间复杂度求解

思路:耗费O(n)空间构造哈希表,遍历数组每个元素nums[i],哈希表对应存储<target-nums[i],i>,存储nums[i]期望的另一半,一旦哈希表中包含nums[i],代表“另一半”已经存储在哈希表中,直接返回即可。

复杂度分析:时间复杂度O(n),空间复杂度O(n).

//解法二:HashMap O(n)时间复杂度求解
    public int[] twoSum1(int[] numbers, int target) {
        if(numbers.length==0)   return null;
        int[] num=new int[2];
        HashMap<Integer,Integer>  hashMap=new HashMap<>();
        for(int i=0;i<numbers.length;i++){
            if(hashMap.containsKey(numbers[i])){
                int index1=hashMap.get(numbers[i]);
                int index2=i;
                //保证index1<index2;
                num[0]=Math.min(index1,index2);
                num[1]=Math.max(index1,index2);
                return num;
            }else{
                hashMap.put(target-numbers[i],i);
            }
        }
        return num;
    }

题目:


分析:这题只需要返回三个整数即可,不需要返回下标,所以直接排序即可。整个题目的解题思路同二数之和差不多。通过控制一个指针i不变,其余两个指针分别指向j和r分别指向i+1和数组最后一个位置,也就是双指针的方法,target为0-指针i指向的值。算法如下:

public class threeSum {
    /**
     * @param numbers: Give an array numbers of n integer
     * @return: Find all unique triplets in the array which gives the sum of zero.
     */
    //三数之和
    //给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。
    public List<List<Integer>> threeSum(int[] numbers) {
        // write your code here
        List<List<Integer>> list=new ArrayList<>();
        if(numbers==null || numbers.length<3)  return list;
        Arrays.sort(numbers);
        for(int i=0;i<numbers.length;i++){
            //跳过与当前i元素相同的元素
            if(i>0 && numbers[i]==numbers[i-1])
                continue;
            int l=i+1;int r=numbers.length-1;  //类似于双指针
            int target=-numbers[i];
            twosum(numbers,l,r,target,list);
        }
        return list;
    }

    //求两数之和
    public void twosum(int[] numbers,int left,int right,int target,List<List<Integer>> lists){
        while(left<right){
            int sum=numbers[left]+numbers[right];
            if(sum==target){
                List<Integer> list=new ArrayList<>();
                list.add(-target);
                list.add(numbers[left]);
                list.add(numbers[right]);
                lists.add(list);
                left++;
                right--;
                //跳过与当前left元素相同的元素
                while(left<right && numbers[left]==numbers[left-1]){
                    left++;
                }
                while(left<right && numbers[right]==numbers[right+1]){
                    right--;
                }
            }else if(sum<target){
                left++;
            }else{
                right--;
            }
        }
    }

题目:


分析:和三数之和思想类似,只不过这次先固定两个指针,两个for循环确定首尾两个指针后,通过调整剩下两个指针来与target比较。

public class Solution {
    /**
     * @param numbers: Give an array
     * @param target: An integer
     * @return: Find all unique quadruplets in the array which gives the sum of zero
     */
    public List<List<Integer>> fourSum(int[] numbers, int target) {
        // write your code here
        List<List<Integer>> list=new ArrayList<>();
        if(numbers==null || numbers.length<3)  return list;
        Arrays.sort(numbers);
        for(int i=0;i<numbers.length;i++){
            //跳过与当前i元素相同的元素
            if(i>0 && numbers[i]==numbers[i-1])
                continue;
            for(int j=numbers.length-1;j>i;j--) {
                if(j<numbers.length-1 && numbers[j]==numbers[j+1])
                    continue;
                int l = i + 1;
                int r = j - 1;  //类似于双指针
                int subtarget = target-numbers[i]-numbers[j];
                twosum(numbers, l, r,i,j,subtarget, list);
            }
        }
        return list;
    }

    //求两数之和
    public void twosum(int[] numbers,int left,int right,int fixI,int fixJ,int target,List<List<Integer>> lists){
        while(left<right){
            int sum=numbers[left]+numbers[right];
            if(sum==target){
                List<Integer> list=new ArrayList<>();
                list.add(numbers[fixI]);
                list.add(numbers[left]);
                list.add(numbers[right]);
                list.add(numbers[fixJ]);
                lists.add(list);
                left++;
                right--;
                //跳过与当前left元素相同的元素
                while(left<right && numbers[left]==numbers[left-1]){
                    left++;
                }
                while(left<right && numbers[right]==numbers[right+1]){
                    right--;
                }
            }else if(sum<target){
                left++;
            }else{
                right--;
            }
        }
    }
}

题目:


分析:和三数之和思想类似,将数组排序后,通过固定一个元素,调整另外两个来得到三数之和。用一个变量存储当前找到的最接近target的三数之和。

public class Solution {
    /**
     * @param numbers: Give an array numbers of n integer
     * @param target: An integer
     * @return: return the sum of the three integers, the sum closest target.
     */
    public int threeSumClosest(int[] numbers, int target) {
        // write your code here
        if(numbers==null || numbers.length<3)   return -1;
        Arrays.sort(numbers);
        int min=Integer.MAX_VALUE;
        for(int i=0;i<numbers.length;i++){
            //跳过与当前元素相同的元素
            if(i>0 && numbers[i]==numbers[i-1]) continue;
            int l=i+1; int r=numbers.length-1;  //类似于双指针
            while(l<r){
                int sum=numbers[l]+numbers[r]+numbers[i];
                if(Math.abs(sum-target)<Math.abs(min-target))   min=sum;
                if(sum<target)  l++;
                else   r--;
            }
        }
        return min;
    }
}


猜你喜欢

转载自blog.csdn.net/qq_27139155/article/details/80003777
今日推荐