京东2018校招 神奇数 (c/c++)

废话

上周末被学长远程抓壮丁答狗东2018的C++笔试题。2个小时4道大题,一个人做确实时间紧,记录一下学长甩给我第二题的神奇数。

想来自从6月份毕业就没再做过题,手生写的慢,好赖算是ac了,后来听说这题现场ac率10%我也是挺吃鲸的 =、=

闲话不多说,看题。


神奇数(京东2018校招C/C++工程师笔试大题第二道)

时间限制:1秒

空间限制:32768K

题目描述:

东东在一本古籍上看到有一种神奇数,如果能够将一个数的数字分成两组,其中一组数字的和等于另一组数字的和,我们就将这个数成为神奇数。例如242就是一个神奇数,我们能够将这个数的数字分成两组,分别是{2, 2}以及{4},而且这两组数的和都是4。东东现在需要统计给定区间内中有多少个神奇数,即给定区间(l, r),统计这个区间中有多少个神奇数,请你来帮助他。


分析及解法

先把题目对神奇数的描述翻译成人话:“给你一个数,按位拆开后分成两堆儿,两堆儿的和相等”。

我们把区间内的数字按位拆开可以得到一个n位的数组,然后求其组合:

Cmn (m = 1, 2, … n/2)

对组合结果求和,判断是否等于按位总和的一半。


Code

#include <cstdio>
#include <vector>
#ifndef NO_WIN32_TIMER
#include <Windows.h>
#endif

using std::vector;

static unsigned long g_target;  //按位总和的一半
static bool g_flag;             //是否是神奇数
static vector<char> g_fenjie;   //按位分解结果
static vector<char> g_zuhe;     //组合结果

// 对待分析的数字进行拆解,结果存入g_fenjie
// 如果按位和为奇数则一定不是神奇数,直接返回false
bool GetSumAndAnalyze(unsigned int num) {
    int fenjie_qiuhe = 0;
    g_fenjie.clear();
    do {
        fenjie_qiuhe += num % 10;
        g_fenjie.push_back(num % 10);
    } while (num /= 10);
    if (0 == fenjie_qiuhe % 2) {
        g_target = fenjie_qiuhe / 2;
        return true;
    }
    return false;
}

// 递归求组合,传入当前遍历到的数组下标和剩余个数
void Combination(int index, int number) {
    if (g_flag) return;
    if (!number) {
        int sum = 0;
        for (auto iter : g_zuhe)
            sum += iter;
        if (sum == g_target)
            g_flag = true;
        return;
    }
    if (index == g_fenjie.size()) return;

    g_zuhe.push_back(g_fenjie[index]);
    Combination(index + 1, number - 1);
    g_zuhe.pop_back();
    Combination(index + 1, number);
}

// 递归C(1/n) ~ C((n/2)/n),求到n-1就可以覆盖全部组合
void Combination()
{
    int length = g_fenjie.size();
    g_zuhe.clear();
    for (int i = 1; i <= length / 2; ++i) {
        Combination(0, i);
        if (g_flag) break;
    }
}

// RT
bool IsMegicNumber(unsigned int num) {
    if (!GetSumAndAnalyze(num))
        return false;
    g_flag = false;
    Combination();
    return g_flag;
}

// 调用IsMegicNumber求区间(l, r)内神奇数的个数.
int MegicNumberCnt(unsigned int l, unsigned int r) {
    g_fenjie.reserve(10);
    g_zuhe.reserve(10);
    int cnt = 0;
    for (unsigned int i = l; i <= r; ++i)
        if (IsMegicNumber(i)) ++cnt;
    return cnt;
}

// 测试并计时
int main()
{
#ifndef NO_WIN32_TIMER
    LARGE_INTEGER t1, t2, tc;
    QueryPerformanceFrequency(&tc);
    double cost;
    QueryPerformanceCounter(&t1);
#endif

    printf("%d ", MegicNumberCnt(1, 65535));

#ifndef NO_WIN32_TIMER
    QueryPerformanceCounter(&t2);
    cost = (double)(t2.QuadPart - t1.QuadPart)*1.0 / tc.QuadPart;
    printf("cost time: %f s.\n", cost);
#endif

    getchar();
    return 0;
}

继续废话

网上看见一篇核心思路用01背包做的,直接上链接:

blog.csdn.net/bing_lee/article/details/77899602

核心思想其实和组合差不多,都是搓堆儿凑一半,但可能有一半冗余计算。
效率不如直接用组合,简单做了个1~65535区间内对照测试验证:

vs2015_win7_x86_Release

猜你喜欢

转载自blog.csdn.net/u014755412/article/details/77944488
今日推荐