• Leetcode935 骑士拨号器


    * @Description 问题为骑士跳 N 步有多少种跳法
    * 我们以步数 N 分割问题,此时发现,影响问题解的不只是步数,还在于骑士当前处在什么位置
    * 因为这决定了骑士下一步会不会越界
    * 所以我们以骑士所处的位置 x,y 以及剩余跳的步数 n 来定义问题
    * g(x,y,n) 表示处在 x,y 位置的骑士跳 n 步有多少种跳法
    * 首先可以肯定的是,x,y,n 三个纬度可以唯一确定一个解,那么我们再来尝试推演状态转移关系
    * 如果存在正确的状态转移关系,则该定义可用
    * 明显的,状态转移关系为:
    * g(x,y,n)=g(x-1,y-2,n-1)+g(x+1,y-2,n-1)+g(x+2,y-1,n-1)+g(x+2,y+1,n-1)+g(x+1,y+2,n-1)
    * +g(x-1,y+2,n-1)+g(x-2,y+1,n-1)+g(x-2,y-1,n-1)
    * 在号码盘上,我们要首先判断越界,再处理回归边界
    * x>2 , y>3 ,(0,0),(2,0) 为越界情况
    * n = 0 为 回归条件,回归 1
    * 解空间为一颗 8 叉树(暂且这么叫吧),每一层的 8 个节点发散下去后,难免存在与同层其他节点发散到相同子问题的情况,
    * 事实上该情况还比较多
    * 那么建立缓存可以很好的帮助我们避免重复计算,或者换句话说,该问题定义方式帮我们找出了许多解空间中可重复利用的部分
    * 对时间复杂度要求不是很极端的话,该思路应该可以通过

      BigInteger mod = new BigInteger("1000000007");
    
        public int knightDialer(int N) {
            if (N == 0) {
                return 0;
            }
            Map<String, BigInteger> cache = new HashMap<String, BigInteger>();
            BigInteger re = new BigInteger("0");
            for (int x = 0; x < 3; x++) {
                for (int y = 0; y < 4; y++) {
                    re = re.add(g(x, y, N - 1, cache));
                }
            }
            return re.mod(mod).intValue();
        }
    
        public final BigInteger g(int x, int y, int n, Map<String, BigInteger> cache) {
            if (x < 0 || y < 0 || x > 2 || y > 3 || (x == 2 && y == 0) || (x == 0 && y == 0)) {
                return new BigInteger("0");
            }
            if (n == 0) {
                return new BigInteger("1");
            }
            String key = String.valueOf(x) + "|" + String.valueOf(y) + "|" + String.valueOf(n);
            if (cache.keySet().contains(key)) {
                return cache.get(key);
            }
            BigInteger re = new BigInteger("0");
            re = re.add(g(x - 1, y + 2, n - 1, cache));
            re = re.add(g(x + 1, y + 2, n - 1, cache));
            re = re.add(g(x + 2, y + 1, n - 1, cache));
            re = re.add(g(x + 2, y - 1, n - 1, cache));
            re = re.add(g(x + 1, y - 2, n - 1, cache));
            re = re.add(g(x - 1, y - 2, n - 1, cache));
            re = re.add(g(x - 2, y - 1, n - 1, cache));
            re = re.add(g(x - 2, y + 1, n - 1, cache));
            cache.put(key, re);
            return re;
        }

      优化为递推:

    public final int knightDialer(int N) {
            int mod = 1000000007;
            long[] array = new long[10];
            Arrays.fill(array, 1);
            for(int n = 2; n <= N; n++) {
                long a1 = array[6] + array[8];
                long a2 = array[7] + array[9];
                long a3 = array[4] + array[8];
                long a4 = array[3] + array[9] + array[0];
                long a6 = array[1] + array[7] + array[0];
                long a7 = array[2] + array[6];
                long a8 = array[1] + array[3];
                long a9 = array[4] + array[2];
                long a0 = array[4] + array[6];
                array[0] = a0 % mod;
                array[1] = a1 % mod;
                array[2] = a2 % mod;
                array[3] = a3 % mod;
                array[4] = a4 % mod;
                array[5] = 0;
                array[6] = a6 % mod;
                array[7] = a7 % mod;
                array[8] = a8 % mod;
                array[9] = a9 % mod;
            }
            long sum = 0;
            for(long a : array) {
                sum += a;
            }
            return (int)(sum % mod);
        }
  • 相关阅读:
    C# sqlhelp
    vs2015 C#打包程序为exe
    python3.6安装docx模块
    python 第八天
    python 第七天
    python 选课系统
    python 第六天
    python 模拟实现一个ATM + 购物商城程序
    python 计算器
    python 第五天
  • 原文地址:https://www.cnblogs.com/niuyourou/p/12960888.html
Copyright © 2020-2023  润新知