题目:
只包含因子2、3、5的数字被称为丑数。例如4和6是丑数,而14不是丑数,因为含有因子7。习惯上把1作为第一个丑数。求按从小到大顺序的第1500个丑数。
分析:
假设一个丑数顺序数组ugly_nums[],对于其中一个丑数ugly=ugly_nums[x],存在2*ugly_nums[i-1]<=ugly,2*ugly_nums[i]>ugly,也就是说2乘以一个丑数刚刚大于丑数ugly;
同理也存在3*ugly_nums[j-1]<=ugly,3*ugly_nums[j]>ugly,和5*ugly_nums[k-1]<=ugly,5*ugly_nums[k]>ugly。
那么第x+1个丑数应该是3个倍数结果中最小的那个,即ugly_nums[x+1]=min{2*ugly_nums[i],3*ugly_nums[j],5*ugly_nums[k]};
这应该算是一种数值逼近的思想,遇到一些需要计算的数值需找时可以考虑,比如找顺序数组中满足和为某值得数字对
算法需要借助一个辅助数组存储丑数,空间复杂度O(n)。时间复杂度O(n)
代码
1 int FindUglyNum(unsigned int index) 2 { 3 int *uglynums=new int[index]; 4 5 uglynums[0]=1; 6 uglynums[1]=2; 7 uglynums[2]=3; 8 uglynums[3]=4; 9 uglynums[4]=5; 10 11 unsigned int i=1,j=1,k=1; 12 unsigned int min_uglynum=0; 13 unsigned int idx=4; 14 while (idx<index) 15 { 16 if (2*uglynums[i]<uglynums[idx]) 17 { 18 i++; 19 } 20 if (3*uglynums[j]<uglynums[idx]) 21 { 22 j++; 23 } 24 if (5*uglynums[k]<uglynums[idx]) 25 { 26 k++; 27 } 28 min_uglynum=MIN(MIN(2*uglynums[i],3*uglynums[j]),5*uglynums[k]); 29 uglynums[++idx]=min_uglynum; 30 } 31 32 return uglynums[index-1]; 33 }
数值逼近之和为n的连续整数序列
输入一个整数,输出所有和为n的连续正数序列。例如:输入15,由于15=7+8=4+5+6=1+2+3+4+5,所以输出的序列为1,2,3,4,5;4,5,6;7,8
分析:
由于要求的子序列是连续的,那么就可以连续数字的相加一点一点逼近n。设small=big=1,sum=small+big,移动big并计算新sum=sum+big,直到sum>=n,如果sum=n,则small到big是所求的子序列之一,
若sum>n,则调整small向后移动,直到sum<=n。循环依次调整big和small,直到small=n/2
代码
1 void FindContinuousNumbers(int n) 2 { 3 int small = 1,big = 1; 4 int middle = n/2; 5 int sum = small; 6 7 while(small <=middle&&big<=n) 8 { 9 sum += big; 10 11 if(sum == n) 12 { 13 for(int i = small;i <= big;++i) 14 cout<<i<<" "; 15 cout<<endl; 16 } 17 18 while(sum > n) 19 { 20 sum-=small; 21 small++; 22 23 if(sum == n) 24 { 25 for(int i = small;i <= big;++i) 26 cout<<i<<" "; 27 cout<<endl; 28 } 29 30 } 31 big++; 32 } 33 }
数值逼近之升序数组中和为n的数字对
输入一个已经按升序排列的数组,一个给定的数字num,在数组中查找两个数,使得它们的和等于n。要求时间复杂度为O(n),如果存在多对满足条件的数字对,只给出一对即可
分析:
既然是已经排列好的数组,又是求和,那么也可以用数值逼近的方式求解。设small=arr[0],big=arr[n-1],sum=small+big,若sum=num,则small和big就是要找的数对之一,若sum>num,则向前调整big,若sum<num,则向后调整small,直至small=big,循环结束。本题既然只要求给出一对数字,那么当sum=num时就可以停止查找了
代码
1 void FindSumPairs(int arr[],int len,int num) 2 { 3 if (arr==NULL||len<=0) 4 throw std::exception("Invalid input."); 5 int small=0,big=len-1; 6 int sum=0; 7 8 while (small<big) 9 { 10 sum=arr[small]+arr[big]; 11 12 if (sum==num) 13 cout<<arr[small]<<' '<<arr[big]<<endl; 14 15 if (sum>num) 16 big--; 17 18 if (sum<num) 19 small++; 20 } 21 22 }