Algorithm之路十五:3Sum

来源:互联网 发布:长江大数据交易所 编辑:程序博客网 时间:2024/06/03 14:53

题目:

给出一个整形数组,在数组中找出一个三元组,这个三元组中的三个数之和为0,并将所有这样的三元组放入列表中返回出来。

举例:

For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

思路:

暴力搜索,来一个三层嵌套循环,就可以得出结果,这样做不仅时间复杂度高O(n^3),并且因为题目要计算的三元组的内容是数组中的项,而不是下标,所以直接暴力搜索时还要考虑三元组的查重问题。当然直接放弃这种做法。

那么如何才能降低时间复杂度呢?之前做过一道在数组中找和为定值的二元组的题目,那么这道题可能也可以通过hashmap和list完成,首先一个二层嵌套循环得到数组中任意两个数的和,并存入hashmap中,hashmap的数据结构是Map<Integer,List<List<Integer>>>,其中第一个整数是两个元素nums[i]和nums[j]的和,而List<List<Integer>>中存放的便是i,j这样的二元组。然后将数组从小到大排序后,在一次循环for(int i = 0; i< nums.length; i++){if( nums[i] > 0) break; while(nums[i] == nums[++i]);}判断nums[i] * (-1)是否在hashmap中,如果存在,则判断i是否i是否在二元组中已经存在,如果不存在,则继续判断下一个二元组,但是这样做的话,就要判断二元组的重复问题,比如hashmap中键值为0的二元组有[nums[0],nums[2]]和[nums[2],nums[4]]而这两个都是[-1,1],所以在这一步中就要加上去重工作,由于个人原因,写了好一会总出毛病,所以偷偷瞄了一眼大神的作品,果断放弃了这种想法,但是我要明确指出,我的这种想法是合理的,可以实现的,只是有可能出现Time Exceed这样的错误。

大神的思路:

将数组排序,从nums[0]开始,将其作为基数,设置头指针和尾指针,计算基数,头指针和尾指针三处的元素之和,根据和的大小,调整头指针和尾指针的位置,并在调整过程中完成去重工作。

代码:

import java.util.ArrayList;import java.util.Arrays;import java.util.List;public class _3Sum {public static List<List<Integer>> threeSum(int[] nums){List<List<Integer>> list = new ArrayList();int length = nums.length;if(length < 3)//数组的长度小于3,返回空列表return list;int i = 0;Arrays.sort(nums);//将数组从小到大排序while(i < length - 2)//将nums[i]作为基数{if(nums[i] > 0)//三个数的和为0,最小的数一定非正break;int j = i + 1;int k = length - 1;while(j < k){int count = nums[i] + nums[j] + nums[k];if(count == 0)list.add(Arrays.asList(nums[i],nums[j],nums[k]));if(count >= 0)//当前正数过大,减小kwhile(nums[k] == nums[--k] && j < k);//去除掉重复的nums[k]if(count <= 0)//当前负数过小,增大jwhile(nums[j++] == nums[j] && j < k);}while(nums[i] == nums[++i] && i < length - 2);}        return list;    }public static void main(String[] args){int[] S = {-1, 0, 1, 2, -1, -4};System.out.println(threeSum(S));}}

时间复杂度:

头指针和尾指针往中间靠近,二者之间的范围为n - i,所以对于每次基数的移动,头指针和尾指针要处理的元素个数为n - i,所以总共处理的三元组的个数为n - 1 + n - 2 + …… + 3 = (n(n - 1)/2) - 3,所以时间复杂度为O(n^2)。(这里没有考虑Arrays.sort的时间复杂度)

空间复杂度:

临时变量占用的空间为O(1),返回列表占用的空间由输入数组的解的个数决定。

原创粉丝点击