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); }
当你看清人们的真相,于是你知道了,你可以忍受孤独