【发布时间】:2017-02-26 22:32:50
【问题描述】:
在识别指数运行时间时有一些特定的模式。例如,如果在数组中的每个元素处,指针可以进行一、二或三步,我们在记忆化之前查看 O(3^N) 数组,因为每个元素有三个函数调用。
但是,在记忆化之后识别运行时间背后的模式是什么,我有点困惑。一般来说,有什么关系?我知道记忆在做什么——只是摆脱重复的子调用,但在面试环境中,我不想画出一棵树并划掉所有重复的子调用来直观地了解运行时。有什么想法吗?
编辑:
例如,下面的问题蛮力是 O(3^N),记忆后是 O(n^3),我不知道如何直觉,或者我是否缺少潜在的模式。
一只青蛙正在过河。河流被分成 x 个单位,在 那里的每个单元可能存在也可能不存在石头。青蛙可以跳上 石头,但不能跳入水中。
给定一个按升序排列的石头位置列表(以单位为单位) 命令,确定青蛙是否能够通过登陆来过河 最后一块石头。最初,青蛙在第一块石头上并假设 第一次跳跃必须是 1 个单位。
如果青蛙的最后一次跳跃是 k 个单位,那么它的下一次跳跃必须是 k - 1、k 或 k + 1 个单位。请注意,青蛙只能在 前进方向
方法 #1 蛮力 [超过时间限制]
In the brute force approach, we make use of a recursive function canCrosscanCross which takes the given stone array, the current position and the current jumpsize as input arguments. We start with currentPosition=0 and jumpsize=0. Then for every function call, we start from the currentPosition and check if there lies a stone at (currentPostion + newjumpsize), where, the newjumpsize could be jumpsize, jumpsize+1 or jumpsize-1. In order to check whether a stone exists at the specified positions, we check the elements of the array in a linear manner. If a stone exists at any of these positions, we call the recursive function again with the same stone array, the currentPosition and the newjumpsize as the parameters. If we are able to reach the end of the stone array through any of these calls, we return true to indicate the possibility of reaching the end.
Java
public class Solution {
public boolean canCross(int[] stones) {
return can_Cross(stones, 0, 0);
}
public boolean can_Cross(int[] stones, int ind, int jumpsize) {
for (int i = ind + 1; i < stones.length; i++) {
int gap = stones[i] - stones[ind];
if (gap >= jumpsize - 1 && gap <= jumpsize + 1) {
if (can_Cross(stones, i, gap)) {
return true;
}
}
}
return ind == stones.length - 1;
}
}
Complexity Analysis
Time complexity : O(3^n)
Recursion tree can grow upto 3^n
Space complexity : O(n). Recursion of depth n is used.
记忆后:
public class Solution {
public boolean canCross(int[] stones) {
int[][] memo = new int[stones.length][stones.length];
for (int[] row : memo) {
Arrays.fill(row, -1);
}
return can_Cross(stones, 0, 0, memo) == 1;
}
public int can_Cross(int[] stones, int ind, int jumpsize, int[][] memo) {
if (memo[ind][jumpsize] >= 0) {
return memo[ind][jumpsize];
}
for (int i = ind + 1; i < stones.length; i++) {
int gap = stones[i] - stones[ind];
if (gap >= jumpsize - 1 && gap <= jumpsize + 1) {
if (can_Cross(stones, i, gap, memo) == 1) {
memo[ind][gap] = 1;
return 1;
}
}
}
memo[ind][jumpsize] = (ind == stones.length - 1) ? 1 : 0;
return memo[ind][jumpsize];
}
}
复杂性分析
Time complexity : O(n^3)
Memorization will reduce time complexity to O(n^3).
Space complexity : O(n^2)
memo matrix of size n^2 is used.
【问题讨论】:
标签: algorithm time-complexity memoization