楼主: kqxqx
跳转到指定楼层
上一主题 下一主题
收起左侧

空气床电面

🔗
yikehongxin 2017-12-13 00:03:38 | 只看该作者
全局:
kqxqx 发表于 2017-12-12 23:47
是的,不用recursion的话得注意逻辑,保证所有中间结果都能cover掉

我最后几分钟写的iteration的版本 ...

我就用的是java,结果爆了。我改成iteration的方法,异常的慢,但是我试了小的数字,比如100,结果都是一样的。所以我觉得你被面试官坑了
回复

使用道具 举报

🔗
 楼主| kqxqx 2017-12-13 00:24:58 | 只看该作者
全局:
daguanyuan 发表于 2017-12-13 00:03
我就用的是java,结果爆了。我改成iteration的方法,异常的慢,但是我试了小的数字,比如100,结果都是一 ...

我写的那个iteration也慢,原因就是我说的不少中间结果没有放到cache里去,但是这个不好做,我现在也没有好的办法

recursion的话,结果是对的,N=1,000,000爆栈后,我试了N=100,000这个case,能跑出结果,但是面试官说他没有N=100,000的测试结果,所以不认
回复

使用道具 举报

🔗
qiu_cqupt 2017-12-21 12:52:38 | 只看该作者
全局:
能问下大佬几年工作经验么?怎么我投A就被秒拒了
回复

使用道具 举报

🔗
magicsets 2017-12-21 14:33:22 | 只看该作者
全局:
为了加速memoization表的存取可以用一个vector作为primary memo,一个unordered_map作为secondary memo

此外这题目有个坑就是对于N = 1000000,中间结果是会超过int表示范围的,比如n = 704511时,中间结果会到达 56991483520

写了一份参考代码,带优化编译的话大概100~200毫秒可以跑完:

  1. #include <algorithm>
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <stack>
  5. #include <unordered_map>
  6. #include <vector>

  7. class Solution {
  8. public:
  9.   std::int64_t exec(const std::int64_t N) {
  10.     // 调整这个系数会影响性能
  11.     // 系数越大,耗费空间越多,但速度也越快
  12.     // 8应该是一个比较好的选择...
  13.     constexpr std::int64_t kFactor = 8;

  14.     bound_ = N * kFactor;
  15.     primary_memo_ = std::vector<std::int64_t>(bound_, -1);
  16.     secondary_memo_ = std::unordered_map<std::int64_t, std::int64_t>();

  17.     std::vector<std::int64_t> stk;
  18.     stk.reserve(N);

  19.     setMemo(1, 0);
  20.     for (std::int64_t i = 2; i < N; ++i) {
  21.       // pre-check以加速运算
  22.       if (getMemo(i) >= 0) {
  23.         continue;
  24.       }

  25.       std::int64_t curr = i;
  26.       std::int64_t ret = -1;
  27.       stk.push_back(curr);

  28.       // 模拟的递归调用
  29.       while (ret < 0) {
  30.         const std::int64_t next = (curr & 0x1) ? (curr * 3 + 1) : (curr >> 1);
  31.         if ((ret = getMemo(next)) < 0) {
  32.           stk.push_back(next);
  33.           curr = next;
  34.         }
  35.       }

  36.       // 模拟的递归返回
  37.       while (!stk.empty()) {
  38.         setMemo(stk.back(), ++ret);
  39.         stk.pop_back();
  40.       }
  41.     }

  42.     return *std::max_element(primary_memo_.begin() + 1,
  43.                              primary_memo_.begin() + N);
  44.   }

  45. private:
  46.   inline std::int64_t getMemo(const std::int64_t key) const {
  47.     if (key < bound_) {
  48.       return primary_memo_[key];
  49.     } else {
  50.       auto it = secondary_memo_.find(key);
  51.       return it == secondary_memo_.end() ? -1 : it->second;
  52.     }
  53.   }

  54.   inline void setMemo(const std::int64_t key, const std::int64_t value) {
  55.     if (key < bound_) {
  56.       primary_memo_[key] = value;
  57.     } else {
  58.       secondary_memo_.emplace(key, value);
  59.     }
  60.   }

  61.   std::int64_t bound_;
  62.   std::vector<std::int64_t> primary_memo_;
  63.   std::unordered_map<std::int64_t, std::int64_t> secondary_memo_;
  64. };

  65. int main(int argc, char *argv[]) {
  66.   Solution s;
  67.   std::cout << s.exec(1000000) << "\n";

  68.   return 0;
  69. }
复制代码

评分

参与人数 1大米 +3 收起 理由
kqxqx + 3 多谢解惑!

查看全部评分

回复

使用道具 举报

🔗
cocaptainco 2017-12-21 15:22:05 | 只看该作者
全局:
自己用c++试了一下,确实是因为在113383 这个数overflow了, 然后就死循环了
回复

使用道具 举报

🔗
 楼主| kqxqx 2017-12-21 23:54:21 | 只看该作者
全局:
magicsets 发表于 2017-12-21 14:33
为了加速memoization表的存取可以用一个vector作为primary memo,一个unordered_map作为secondary memo

...

太感谢了!看来这个题目的坑主要就是N=1,000,000的时候中间需要计算的n会超过32位int的表示范围,我回去改了一下我的code,把int换成long型,其余的不变,recursion + memorization就能跑出正确的结果了。哎,怎么当时就没有想到是这个问题呢 anyway,当时的code确实没有跑出正确结果,只好move on了

补充内容 (2017-12-22 00:50):
N=100,000,则中间需要计算的最大n=1570824736,没超出int范围;
N=1,000,000,则最大n=56991483520,远超int范围。看来这个1,000,000的测试数据是精心挑选的,就是个坑。
回复

使用道具 举报

🔗
 楼主| kqxqx 2017-12-21 23:58:02 | 只看该作者
全局:
qiu_cqupt 发表于 2017-12-21 12:52
能问下大佬几年工作经验么?怎么我投A就被秒拒了

4年多一点
回复

使用道具 举报

🔗
yikehongxin 2017-12-27 06:37:54 | 只看该作者
全局:
kqxqx 发表于 2017-12-21 23:54
太感谢了!看来这个题目的坑主要就是N=1,000,000的时候中间需要计算的n会超过32位int的表示范围,我回去 ...

所以,正确答案是524是么?
回复

使用道具 举报

🔗
 楼主| kqxqx 2017-12-27 07:38:46 | 只看该作者
全局:
daguanyuan 发表于 2017-12-27 06:37
所以,正确答案是524是么?

我是按照525算的,初始条件1算1(指的是变化序列的长度)
回复

使用道具 举报

🔗
houpy 2017-12-27 08:09:40 | 只看该作者
全局:
kqxqx 发表于 2017-12-21 23:54
太感谢了!看来这个题目的坑主要就是N=1,000,000的时候中间需要计算的n会超过32位int的表示范围,我回去 ...

对,应该就是数据类型的问题,我用java 写了一下,也得改写数据类型才能得出525

不过要是可以用python写,可能真心就需要担心这个问题了。。。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表