京东2018校招 神奇数 (c/c++)
2017-09-12 14:07
274 查看
废话
上周末被学长远程抓壮丁答狗东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区间内对照测试验证:
相关文章推荐
- 京东2018校招Web前端工程师笔试有感
- 2018京东校招笔试题-数据分析岗
- 【2018校招笔试-京东=java开发】题目1括号匹配方案
- 京东2018校招在线笔试编程题①
- 2018京东校招Java笔试题
- 京东2018校招研发笔试题记录
- 【2018校招笔试-京东=java开发】题目2 求幂
- 2018京东笔试 疯狂序列 神奇数
- JD2018校招神奇数,疯狂队列
- 京东2018秋招校招Java研发岗
- 剑指Offer——京东校招笔试题+知识点总结
- 2017京东校招面试回忆(已成功拿到offer)
- 把N*N矩阵顺时针旋转90°输出(2018携程校招笔试题)
- 2018校招关于循环小数的题目
- 牛客网-网易2018校招内推编程题集合-解题思路及源码
- 网易2018校招内退编程题 独立的小易
- 网易2018校招编程题集合8
- 2018校招(BAT机器学习)要求
- 美团2018算法岗校招笔试第一题
- 网易2018校招内推编程题--彩色砖块