索引请参考:系列目录
题目:
- 输入一个递增排序的数字和一个数字S,使得他们的和正好是S。如果有多对数字的和等于S,输出2个乘积最小的。
- 示例:
- 输入: {1,2,3,3,4,5,6} 和 6
- 输出: {2,4}
分析:
思路1:
- 利用容器set或者map(multi)的成员函数
- (1)将数组放入set或者map(multi)中
- (2)遍历 + 判断
m_elem = s - array[i]
if(multimap::count(m_elem))
//放入数组中
- 如果结果数组中的个数大于1,找到2个数乘积最小的输出
思路2:
- 遍历 + 标准模板库中算法中的find()算法
思路3:双指针思想
- (1)在数组中选择两个数
- 和等于输入S ——>找到要找的两个数字
- 和小于S——>希望2个数字的和再大点。由于数组已经排序好了,可以考虑较小的数组后面的数字
- 和大于S——>选择较大数字前面的数字(具体请参考代码)
思路1:
std::vector<int> FindNumbersWithSum1(const std::vector<int> & array, int sum) {
std::multiset<int> coll;
for (auto elem : array)
coll.insert(elem);
std::vector<int>result;
for (auto elem : coll)
{
int m_elem = sum - elem;
if (coll.count(m_elem))
{
if (result.empty())
{
result.push_back(elem);
result.push_back(m_elem);
}
else if (result[0] * result[1] > elem * m_elem)
{
result.clear();
result.push_back(elem);
result.push_back(m_elem);
}
}
}
return result;
}
牛客运行结果:
思路2:
auto end = array.end();
std::vector<int>result;
for (auto elem : array)
{
auto pos = std::find(array.begin(), array.end(), sum - elem);
if (pos != end)
{
if (!result.empty())
{
int a = result[0];
int b = result[1];
if (a * b > *pos * elem)
{
result.clear();
result.push_back(elem);
result.push_back(*pos);
}
}
else
{
result.push_back(elem);
result.push_back(*pos);
}
}
}
return result;
牛客运行结果:
思路3:
if (array.empty())
return{};
int temp = INT_MAX;
std::pair<int, int>ret;
int i = 0, j = array.size();
while (i < j)
{
if (array[i] + array[j - 1] == sum)
{
if (array[i] * array[j - 1] < temp)
{
temp = array[i] * array[j - 1];
ret = { i , j - 1 };
}
i++;
j--;
}
else if (array[i] + array[j - 1] < sum)
++i;
else
--j;
}
if (ret.first == ret.second)
return{};
return std::vector<int>({ array[ret.first],array[ret.second] });
评注:理论上应该是双指针的形式时间复杂度更低一些,但是实际牛客测试结果是利用STL容器内部的成员函数运行时间更快。具体原理有待理解。。。