程序员面试金典: 9.7数学与概率 7.7有些数的素因子只有3,5,7,请设计一个算法,找出其中第k个数

#include <iostream>
#include <stdio.h>

using namespace std;

/*
问题:有些数的素因子只有3,5,7,请设计一个算法,找出其中第k个数。
分析:第k个数是指第k小的数吧?这个题目应该是剑指offer或编程之美中的丑数。
      丑数的关键是寻找下一个丑数,
	  下一个丑数 = 在之前生成的丑数数组中寻找一个数 * (3或5或7),即大于当前丑数的最小值
	  设当前丑数为M
	  设第一个乘以3大于M的数为M3,同理M5,M7,则M = min(M3, M5 , M7)
	  对于丑数3而言,必定存在T3使得T3之前的数乘以3都小于M,T3之后的丑数
	  关键是寻找丑数数组中第一个乘以3大于当前最大丑数的数T3,寻找丑数数组中第一个乘以5大于最大丑数的数T5,同理T7
	  使得:
	  设当前丑数为M
	  3*T3=M3 > M  【公式(1)】
	  5*T5=M5 > M  【公式(2)】
	  7*T7=M7 > M  【公式(3)】
	  从中令新的M = min(M3 , M5 , M7),并更新T3,T5,T7,使得新的T3,有3*T3 > M,同理T5,T7    【操作1】
	  如果不更新,带来的问题就是,会陷入死循环
	  比如刚开始M=1,初始T3=T5=T7=1,满足上述条件后,M=3,此时3*T3 <= M,则T3=1没有等于3,同理后续T5=1,T7=1,而M=7,
	  之后就发现T3,T5,T7中没有一个能符合上述公式(1),(2),(3),则M一直变成7不再变化;
	  为了防止这种情况,要进行上述操作1的处理,为的就是能够作为下一个丑数M的候选值能够一直变大
输入:
7(k)
输出:
25

关键:
1 下一个丑数 = 在之前生成的丑数数组中寻找一个数 * (3或5或7),即大于当前丑数的最小值 
设当前丑数为M
3*T3=M3 > M  【公式(1)】
5*T5=M5 > M  【公式(2)】
7*T7=M7 > M  【公式(3)】
从中令新的M = min(M3 , M5 , M7),并更新T3,T5,T7,使得新的T3,有3*T3 > M,同理T5,T7    【操作1】
如果不更新,带来的问题就是,会陷入死循环
比如刚开始M=1,初始T3=T5=T7=1,满足上述条件后,M=3,此时3*T3 <= M,则T3=1没有等于3,同理后续T5=1,T7=1,而M=7,
之后就发现T3,T5,T7中没有一个能符合上述公式(1),(2),(3),则M一直变成7不再变化;
为了防止这种情况,要进行上述操作1的处理,为的就是能够作为下一个丑数M的候选值能够一直变大
*/

int min(int a , int b , int c)
{
	int minNum = a < b ? a : b;
	minNum = minNum < c ? minNum : c;
	return minNum;
}

int findUglyNumber(int k)
{
	int *pArray = new int[k + 1];
	pArray[0] = 1;
	int* p3 , *p5 , *p7;
	p3 = p5 = p7 = pArray;
	int count = 0;
	int minNum;
	while(count < k)
	{
		count++;
		minNum = min( *p3 * 3 , *p5 * 5 , *p7 * 7);
		pArray[count] = minNum;
		//注意等号不能取,while中循环条件如果改成 *p3 * 3 < minNum 是错误的,这样会陷入死循环,使得minNum候选的几个候选值不再变化 
		while( *p3 * 3 <= minNum )
		{
			p3++;
		}
		while( *p5 * 5 <= minNum)
		{
			p5++;
		}
		while( *p7 * 7 <= minNum)
		{
			p7++;
		}
	}
	int result = pArray[k];
	delete[] pArray;
	return result;
}

void process()
{
	int k;
	while(cin >> k)
	{
		int result = findUglyNumber(k);
		cout << result << endl;
	}
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


                
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值