存在ai * aj = ak
来源:互联网 发布:休闲零食市场数据 编辑:程序博客网 时间:2024/06/11 18:42
给定一个正整数集合 s = {a1, a2, ..., an},
存在ai * aj = ak, i != j != k
试找出满足上述条件的最大数ak,如果不存在满足上述条件的三个数,则输出-1
回复人:xwzheng(蚩尤) ( ) 信誉:100 2007-7-27 16:25:39 得分:0 ? 存在ai * aj = ak, i != j != k
试找出满足上述条件的最大数ak,如果不存在满足上述条件的三个数,则输出-1
o(n3)肯定能解出
排序再穷举,
可以到O(N^2lgN);
肯定有复杂度比较低的解法,不然google不会拿出来的;
排序再做,是可以到O(N^2lgN)
不知道还有没有复杂度更低的方法
应该可以用数论的知识解决,实验室关门了,明天看。
O(N^2)
先从小到大排序
for(i=0;i<n;i++)
{
for(j=0,k=i;j<=i && k<n;)
{
if(a[i]*a[j]==a[k])return; //find
else if(a[i]*a[j]>k)k++;
else j++;
}
}
return -1;
修正下,前面没看到i != j != k
for(i=0;i<n;i++)
{
for(j=0,k=i+1;j<i && k<n;)
{
if(a[i]*a[j]==a[k]){
return; //find
}
else if(a[i]*a[j]>k)k++;
else j++;
}
}
return -1;
还有点小错,
for(i=0;i<n;i++)
{
for(j=0,k=i+1;j<i && k<n;)
{
if(a[i]*a[j]==a[k]){
return; //find
}
else if(a[i]*a[j]>a[k])k++;
else j++;
}
}
return -1;
int max=-1;
for(i=0;i<n;i++)
{
for(j=0,k=i+1;j<i && k<n;)
{
if(a[i]*a[j]==a[k]){
if(a[k]>max)max=a[k];
}
else if(a[i]*a[j]>a[k])k++;
else j++;
}
}
return max;
一转眼功夫,居然转移阵地了
先按递增排序,复杂度o(nlogn)
计算在已排好序的数组中的首元a[0]的平方,即a[0]*a[0]。用二分查找,找到在已排好序的数组中不小于a[0]*a[0]的最低位置big_pos,若big_pos==len,说明无解。
否则:
对区间[big_pos,len)的元素(len是数组的长度),从尾开始向前扫描。
对元素ak,计算它的取整平方根sak=int(sqrt(ak)),用二分查找,找到在已排好序的数组中大于sak的最低位置pos。
对已排好序的数组中区间[0,pos)内的元素ai,检查ak/ai是否为正整数,
a): 若不是,++i;
b): 若是,用二分查找确定区间[pos,k)是否存在值为ak/ai的数,若存在,结束;否则,++i。
根据medie2005(阿诺)的提示,写了以下程序,测了几组数据,还没有发现问题,正继续测试中
/**
* 正整数集合s = {a1, a2, ..., an}
* 存在 ai * aj = ak, i != j != k
* 求满足条件的最大整数k,如果不存在,则输出-1
*/
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int array[] = { 1, 2, 3, 6, 4, 7, 19, 20, 25 , 80};
/**
* 二分查找,找到集合中不大于x的最高位置或不低于x的最低位置
*/
template<class Type>
int BinarySearch(Type arr[], const Type& x, int n)
{
int left = 0;
int right = n - 1;
while(left <= right) {
int middle = (left + right) / 2;
if(x == arr[middle])
return middle;
if(x > arr[middle])
left = middle + 1;
else
right = middle - 1;
}
return left - 1;
}
/**
* 严格的二分查找
*/
template<class Type>
int BinarySearchAccurate(Type arr[], const Type& x, int low, int high)
{
int left = low;
int right = high - 1;
while(left <= right) {
int middle = (left + right) / 2;
if(x == arr[middle])
return middle;
if(x > arr[middle])
left = middle + 1;
else
right = middle - 1;
}
return -1;
}
//打印数组arr
template<class Type>
void PrintArray(Type arr[], int n)
{
int i;
for(i = 0; i < n; ++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
//计算n的平方
int ComputeSquare(int n)
{
return n * n;
}
//判断double是否为一个整数
bool IsInteger(double n)
{
if(n == (int)n)
return true;
return false;
}
//求解,array为待分析的数组,n为数组长度
//如果存在,则返回ak
//否则返回-1
int Compute(int array[], int n)
{
//首先计算a[0]的平方
int temp = ComputeSquare(array[0]);
int big_pos = BinarySearch<int>(array,temp,n);
if(temp == n - 1)
{
return -1; //无解
}
else
{
//对于(big_pos, len)
for(int i = n - 1; i >= big_pos; --i)
{
temp = int(sqrt((double)array[i]));
int low_pos = BinarySearch<int>(array,temp,n);
for(int j = 0; j <= low_pos; )
{
double temp2 = (double)array[i] /(double) array[j];
if(!IsInteger(temp2))
++j;
else
{
int k = BinarySearchAccurate<int>(array, (int)temp2, low_pos + 1, i );
if(k != -1)
return array[i];
else
++j;
}
}
}
}
return -1; //无解
}
int main()
{
sort(array, array + sizeof(array)/sizeof(array[0]));
// qsort(array, sizeof(array), sizeof(array) / sizeof(array[0]));
PrintArray<int>(array, sizeof(array) / sizeof(array[0]));
// cout<<BinarySearch<int>(array,13,sizeof(array) / sizeof(array[0]))<<endl;
cout<<"Result: "<<Compute(array, sizeof(array) / sizeof(array[0]))<<endl;
return 0;
}
喔,上面程序开头的注释写错了
求满足条件的最大整数k,如果不存在,则输出-1
应该是
求满足条件的最大整数ak,如果不存在,则输出-1
medie2005(阿诺)的方法的复杂度能证明是O(NlogN)的么?
我觉得最坏的情况下的复杂度是O(N^2);
考虑{2,4,16,256,....,2^(2*(N-1)))的数组;
计算在已排好序的数组中的首元a[0]的平方,即a[0]*a[0]。用二分查找,找到在已排好序的数组中不小于a[0]*a[0]的最低位置big_pos,若big_pos==len,说明无解。
// big_pos=1;
否则:
对区间[big_pos,len)的元素(len是数组的长度),从尾开始向前扫描。
对元素ak,计算它的取整平方根sak=int(sqrt(ak)),用二分查找,找到在已排好序的数组中大于sak的最低位置pos。
//pos=k-1;
对已排好序的数组中区间[0,pos)内的元素ai,检查ak/ai是否为正整数,
a): 若不是,++i;
b): 若是,用二分查找确定区间[pos,k)是否存在值为ak/ai的数,若存在,结束;否则,++i。
//区间[0,pos)内的元素ai,ak/ai都是整数,且在[pos,k)不存在值为ak/ai的数;
//所以必须搜索所有的[0,pos)范围内所有的数;
总的代价应该是O(N^2);
galois_godel() 贴的代码好象也有点问题;
只是找到有ak,但不是要求的最大的ak;
应该这样的:
for(i=n-1;i>=2;i--)
{
for(j=0,k=i-1;k>j;)
{
int s=a[j]*a[k];
if (s==a[i]) return; a[i];
else if (s>a[i]) k--;
else j++;
}
}
return -1;
假设有数组A[1...n]
(1)首先从小到大排序;
(2)假设ai<=aj<=ak
从末尾最大的元素开始,最左边ai从A[1]开始向右搜索,最右边aj从A[i]/A[1]向左搜索
找到的第一个满足条件的ak就是该题的解
算法伪码描述如下:
n = Length[A];
for i=n to 1 step -1
leftBound = 1;
rightBound = A[i]/A[1]; //确定搜索的右边界
while ( leftBound<rightBound )
temp = A[leftBound]*A[rightBound];
if ( temp < A[i] )
then leftBound++;
else if( temp == A[i] )
then return A[i]; //返回,找到该最大的值
else
rightBound -- ;
return -1; //没找到
在最坏的情况下,时间复杂度是O(nlogn+ n2 )
上面写错了,应该算法是:
n = Length[A];
for i=n to 1 step -1
//确定搜索的左边界
leftBound = 1;
//确定搜索的右边界
k = A[i]/A[1];
rightBound = i;
while( A[rightBound] > k )
rightBound --;
while ( leftBound<rightBound )
temp = A[leftBound]*A[rightBound];
if ( temp < A[i] )
then leftBound++;
else if( temp == A[i] )
then return A[i]; //返回,找到该最大的值
else
rightBound -- ;
return -1; //没找到
最坏的情况是:1,2,2,7,9,............ 最大的ak是a3=2
最好的情况是:1, ..........., 199, 199 时间复杂度是O(1)
loops(迷茫)算新颖。。。
1. 不排序,先利用找最大算法找出第一大的值Max
2. 然后利用Max的平方根r作为划分标准将集合s划分为两部分A、B。使得A中小于r,B中大于r
3. 令|A|=a, |B|=b
4. if a>b
5. then 按照从小到大顺序排序B中元素
6. 对A中每个元素x利用二分检索检查在B中是否有元素y使得x*y=s
7. else 按照从小到大顺序排序A中元素
8. 对B中每个元素y利用二分检索检查在A中是否有元素x得x*y=s
9. 不满足的话跳回步骤1找第二大值赋给Max直到所有数都选择后输出-1
屈婉玲老师在我们的课上好像就是说的这个题目
看来在最坏情况下,O(n^2)的时间复杂度逃不掉,都是同一个量级的,各个算法的区别只是在于具体计算步骤多几步或少几步。
loops的算法跟tailzhou的算法实质差不多,只是没有进行二分查找和用sqrt()去限定查找结束的范围。
to division
对A中每个元素x利用二分检索检查在B中是否有元素y使得x*y=s
这个s是什么
of coz 应该是O(N^2)
toold的经典题
nod, O(N^2)看来是不可避免的
to galois_godel()
请问这道题目有出处吗,谢谢
我给的复杂度比较难算,那位给算算啊。
mark一下先
对A中每个元素x利用二分检索检查在B中是否有元素y使得x*y=s
这个s是什么
s 即是本题中的ak
但是现在还不知道ak是多少啊,ai和aj也不知道啊,怎么用二分检索查?
medie2005(阿诺)的算法复杂度:
1)对于ak,设需要测试的ai的个数为p,则对于每个ai,二分查找的个数为k-p。
2)假设输入是均匀分布的,那么平均情况下,p=k^(1/2),k-p = k - k^(1/2)。
3) k的取值范围是0--N,平均情况下是N/2,故第二点的p为O(N^(1/2)),k-p为O(N)。
4)查找ak次数,平均情况下为N/2
综上,该算法平均时间复杂度是O(N^(3/2)logN),小于O(N^2).
而在最坏情况下,p可以达到它的最坏复杂度O(N),并且k-p也保持O(N)[例如,当某种输入分布使p=k/2时]。此时,算法达到其最坏复杂度O(N^2*logN),大于O(N^2).
可 以对这个算法做一些改进以进一步提高速度。例如,对于二分查找方面,可以改用hash查找。预先用hash表存储所有的输入值(不需要对每个ak建立 hash表,只要一次性建立即可,因为根据对ai的限定,如果查找出值,则一定是所需要的),并在原先二分查找的地方,使用hash查找。由于建立整个 hash表的复杂度是O(N),并且整个算法只需建立一次。而查找一次hash表的复杂度是O(1)。所以,这个改进可以使算法的平均复杂度达到O(N^ (3/2)),最坏复杂度达到O(N^2)。
上文有一个含糊之处,在3)中,“k-p为O (N)”系指将其个数等价于O(N),而在复杂度计算中,由于使用二分查找,其实际复杂度是O(logN)。在最坏情况分析中,"k-p也保持O(N)" 也是同样的含义。当然,在每个复杂度的结论部分没有错误,均已考虑了此处说明的内容。
这个题目,最坏情况下为O(N^2)的原因是:在把每个数字看成相互独立的前提下,任何一个ai*aj(或者ak/ai)都有可能目标值,为此,最坏情况下至少需要计算每一个值,从而达到O(N^2)的复杂度。
也 许,可以想办法去除数字间的独立性,从而找到进一步提高的可能。如将每个a因式分解后再想办法查找?N个元素的因式分解的最坏复杂度是O(N^(3/2) logN),低于O(N^2)。此后如果有复杂度基于因子个数[为O(N^(1/2))]的算法可以用低于4次方的速度找到结果,那么就有可能将最坏复杂 度提高到O(N^(3/2)logN)。
kan.
mark
to Vitin(卫亭) ( )
因式分解的话复杂度跟元素的大小相关的,如果元素值比N大很多,那总的复杂度会比N^2大
O(N^2)
先从小到大排序
for(i=0;i<n;i++)
{
for(j=0,k=i;j<=i && k<n;)
{
if(a[i]*a[j]==a[k])return; //find
else if(a[i]*a[j]>k)k++;
else j++;
}
}
return -1;
这个会计算出最小的那个 ak
ok.
oo(为了名副其实,努力学习oo技术ing) 说的对,关于因式分解的复杂度计算错了。
对于值为V的整数,做因式分解的复杂度为O(V^(1/2)logV)。
之前我将ak的最大序数值N和最大数值V=max(ak)搞混了。
呵呵,看来因式分解是不行的。大家可以想想其他办法。
请问这道题目有出处吗,谢谢
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~作过竞赛题好几次阿
这是俺的解法,按俺的测试没超过 O(N^2)
bool MyFind(vector<unsigned int> &vec, unsigned int &result)
{
if(vec.size() < 3)
{
result = -1;
return false;
}
std::sort(vec.begin(), vec.end()); //小到大排序
int count = 0;
vector<unsigned int>::size_type left, right;
const vector<unsigned int>::size_type MaxRight = vec.size() - 1; //数组最大下标, 最小下标为 0
for(vector<unsigned int>::size_type mid = vec.size() - 2; mid > 0; mid--)
{
left = mid - 1;
right = MaxRight;
while(left >= 0 && right > mid)
{
count++;
if(vec[right] == vec[mid] * vec[left])
{
result = vec[right];
cout<<count<<endl;
cout<<vec[right]<<"="<<vec[mid]<<"*"<<vec[left]<<endl;
return true;
}
if(vec[right] > vec[left])
{
--right;
}
else
{
--left;
}
}
}
cout<<count<<endl;
return true;
}
一个笨方法 O(N^3)
例 1,2,3,4,5,15,16,17,18,64
先分析 64
64 开方为 8
有
1,2,3,4,5 | 15,16,17,18,
------> <-----------
n1 * n2 = 64
有1 * 18 < 64 必有 n1 > 1
.....
必有 n1 > 3
4 * 18 > 64 必有 n2 < 18
....
.
.
.
得到64 = 4 * 1
Top 回复人:tengomi() ( ) 信誉:100 2007-07-30 10:51:16 得分:0 ? 例 1,2,3,4,5,15,16,17,18,64
先分析 64
64 开方为 8
有
1,2,3,4,5 | 15,16,17,18,
------> <-----------
n1 * n2 = 64
有1 * 18 < 64 必有 n1 > 1
.....
必有 n1 > 3
4 * 18 > 64 必有 n2 < 18
....
.
.
.
得到64 = 4 * 1
呵呵,再看看,如果没有更好的解法,今天晚上就结贴了
Top 回复人:shareyao() ( ) 信誉:100 2007-07-30 10:58:54 得分:0 ? 先递增排序:a1,a2,...an
因为是递增,假定i<j<k
pseudocode:
for(k=n →1)
for(j = k-1 →1)
{
if(a[k]%a[j] != 0)
countinu;
else
binarysearch(//二分查找[1-j)之间是否存在a[k]/a[j]);
if(存在)
return a[k]; //满足条件的最大数
}
return -1;
Top 回复人:danjiewu(阿丹) ( ) 信誉:100 2007-07-30 12:16:50 得分:0 ? 因为是递增,假定i<j<k
pseudocode:
for(k=n →1)
for(j = k-1 →1)
{
if(a[k]%a[j] != 0)
countinu;
else
binarysearch(//二分查找[1-j)之间是否存在a[k]/a[j]);
if(存在)
return a[k]; //满足条件的最大数
}
return -1;
只要求最大的ak,应该不需要O(n^2)
Top 回复人:charlie_god() ( ) 信誉:100 2007-07-30 12:24:19 得分:0 ? 1.把集合采用组合算法变为 3个元素对的集合{{a1, b1, c1},....{an, bn, cn} }
2.接着把这个3元素对集合进行 ak * bk == ck 检验
Top 回复人:danjiewu(阿丹) ( ) 信誉:100 2007-07-30 12:57:55 得分:0 ? 2.接着把这个3元素对集合进行 ak * bk == ck 检验
想了一下,复杂度确实是O(n^2)的。
Top 回复人:masterfather() ( ) 信誉:100 2007-07-30 13:34:33 得分:0 ? #include <iostream.h>
void main()
{
int i,j,k,n,t;
int s=0;
cin>>n;
int *a=new int[n];
int *b=new int[n];
for(i=0;i<n;i++)
cin>>a[i];
for(i=0;i<n-2;i++)
for(j=i+1;j<n-1;j++)
for(k=j+1;k<n;k++)
if(a[i]*a[j]==a[k])
b[s++]=a[k];
if(s==0)
cout<<-1<<endl;
else
{
for(i=0;i<s-1;i++)
for(j=i+1;j<s;j++)
if(b[i]<b[j])
{
t=b[i];
b[i]=b[j];
b[j]=t;
}
cout<<b[0]<<endl;
}
}
Top 回复人:masterfather() ( ) 信誉:100 2007-07-30 13:36:48 得分:0 ? void main()
{
int i,j,k,n,t;
int s=0;
cin>>n;
int *a=new int[n];
int *b=new int[n];
for(i=0;i<n;i++)
cin>>a[i];
for(i=0;i<n-2;i++)
for(j=i+1;j<n-1;j++)
for(k=j+1;k<n;k++)
if(a[i]*a[j]==a[k])
b[s++]=a[k];
if(s==0)
cout<<-1<<endl;
else
{
for(i=0;i<s-1;i++)
for(j=i+1;j<s;j++)
if(b[i]<b[j])
{
t=b[i];
b[i]=b[j];
b[j]=t;
}
cout<<b[0]<<endl;
}
}
我刚试过了,可以提到想要的结果。
- 存在ai * aj = ak
- 求序列中满足Ai < Aj > Ak and i < j < k的组数 树状数组 HIT 2275 Number sequence
- 稳定排序:如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前
- CareerCup perform increment operation on ai = ai+1 and decrements operation on aj = aj - 1
- aj
- UVa 11078 Ai-Aj(i<j)的最大值
- 求浮点数数组A={A1,A2,A3,…,An}中,Aj-Ai(j>i)的最大值。要求时间复杂度越小越好
- 给一个数组[a1,a2,a3....an],要求出令ai-aj有最大值,其中i<=j,时间和空间复杂度尽可能小
- HDU 5344(MZL's xor-(ai+aj)的异或和)
- 2-11 整数数组 A1<A2<A3......An中是否存在 Ai = i?
- AI技术存在的伦理争议
- AK build
- AK-47
- ai=?
- AK-47 制造商 Kalashnikov 已成功研发 AI 武器 以 AK-47 闻名世界的俄罗斯军火商 Kalashnikov 近日宣布,其已成功研发全自动武器模块,能够利用人工智能技术识别目
- 英语 -AJ
- 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列,对于1<=i,j<=k,求k个最小的(ai+bj),要求算法尽量高效
- 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。
- firefox与ie 的javascript区别
- Berkeley 的大牛论GPL,LGPL and BSD
- [偷懒:)]Functional Programming Tools
- 学习Java需要达到的30个目标[转]
- 17个推荐Blogger使用的Firefox扩展
- 存在ai * aj = ak
- 推荐:用百度搜索的一些小秘密
- 商务英语文选
- java学习之路【转】
- 将文本文件读入c#数组
- MAYA学习心得——起步2 小魔
- 用“心”管理,收获人心
- 差点冤枉了boost iostream
- SAP真的很难呀