题目
快速找出一个包含
分析1
如果直接遍历穷举将会得到
另外一个思路同样是将数组排序,接着设置两个指针
能否让时间复杂度进一步减小呢?利用哈希往往能用空间换取时间。不用排序,将所有整数放入哈希表中,对于每一个元素
代码1
import java.util.*;
public class Sum2 {
static void sum2bs(int[] array, int sum) {
Arrays.sort(array);
int n = array.length;
int remain, pos;
for (int i = 0; i < n; i++) {
remain = sum - array[i];
pos = binarySearch(array, remain, i);// 如果一个数只使用一次则左边界为i+1
if (pos != -1)
System.out.println(array[i] + " " + remain);
}
}
// 数组从左向右遍历,设置查找的左边界就可以避免重复组合
static int binarySearch(int[] array, int target, int left) {
int i = left, j = array.length - 1;
int mid;
while (i <= j) {
mid = i + (j - i) / 2;
if (array[mid] == target) {
return mid;
} else if (array[mid] < target) {
i = mid + 1;
} else {
j = mid - 1;
}
}
return -1;
}
static void sum2bt(int[] array, int sum) {
Arrays.sort(array);
int n = array.length;
int i = 0, j = n - 1;
while (i <= j) {// 如果一个数只使用一次则i<j
if (array[i] + array[j] == sum) {
System.out.println(array[i] + " " + array[j]);
i++;
j--;
} else if (array[i] + array[j] < sum) {
i++;
} else {
j--;
}
}
}
static void sum2hash(int[] array, int sum) {
int n = array.length;
Set<Integer> set = new HashSet<>();
for (int i = 0; i < n; i++) {
set.add(array[i]);
}
int remain;
for (int i = 0; i < n; i++) {
remain = sum - array[i];
if (set.contains(remain))
System.out.println(array[i] + " " + remain);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int sum = sc.nextInt();
int n = sc.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
sum2bs(array, sum);
}
}
扩展
将找出所有两个数的组合改为找出所有三个数的组合,其余不变。
分析2
找三个数可以使用同样的思路,但是使用二分查找和双指针遍历就会有不同的复杂度。考虑到
代码2
import java.util.*;
public class Sum3 {
static void sum3bs(int[] array, int sum) {
Arrays.sort(array);
int n = array.length;
int remain1, remain2, pos;
for (int i = 0; i < n; i++) {
remain2 = sum - array[i];
for (int j = i; j < n; j++) {
remain1 = remain2 - array[j];
pos = binarySearch(array, remain1, j);// 如果一个数只使用一次则左边界为j+1
if (pos != -1)
System.out.println(array[i] + " " + array[j] + " " + remain1);
}
}
}
// 数组从左向右遍历,设置查找的左边界就可以避免重复组合
static int binarySearch(int[] array, int target, int left) {
int i = left, j = array.length - 1;
int mid;
while (i <= j) {
mid = i + (j - i) / 2;
if (array[mid] == target) {
return mid;
} else if (array[mid] < target) {
i = mid + 1;
} else {
j = mid - 1;
}
}
return -1;
}
static void sum3bt(int[] array, int sum) {
Arrays.sort(array);
int n = array.length;
int remain2, j, k;
for (int i = 0; i < n; i++) {
remain2 = sum - array[i];
j = i;// 如果一个数只使用一次则j=i+1
k = n - 1;
while (j <= k) {// 如果一个数只使用一次则条件为j<k
if (array[j] + array[k] == remain2) {
System.out.println(array[i] + " " + array[j] + " " + array[k]);
j++;
k--;
} else if (array[j] + array[k] < remain2) {
j++;
} else {
k--;
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int sum = sc.nextInt();
int n = sc.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
sum3bs(array, sum);
}
}