「算法导论」:课后习题2.3-7求集合S中是否有两个元素的和为X

        本题要求时间复杂度控制在o(nlgn),有两种想法:

        1、先采取归并排序法排序,复杂度o(nlgn),然后再对x中出现的每一个元素list[i]在list中用二分查找x-list[i],由于二分查找复杂度为o(lgn),所以此操作复杂度为o(nlgn),符合要求,为了防止出现2list[i] = x这种情况加了排除找到位置和自身相等的情况。

        代码如下:

/*************************************************************************
	> File Name: binary_sum_x.cpp
	> Author sangoly
	> Mail: sangoly@aliyun.com 
	> Created Time: 2014年07月01日 星期二 19时00分28秒
 ************************************************************************/

#include<iostream>
#include<limits>
using namespace std;

void merge(int list[], int start, int middle, int end) {
	int llen = middle - start + 1;
	int rlen = end - middle;

	int* larr = new int[llen + 1];
	int* rarr = new int[rlen + 1];

	int i, j;
	for (i = 0; i < llen; i++) {
		larr[i] = list[start + i];
	}
	for (j = 0; j < rlen; j++) {
		rarr[j] = list[middle + 1 + j];
	}
	// Add the guard
	larr[llen] = numeric_limits<int>::max();
	rarr[rlen] = numeric_limits<int>::max();

	i = j = 0;
	for (int k = start; k <= end; k++) {
		if (larr[i] <= rarr[j])
			list[k] = larr[i++];
		else
			list[k] = rarr[j++];
	}
	delete [] larr;
	delete [] rarr;
}

void merge_sort(int list[], int start, int end) {
	if (start >= end)
		return;
	int middle = (start + end) / 2;
	merge_sort(list, start, middle);
	merge_sort(list, middle + 1, end);
	merge(list, start, middle, end);
}

int binary_search(int list[], int start, int end, int target) {
	if (start > end)
		return -1;
	int middle = (start + end) / 2;
	if (list[middle] == target)
		return middle;
	else if (list[middle] > target)
		return binary_search(list, start, middle - 1, target);
	else
		return binary_search(list, middle + 1, end, target);
}


int main() {
	bool find_it = false;
	int* list = new int[15]{10, 4, 3, 5, 20, 36, 7, 8, 14, 6, 9, 12, 43, 56, 2};
	merge_sort(list, 0, 14);
	int x = 92;
	for (int i = 0; i < 15; i++) {
		int target = list[i];
		int index = binary_search(list, 0, 14, x - target);
		if (index > 0 && index != i) {
			find_it = true;
			break;
		}
	}
	if (find_it)
		cout<<"Find it"<<endl;
	else
		cout<<"Did't find"<<endl;
	delete [] list;
	return 0;
}
        下面再写一个利用c++标准库的版本

/*************************************************************************
	> File Name: std_sum_x.cpp
	> Author sangoly
	> Mail: sangoly@aliyun.com 
	> Created Time: 2014年07月01日 星期二 19时30分24秒
 ************************************************************************/

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

bool find_x(vector<int> &ivec, int x) {
	sort(ivec.begin(), ivec.end());
	for (vector<int>::iterator ct = ivec.begin(); ct != ivec.end(); ct++) {
		int target = x - *ct;
		vector<int>::iterator rt = find(ivec.begin(), ivec.end(), target);
		if (rt != ivec.end())
			return true;
	}
	cout<<endl;
	return false;
}

int main() {
	int element[] = {10, 4, 3, 5, 20, 36, 7, 8, 14, 6, 9, 12, 43, 56, 2};
	size_t count = sizeof(element) / sizeof(int);
	vector<int> ivec(element, element + count);
	if (find_x(ivec, 11))
		cout<<"Find it"<<endl;
	else
		cout<<"Did't find it"<<endl;
	return 0;
}
        第二种,先用归并法进行排序(o(nlgn)),然后从两侧向中间搜寻(o(n)),总体复杂度为o(nlgn)。代码如下

/*************************************************************************
	> File Name: linear_sum_x.cpp
	> Author sangoly
	> Mail: sangoly@aliyun.com 
	> Created Time: 2014年07月01日 星期二 20时01分19秒
 ************************************************************************/

#include<iostream>
#include<limits>
using namespace std;

void merge(int list[], int start, int middle, int end) {
	int llen = middle - start + 1;
	int rlen = end - middle;

	int* larr = new int[llen + 1];
	int* rarr = new int[rlen + 1];

	int i, j;
	for (i = 0; i < llen; i++) {
		larr[i] = list[start + i];
	}
	for (j = 0; j < rlen; j++) {
		rarr[j] = list[middle + 1 + j];
	}
	// Add the guard
	larr[llen] = numeric_limits<int>::max();
	rarr[rlen] = numeric_limits<int>::max();

	i = j = 0;
	for (int k = start; k <= end; k++) {
		if (larr[i] <= rarr[j])
			list[k] = larr[i++];
		else
			list[k] = rarr[j++];
	}
	delete [] larr;
	delete [] rarr;
}

void merge_sort(int list[], int start, int end) {
	if (start >= end)
		return;
	int middle = (start + end) / 2;
	merge_sort(list, start, middle);
	merge_sort(list, middle + 1, end);
	merge(list, start, middle, end);
}

bool linear_search(int list[], int len, int target) {
	int start = 0, end = len - 1;
	merge_sort(list, start, end);
	while (start < end) {
		int tmp_sum = list[start] + list[end];
		if (tmp_sum == target)
			return true;
		if (tmp_sum > target)
			end--;
		else
			start++;
	}
	return false;
}

int main() {
	int list[] = {10, 4, 3, 5, 20, 36, 7, 8, 14, 6, 9, 12, 43, 56, 2};
	size_t count = sizeof(list) / sizeof(int);
	if (linear_search(list, count, 21))
		cout<<"Find it"<<endl;
	else
		cout<<"Did't find it"<<endl;
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值