算法题3 寻找丑数&数值逼近

题目

只包含因子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  }

 

    

posted @ 2016-01-28 17:34  summerxx  阅读(292)  评论(0编辑  收藏  举报