• 汉诺塔I && II


    汉诺塔I

    题目链接:https://www.nowcoder.com/questionTerminal/7d6cab7d435048c4b05251bf44e9f185

    题目大意:

      略

    分析:

      利用汉诺塔与二进制的关系来做。

      如何用二进制解汉诺塔:https://www.bilibili.com/video/av7398130/

    代码如下:

     1 class Hanoi {
     2 public:
     3     // 计算x的二进制位数 
     4     inline int getBits(int x) {
     5         int cnt = 1;
     6         while(x >>= 1) ++cnt;
     7         return cnt;
     8     } 
     9     
    10     vector<string> getSolution(int n) {
    11         vector< string > ans;
    12         string s[3] = {"left", "mid", "right"};
    13         vector< int > arr;
    14         arr.resize(n, 0);
    15         // tot表示总移动次数
    16         int tot = (1 << n) - 1;
    17         int cnt = 0;
    18         while(cnt++ < tot) {
    19             int lowbit = cnt & (-cnt);
    20             int bitlen = getBits(lowbit) - 1;
    21             int b = 1 + (n - bitlen) % 2;// 偏移,b = 1往右,b = 2往左
    22             ans.push_back("move from " + s[arr[bitlen]] + " to " + s[(arr[bitlen] + b) % 3]);
    23             arr[bitlen] = (arr[bitlen] + b) % 3;
    24         }
    25         return ans;
    26     }
    27 };
    View Code

    汉诺塔II

    题目链接:https://www.nowcoder.com/questionTerminal/b2d552cd60b7415fad2612a32e799812?toCommentId=2927834

    题目大意:

      略

    分析:

    先给出4个盘子的表(三根柱子的序号分别为0, 1, 2):

    容易看出n个盘子需要移动2n次。

      首先我们看红线分割的两块,令8~15行的0号,1号,2号盘子的位置加上2再模3,他们的数值刚好等于0~7行的0号,1号,2号盘子的位置。

      再看绿线分割的0~7行,另4~7行的0号,1号盘子的位置加上1再模3,他们的数值刚好等于0~3行的0号,1号盘子的位置。

      发现规律了没有?

      比如有汉诺塔的位置序列[2, 1, 1, 2],序列最后一个数为2,于是step([2, 1, 1, 2])就等于1000B + step([(2 + 2) % 3, (1 + 2) % 3,  (1 + 2) % 3]) = 1000B + step([1, 0, 0]),然后step([1, 0, 0])的最后一个数为0,于是step([1, 0, 0]) = step([1, 0]),直接往前进,并不需要上移,同理step([1, 0]) = step([1]), 对于step([1]),只有一个数字,直接取值,所以step([2, 1, 1, 2])最终等于1001B

      再比如有汉诺塔的位置序列[2, 0, 1, 2],序列最后一个数为2,于是step([2, 0, 1, 2])就等于1000B + step([(2 + 2) % 3, (0 + 2) % 3,  (1 + 2) % 3]) = 1000B + step([1, 2, 0]),然后step([1, 2, 0])的最后一个数为0,于是step([1, 2, 0]) = step([1, 2]),step([1, 2])的最后一个数字是2,于是step([1, 2]) = 10B + step([(1 + 2) % 3]) = 10B + step([0]), 对于step([0]),只有一个数字,直接取值,所以step([2, 1, 1, 2])最终等于1010B

      简单来说,就是末尾数字为0,就不变;末尾数字不为0,就让前面的数字加上这个数字再模3,然后求子问题,同时要加上这一位的权值,比如它是第5个数字,就要加上10000B;如果是第3个数字,就要加上100B

      不要问我原理,我是结合二进制找规律找出来的。

    代码如下:

    1 class Hanoi {
    2 public:
    3     int chkStep(vector<int> &arr, int n, int b = 0) {
    4         if(n == 0) return 0;
    5         int tmp = (arr[n - 1] + b - 1) % 3 ;
    6         return (1 << (n - 1)) * (tmp != 0) + chkStep(arr, n - 1, b + tmp);
    7     }
    8 };
    View Code
  • 相关阅读:
    nginx article
    学习历程
    GRPC
    学习记录
    JAVA知识点记录
    flag
    读的文章
    This usually happens because your environment has changed since running `npm install`.
    expandedRowKeys、expandedRowsChange、expand
    服务端高并发分布式架构演进之路
  • 原文地址:https://www.cnblogs.com/zaq19970105/p/10759266.html
Copyright © 2020-2023  润新知