首先是参考思路:
解法1
解题步骤:
1. 对数组S进行归并排序。
2. 构造数组S’={z : z=x-y, y∈S},并排序。由于S已经有序,构造与排序可一并完成。
3. 删除S中重复的元素使仅保留一个,对S’进行同样的操作。
4. 合并S和S’,并保证合并后有序,这里可以使用归并排序的思想。
5. 如果在合并后的数组中存在连续两个相同的元素,并且这种元素的个数大于1,那么有解。
设想在合并后的数组中存在连续两个w,则w分别属于S和S’,那么S中存在y使得w=x-y,即x=y+w。因此,S中元素w和y的和为x。
步骤1的运行时间为Θ(n lg n),其余步骤运行时间为Θ(n),因此总的时间代价为Θ(n lg n)。
解法2:
对S排个序O(nlgn),然后用两个指针p1,p2分别指向头尾,
if(p1+p2 == x)
return true;
else if(p1 + p2 > x)
p2--;
else
p1++;
直到2指针相遇,如果没有找到,返回false
解法3
如果x不大的话.
申请x大小的数组byte t[x],memset 0.
遍历下集合S,对于小于x的数i将t[i]=1; 这是0(N);
然后对数组t[x]遍历. 循环查找i对应的t[x-i]是否为1. 这是O(X)
相比较三种解题思路,首先第三种局限较大,没有前两种实现实用。第二种实现指针的方式一般适用于C/C++解题。第一种是一个很好的想法,所以我实现了第一种的java解法。下面是实现代码
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public class TestSet {
public static void main(String[] args) {
int X = 30; //给定整数
int[] S = {2,9,7,11,45,13,18,16,20,22,25,26,27,30}; // 原始集合
Arrays.sort(S); //数组排序
int length = S.length;
int[] S1 = new int[length];
for (int i = 0 ; i < S.length; i++) {
S1[i] = X - S[i];
}
System.out.println(Arrays.toString(S));
Arrays.sort(S1);
System.out.println(Arrays.toString(S1));
int[] SS = delNum(S); //数组去重
int[] SS1 = delNum(S1);
int[] Test = new int[SS.length + SS1.length]; //结果数组
System.arraycopy(SS,0,Test,0,SS.length);
System.arraycopy(SS1,0,Test,SS.length,SS1.length);
Arrays.sort(Test);
System.out.println(Arrays.toString(Test));
int result = 0 ;
for(int i = 0 ;i< Test.length-1; i++){
if(Test[i] == Test[i+1]){
result ++;
}
}
if(result == 0){
System.out.println(" false" );
}else{
System.out.println(" ture " + result);
}
}
private static int[] delNum(int[] s) {
Set set = new TreeSet(); //Set 集合实现去重。
for (int i : s) {
set.add(i);
}
int j = 0;
int[] SS = new int[set.size()];
for (Integer i : set) {
SS[j++] = i;
}
System.out.println(Arrays.toString(SS));
return SS;
}
}