第15题
从时间复杂度上看,和双指针相同,甚至高于双指针,但是计算时间上快了很多。。。
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++)
{
if (i ==0 || nums[i] != nums[i-1]) // 保证前后两次循环的数字不同
{
int k = nums.length - 1;
for (int j = i+1; j < nums.length-1; j++) // 第三个数字是k表示的
{
if (j == i+1 || nums[j] != nums[j-1]) // 保证前后两次循环的数字不同
{
while (k > j && nums[i] + nums[j] + nums[k] > 0) // 第三个数字和第二个数字不能相等
{
k--; // 第三个数字向左移动,和变小
}
if (nums[i] + nums[j] + nums[k] == 0)
{
List<Integer> l = Arrays.asList(i, j, k);
ret.add(l);
}
}
}
}
}
return ret;
}
第15题,使用双指针,时间复杂度为O(n2)
public static List<List<Integer>> threeSum2(int[] nums) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
Set<List<Integer>> set = new HashSet<List<Integer>>();
Arrays.sort(nums);
for (int i = 0; i < nums.length-2; i++)
{
int j = i+1;
int k = nums.length-1;
int sum;
while (j < k)
{
sum = nums[i] + nums[j] + nums[k];
if (sum < 0)
j++;
else if (sum > 0)
k--;
else
{
List<Integer> l = Arrays.asList(nums[i], nums[j], nums[k]);
set.add(l); // 有重复的问题
j++;
k--;
}
}
}
ret.addAll(set);
return ret;
}
第16题
public static int threeSumClosest(int[] nums, int target) {
int ret = 0;
int[] pos = new int[3];
int d = Integer.MAX_VALUE; // 目的是使得d逐渐减小,全局的最小
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++)
{
if (i == 0 || nums[i] != nums[i-1])
{
for (int j = i+1; j < nums.length-1; j++)
{
if (j == i+1 || nums[j] != nums[j-1])
{
int n = target - nums[i] - nums[j];
int k = nums.length-1;
int dd = Integer.MAX_VALUE;
while (k > j)
{
if (Math.abs(nums[k] - n) <= dd) // dd 是指当前的距离,而不是全局的距离
{
dd = Math.abs(nums[k] - n);
if (dd <= d)
{
d = dd;
pos[0] = i;
pos[1] = j;
pos[2] = k;
}
}
else // 差距更大了,就可以退出了
break; // 一旦差距变大,后面数字的差距也会越来越大
k--;
}
}
}
}
}
ret = nums[pos[0]] + nums[pos[1]] + nums[pos[2]];
return ret;
}
第16题,使用双指针,时间复杂度为O(n2)
public static int threeSumClosest(int[] nums, int target) {
int ret = 0;
Arrays.sort(nums);
int[] pos = new int[3];
int dist = Integer.MAX_VALUE;
for (int i = 0; i < nums.length-2; i++)
{
int j = i+1;
int k = nums.length-1;
// 以距离更近更远为标准判断如何移动左右指针。
int sum;
while (j < k)
{
sum = nums[i] + nums[j] + nums[k];
if (sum < target) // 判断向哪个方向移动
{
if (target - sum < dist) // 判断何时更新
{
dist = target - sum; // 更新部分,可以写成一个update();
pos[0] = i;
pos[1] = j;
pos[2] = k;
}
j++;
}
else if (sum > target)
{
if (sum - target < dist)
{
dist = sum - target; // 更新部分,可以写成一个update();
pos[0] = i;
pos[1] = j;
pos[2] = k;
}
k--;
}
else // sum == target
return nums[i] + nums[j] + nums[k];
}
}
ret = nums[pos[0]] + nums[pos[1]] + nums[pos[2]];
return ret;
}
第18题
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++)
{
if (i == 0 || nums[i] != nums[i-1])
{
for (int j = i+1; j < nums.length-2; j++)
{
if (j == i+1 || nums[j] != nums[j-1])
{
for (int k = j+1; k < nums.length-1; k++)
{
int l = nums.length-1;
while (l > k && nums[i] + nums[j] + nums[k] + nums[l] > target)
l--;
if (l > k && nums[i] + nums[j] + nums[k] + nums[l] == target)
{
List<Integer> ll = Arrays.asList(nums[i], nums[j], nums[k], nums[l]);
ret.add(ll);
}
}
}
}
}
}
return ret;
}