ok?拿到这个题目,我们最开始想到的可不可以利用一般的除法获得结果,然后将结果装换成一个字符串进行字符的匹配,然后返回下标呢?
显然在这里是行不通的:
原因:
1、首先我们通常使用的double除法,位数的精度满足不了题目中的要求,题目中假如出现的是一个无限循环小数,我们无法记录它的所有小数点之后的数字。
2、即便我们记录下来了一定的位数,进行匹配的效率上也会存在很大的问题。
综上所述,我们应该选择另外一条路来解决这个问题,好吧,没有别的办法我们就用笔在纸上算一下这个算数除法的过程,在计算的过程中我们会发现:
1、所谓除法无非就是一个求商求余数的过程。
2、进一步来说所谓求商,实际上一个余数补零取整的操作。
3、求余数就是一个余数补零求模的操作。
看到以上三点我们就成功了一半,为什么说是一半呢:因为很多人看到这里,就开始写程序了,求模求商,然后将商放在一个数字里面进行匹配输出结果,最开始我也是这么去做的。但是,实际上这其中就包含了不能容忍的空间和时间上的损失。为什么这么说呢?
首先,我们知道其实小数分为两类:有限小数和无限小数,其实所谓的无限小数又分为循环小数和不循环小数。但是由分数构成的无限小数都是循环小数。为什么这么说呢?原因很简单就是我们从求小数的计算过程中可以看出,只要我们的余数出现了重复,商就进入了一个循环之中,所以我们没有必要将所有的商存储在一起,我们只需要存储一段未重复的商值,就可以通过M推导出商之中所有的数字出现的次序。
看到这里这个问题我们就解决了98%了,那余下的2%到底是什么?不要着急,当你写程序的时候就会发现这个问题了。现在我可以告诉大家:当我们的余数不重复的时候,商是有可能发生重复的,在一次循环中出现了商重复的情况我们需要记住重复重现的所有商的位置!
说了这么多还是上代码吧!
点击(此处)折叠或打开
-
#include <iostream>
-
#include <vector>
-
#include <set>
-
using namespace std;
-
int numPosAfterDecimalPoint(int firstNum, int secondNum, int code, int dest)
-
{
-
if(firstNum < 0 || secondNum < 0 || code <= 0)
-
return -1;
-
set<int> remainder; //记录下余数
-
int temp;
-
int start; //循环起始时的余数
-
int counter = 0;
-
vector<int> quotient;
-
vector<int> cycleQuotient;
-
vector
pos(secondNum, 0) ;
-
temp = firstNum % secondNum; //当被除数大于除数的时候先要进行一次取模的运算,如果为零则直接返回0
-
if(temp == 0)
-
{
-
return 0;
-
}
-
remainder.insert(temp);//将余数压入set集合
-
while(true)
-
{
-
quotient.push_back(temp * 10 / secondNum); //将商放入一个数组
-
temp = temp * 10 % secondNum;
-
if(remainder.count(temp)) //判断余数是否发生了重复,假如发生了重复将重复部分的商压入cycleQuotient
-
{
-
start = temp;
-
do{
-
cycleQuotient.push_back(temp * 10 / secondNum);
-
temp = temp * 10 % secondNum;
-
}while(temp != start);
-
//cout << "cycleQuotient: " << cycleQuotient.size() << endl;
-
break;
-
}
-
remainder.insert(temp);
-
}
-
//cout << "quotient.size(): " << quotient.size() << endl;
-
vector<int>::size_type it = 0;
-
while(it != quotient.size()) //在一次循环中查找目标元素
-
{
-
if(quotient[it] == dest)
-
{
-
counter++;
-
if(counter == code)
-
return ++it;
-
}
-
it++;
-
}
-
if(counter == 0)
-
return 0;
-
else if(counter < code) //判断要求的位置是否超出了一次循环,假如超出计算循环商中目标数字的位置
-
{
-
int i = 0;
-
vector<int>::size_type it = 0;
-
while(it != cycleQuotient.size())
-
{
-
if(cycleQuotient[it] == dest)
-
{
-
pos[++i] = it + 1;
-
}
-
it++;
- }
- if(pos[1] == 0)
-
return 0;
-
if((code - counter) >= i && (code - counter)% i == 0)
-
{
-
return quotient.size() + ((code -counter) / i - 1) * cycleQuotient.size() + pos[i];
-
}
-
else if((code - counter) < i)
-
return quotient.size() + pos[(code - counter) % i];
-
else
-
{
-
return quotient.size() + ((code - counter) / i - 1) * cycleQuotient.size() + pos[(code - counter) % i];
-
}
-
}
-
}
-
int main() {
-
int firstNum; //被除数
-
int secondNum; //除数
-
int code; //表示第次出现的目标数字
-
int dest; //目标数字
-
cout << "firstNum: " << endl;
-
cin >> firstNum;
-
cout << "secondNum: " << endl;
-
cin >> secondNum;
-
cout << "code: " << endl;
-
cin >> code;
-
cout << "dest: " << endl;
-
cin >> dest;
-
cout << "result: " << numPosAfterDecimalPoint(firstNum, secondNum, code, dest) << endl;
-
return 0;
- }