两个有序数组元素之和的最小K个值

这是在http://blog.csdn.net/insistgogo/article/details/12187329里面看到的一道题,自己拿来做一做。只做加法的部分吧。

我想到的一个思路就是对于

1,3,5,7,9

2,4,6,8,10

这两个序列,肯定是1+2是最小的,然后1+4<3+4,2+3<3+4,所以可以按照归并的思想从小到大把所有的结果都存储在一个数组中。

这个方法虽然时间复杂度低,但是需要的额外空间也不少,而且编起来也很麻烦。


对于求前k个最小值,自然是使用最大堆了。那到底有没有必要使用暴力解法呢?实际上对每个数字之和,还是要遍历一遍的,比如

1,2,3,4,5,6,7

10,10,10,10,10,10

就必须要全部遍历一遍,所以不能求出n^2 >= k的下标就了事。


但是题目本身来说还是可以进行优化的,因为是有序数组,所以左边的数相加肯定比右边的数相加要小。所以如果A的元素乘以B的元素比最大堆中的数还要大,那么可以肯定A以后的元素和B以后的元素相加肯定是要比最大堆中的数要大了,所以这个时候就可以退出了。


具体代码:

#ifndef _KTH_SAMLLEST_H_ 
#define _KTH_SAMLLEST_H_

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

vector<int> A;
vector<int> B;
typedef struct containter
{
	int a;
	int b;
	int res;
	containter(int a_, int b_)
		: a(a_), b(b_), res(a_+b_){}

	const bool operator<(const containter& rhs) const
	{
		return this->res < rhs.res;
	}

}container_t;
vector<container_t> heap;

const size_t K = 10;

//插入到最大堆中
const bool insert_heap(int a, int b)
{
	container_t c(a, b);
	if (! (c < heap[0]) )
	{//
		return false;
	}

	size_t hole = 0;
	for (size_t child; child = hole*2+1, child < heap.size(); hole = child)
	{//
		if (child + 1 < heap.size() && heap[child] < heap[child+1])
		{//
			child++;
		}
		if (heap[child] < c)
		{//
			break;
		}
		heap[hole] = heap[child];
	}

	heap[hole] = c;

	return true;
}

void solution()
{
	heap.reserve(K);
	for (size_t i = 0; i < K; i++)
	{//
		container_t c(1000,1000);
		heap.push_back(c);
	}
	
	size_t k = 0;
	size_t ptrA = 0, ptrB = 0, ptr;
	int mul;
	vector<int>& rep = A;
	while (true)
	{//
		if (A[ptrA] > B[ptrB])
		{//
			mul = A[ptrA++];
			rep = B;
			ptr = ptrB;
		}
		else
		{
			mul = B[ptrB++];
			rep = A;
			ptr = ptrA;
		}

		//剪枝
		int first = mul*rep[ptr];
		if (heap[0].res < first)
		{//结束
			return;
		}

		for (; ptr < rep.size(); ptr++)
		{//
			if (!insert_heap(mul, rep[ptr]))
			{//剪枝
				break;
			}
		}
	}
}

void print_()
{
	for (size_t i = heap.size()-1; i != 0; i--)
	{//
		swap(heap[0], heap[i]);

		size_t hole = 0;
		container_t tmp = heap[0];
		for (size_t child; child = hole*2+1, child < i; hole = child)
		{//
			if (child + 1 < heap.size() && heap[child] < heap[child+1])
			{//
				child++;
			}
			if (heap[child] < tmp)
			{//
				break;
			}
			heap[hole] = heap[child];
		}
		heap[hole] = tmp;
	}

	for (size_t i = 0; i < heap.size(); i++)
	{//
		cout << heap[i].a << " + " << heap[i].b << " = " << heap[i].res << endl;
	}
}

void tester()
{

	for (int i = 1; i < 10; i += 2)
	{//
		A.push_back(i);
	}
	for (int i = 2; i <= 10; i += 2)
	{//
		B.push_back(i);
	}

	solution();

	print_();
}

#endif



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值