【递归】带分数

  • Post author:
  • Post category:其他




【递归】带分数

题目来源

带分数

,这道题目比较有意思

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。

自己也尝试去实现,但是自己写的代码时间复杂度太高,因此这里黏贴了自己的代码 和 别人的代码,以供对比理解和学习。



一、自己写的代码(相当相当耗时~~)

想法:

  • 从小于

    num

    的整数集合中选一个数作为整数

    k

    ,并判断是否出现重复数字。
  • 将9位数字中未出现的数字拼接成一个字符串,利用全排列和字符串截断,校验分数是否等于

    num - k

实现代码:

#include<stdio.h>
#include <iostream>
#include <algorithm>
#include<string>
#define N 9 
using namespace std;

//查找带分数(不包含0)
int found(int num){
    int i;
    int count = 0;  //满足条件的带分数个数
    for(i = 0; i < num; ++i){

        if(i % 10 == 0){ //整数部分含0,去除
            continue;
        }

        int visited[10] = {0};  
        int flag = 1;
        int temp = i;
        do{
            if(visited[temp % 10] == 1){ //整数部分含重复数字,去除
                flag = 0;
                break;
            }
            visited[temp % 10] = 1;
        }while(temp / 10);
        
        //整数部分i满足要求
        if(flag){
            string str;
            int j;
            for(j = 1; j < 10; ++j){
                if(visited[j] == 0){
                    str += (j + '0');
                }
            }

            int left = num -i; //num - 整数
            //全排列 + 分数校验
            do {
                // cout << str << endl;
                int k;
                for(k = str.length() / 2 - 1; k < str.length(); ++k){
                   long p1 = atol(str.substr(0,k).c_str()); 
                   long p2 = atol(str.substr(k, str.length()).c_str());
                   cout << p1 << " / " << p2 << endl;
                   if(p1 / p2 == left){
                        count++;
                   }
                }
            } while (next_permutation(str.begin(), str.end()));
            cout << endl;
        }
    }
    return count;
}

int main(int argc, char const *argv[])
{
    int num = 100;
    int count = found(num);  // 分数校验
    cout << count << endl;
}

无奈时间复杂度太高:

  • 如果

    num=100

    ,需要遍历100次查找整数部分;
  • 分数部分最好情况下则需要每次对7位字符进行全排列;
  • 全排列后每次得到的字符串又需要通过截断来计算分子和分母,再进行

    100-k

    的数值校验。

所以整趟下来,遍历次数为

100 * 7! * (7 - 2) = 2520000

。对于

n=100





10

0

3

2520000

100^3 \sim 2520000






1


0



0










3




















2


5


2


0


0


0


0





,因此时间复杂度为



O

(

n

3

)

O(n^3)






O


(



n










3









)





接下来看看别人写的代码,自行分析解题思路,理解是怎样毫秒级求得解的。



二、别人的代码1

#include<iostream>
#include <cstring>
using namespace std;

int a[10] = {0};
int Division(int m)
{
    int t;
    while (m)
    {
        t = m % 10;
        if (t == 0)
        {
            return 0;
        }
        a[t]++;
        m = m / 10;
    }
    return 1;
}
int main()
{
    int i, k, j;
    int number, ans = 0, flag;
    cin >> number;
    for (i = 1; i < number; i++)
    {
        for (j = 1; j <= 4938; j++)
        {
            memset(a, 0, sizeof(a));
            k = (number - i) * j;
            if (Division(i) && Division(j) && Division(k))
            {
                flag = 1;
                for (int x = 1; x < 10; x++)
                {
                    if (a[x] != 1)
                    {
                        flag = 0;
                        break;
                    }
                }
                if (flag == 1)
                    ans++;
            }
        }
    }
    cout << ans;
    return 0;
}



三、别人的代码2

#include<iostream>
#include <cstring>
using namespace std;

int visit[10] = {0};
int s[10];
int ans = 0;
int N;
void found(int s[])
{
    int x, y, z;
    for (int i = 1; i < 9; i++)
    {
        for (int j = i + 1; j < 9; j++)
        {
            x = y = z = 0;
            for (int k = 0; k < 9; k++)
            {
                if (k < i)
                    x = x * 10 + s[k + 1];
                else if (k < j)
                    y = y * 10 + s[k + 1];
                else
                    z = z * 10 + s[k + 1];
            }
            if (y % z == 0 && x + y / z == N)
            {
                ans++;
            }
        }
    }
}

void dfs(int pos, int n)
{
    if (pos == n)
        found(s);
    else
    {
        for (int i = 1; i <= 9; i++)
        {
            if (!visit[i])
            {
                s[pos] = i;
                visit[i] = 1;
                dfs(pos + 1, n);
                visit[i] = 0;
            }
        }
    }
}
int main()
{
    cin >> N;
    dfs(1, 10);
    cout << ans << endl;
    return 0;
}



四、别人的代码3

#include<iostream>
#include <cstring>
#include<algorithm>
using namespace std;

int parse(const char *arr, int pos, int len)
{
    int ans = 0;
    int t = 1;
    for (int i = pos + len - 1; i >= pos; i--)
    {
        ans += (arr[i] - '0') * t;
        t *= 10;
    }
    return ans;
}

int main()
{
    int N;
    cin >> N;
    int ans = 0;
    string s = "123456789";
    do
    {
        const char *str = s.c_str();
        for (int i = 0; i <= 7; i++)
        {

            int inta = parse(str, 0, i);

            if (inta >= N)
                break;
            for (int j = 1; j <= 9 - 1 - i; j++)

            {

                int intb = parse(str, i, j);
                int intc = parse(str, i + j, 9 - i - j);
                if (intb % intc == 0 && inta + intb / intc == N)
                {
                    ans++;
                }
            }
        }
    } while (next_permutation(s.begin(), s.end()));

    cout << ans;
    return 0;
}



版权声明:本文为qq_33934427原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。