给定一个大小为N的排序数组arr[] ,任务是通过跳转arr[i] + k – 1 , arr[i] +来检查是否有可能从arr[1] 到达给定数组的末尾k,或arr[i] + k + 1在每一步,其中k代表在上一步中跳跃的索引数。最初考虑K = 1 。如果可能,则打印“是” 。否则,打印“否” 。
例子:
Input: arr[] = {0, 1, 3, 5, 6, 8, 12, 17}
Output: Yes
Explanation:
Step 1: Take (k + 1 = 2) steps to move to index containing A[1] + 2 = 3
Step 2: Take (k = 2) steps to move to index containing A[2] + 2 = 5.
Step 3: Take (k + 1 = 3) steps to move to index containing A[3] + 3 = 8
Step 4: Take (k + 1 = 4) steps to move to index containing A[5] + 4 = 12
Step 4: Take (k + 1 = 5) steps to move to index containing A[6] + 5 = 17
Since the last array index contains 17, the end of the array is reached.
Input: arr[] = {0, 1, 2, 3, 4, 8, 9, 11}
Output: No
朴素的方法:这个想法是使用递归。从索引i递归移动到值为A[i] + K – 1、A[i] + K或A[i] + K + 1 的索引,并检查是否有可能到达终点。如果存在任何到达终点的路径,则打印“是”,否则打印“否” 。
时间复杂度: O(2 N )
辅助空间: O(1)
高效的方法:为了优化上述方法,思想是使用动态规划。创建一个二维表memo[N][N]来存储记忆的结果。对于任何索引(i, j) , memo[i][j]表示是否可以从索引i移动到结尾(N-1)和之前采取的j步。 memo[i][j] = 1表示可能, memo[i][j] = 0表示不可能。请按照以下步骤解决问题:
- 创建一个大小为N*N的记忆表memo[][] 。
- 对于任何索引(i, j)更新memo[][]表,如下所示:
- 如果i等于(N – 1) ,则在到达结束位置时返回 1。
- 如果备忘录[i] [j]已经计算出,然后返回备忘录[i] [j]。
- 检查具有A[i] + j、A[i] + j – 1或A[i] + j + 1值的任何索引,并递归检查是否有可能到达终点。
- 将值存储在memo[i][j] 中并返回值。
- 如果可以到达终点,则打印“Yes” 。
- 否则,打印“否” 。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
#define N 8
// Utility function to check if it is
// possible to move from index 1 to N-1
int check(int memo[][N], int i,
int j, int* A)
{
// memo[i][j]: Stores if it is
// possible to move from index i
// to end(N-1) previously j steps
// Successfully reached end index
if (i == N - 1)
return 1;
// memo[i][j] is already calculated
if (memo[i][j] != -1)
return memo[i][j];
// Check if there is any index
// having value of A[i]+j-1,
// A[i]+j or A[i]+j+1
int flag = 0, k;
for (k = i + 1; k < N; k++) {
// If A[k] > A[i] + j + 1,
// can't make a move further
if (A[k] - A[i] > j + 1)
break;
// It's possible to move A[k]
if (A[k] - A[i] >= j - 1
&& A[k] - A[i] <= j + 1)
// Check is it possible to
// move from index k
// having previously taken
// A[k] - A[i] steps
flag = check(memo, k,
A[k] - A[i], A);
// If yes then break the loop
if (flag)
break;
}
// Store value of flag in memo
memo[i][j] = flag;
// Return memo[i][j]
return memo[i][j];
}
// Function to check if it is possible
// to move from index 1 to N-1
void checkEndReach(int A[], int K)
{
// Stores the memoized state
int memo[N][N];
// Initialize all values as -1
memset(memo, -1, sizeof(memo));
// Initially, starting index = 1
int startIndex = 1;
// Function call
if (check(memo, startIndex, K, A))
cout << "Yes";
else
cout << "No";
}
// Driver Code
int main()
{
int A[] = { 0, 1, 3, 5, 6,
8, 12, 17 };
int K = 1;
// Function Call
checkEndReach(A, K);
return 0;
}
Java
// Java program for the above approach
import java.io.*;
class GFG{
static int N = 8;
// Utility function to check if it is
// possible to move from index 1 to N-1
static int check(int[][] memo, int i,
int j, int[] A)
{
// memo[i][j]: Stores if it is
// possible to move from index i
// to end(N-1) previously j steps
// Successfully reached end index
if (i == N - 1)
return 1;
// memo[i][j] is already calculated
if (memo[i][j] != -1)
return memo[i][j];
// Check if there is any index
// having value of A[i]+j-1,
// A[i]+j or A[i]+j+1
int flag = 0, k;
for(k = i + 1; k < N; k++)
{
// If A[k] > A[i] + j + 1,
// can't make a move further
if (A[k] - A[i] > j + 1)
break;
// It's possible to move A[k]
if (A[k] - A[i] >= j - 1 &&
A[k] - A[i] <= j + 1)
// Check is it possible to
// move from index k
// having previously taken
// A[k] - A[i] steps
flag = check(memo, k, A[k] - A[i], A);
// If yes then break the loop
if (flag != 0)
break;
}
// Store value of flag in memo
memo[i][j] = flag;
// Return memo[i][j]
return memo[i][j];
}
// Function to check if it is possible
// to move from index 1 to N-1
static void checkEndReach(int A[], int K)
{
// Stores the memoized state
int[][] memo = new int[N][N];
// Initialize all values as -1
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
{
memo[i][j] = -1;
}
}
// Initially, starting index = 1
int startIndex = 1;
// Function call
if (check(memo, startIndex, K, A) != 0)
System.out.println("Yes");
else
System.out.println("No");
}
// Driver Code
public static void main(String[] args)
{
int[] A = { 0, 1, 3, 5, 6, 8, 12, 17 };
int K = 1;
// Function Call
checkEndReach(A, K);
}
}
// This code is contributed by akhilsaini
Python3
# Python3 program for the above approach
N = 8
# Utility function to check if it is
# possible to move from index 1 to N-1
def check(memo, i, j, A):
# memo[i][j]: Stores if it is
# possible to move from index i
# to end(N-1) previously j steps
# Successfully reached end index
if (i == N - 1):
return 1
# memo[i][j] is already calculated
if (memo[i][j] != -1):
return memo[i][j]
# Check if there is any index
# having value of A[i]+j-1,
# A[i]+j or A[i]+j+1
flag = 0
for k in range(i + 1, N):
# If A[k] > A[i] + j + 1,
# can't make a move further
if (A[k] - A[i] > j + 1):
break
# It's possible to move A[k]
if (A[k] - A[i] >= j - 1 and
A[k] - A[i] <= j + 1):
# Check is it possible to
# move from index k
# having previously taken
# A[k] - A[i] steps
flag = check(memo, k,
A[k] - A[i], A)
# If yes then break the loop
if (flag != 0):
break
# Store value of flag in memo
memo[i][j] = flag
# Return memo[i][j]
return memo[i][j]
# Function to check if it is possible
# to move from index 1 to N-1
def checkEndReach(A, K):
# Stores the memoized state
memo = [[0] * N] * N
# Initialize all values as -1
for i in range(0, N):
for j in range(0, N):
memo[i][j] = -1
# Initially, starting index = 1
startIndex = 1
# Function call
if (check(memo, startIndex, K, A) != 0):
print("Yes")
else:
print("No")
# Driver Code
if __name__ == '__main__':
A = [ 0, 1, 3, 5, 6, 8, 12, 17 ]
K = 1
# Function Call
checkEndReach(A, K)
# This code is contributed by akhilsaini
C#
// C# program for the above approach
using System;
class GFG{
static int N = 8;
// Utility function to check if it is
// possible to move from index 1 to N-1
static int check(int[,] memo, int i,
int j, int[] A)
{
// memo[i][j]: Stores if it is
// possible to move from index i
// to end(N-1) previously j steps
// Successfully reached end index
if (i == N - 1)
return 1;
// memo[i][j] is already calculated
if (memo[i, j] != -1)
return memo[i, j];
// Check if there is any index
// having value of A[i]+j-1,
// A[i]+j or A[i]+j+1
int flag = 0, k;
for(k = i + 1; k < N; k++)
{
// If A[k] > A[i] + j + 1,
// can't make a move further
if (A[k] - A[i] > j + 1)
break;
// It's possible to move A[k]
if (A[k] - A[i] >= j - 1 &&
A[k] - A[i] <= j + 1)
// Check is it possible to
// move from index k
// having previously taken
// A[k] - A[i] steps
flag = check(memo, k, A[k] - A[i], A);
// If yes then break the loop
if (flag != 0)
break;
}
// Store value of flag in memo
memo[i, j] = flag;
// Return memo[i][j]
return memo[i, j];
}
// Function to check if it is possible
// to move from index 1 to N-1
static void checkEndReach(int[] A, int K)
{
// Stores the memoized state
int[,] memo = new int[N, N];
// Initialize all values as -1
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
{
memo[i, j] = -1;
}
}
// Initially, starting index = 1
int startIndex = 1;
// Function call
if (check(memo, startIndex, K, A) != 0)
Console.WriteLine("Yes");
else
Console.WriteLine("No");
}
// Driver Code
public static void Main()
{
int[] A = { 0, 1, 3, 5, 6, 8, 12, 17 };
int K = 1;
// Function Call
checkEndReach(A, K);
}
}
// This code is contributed by akhilsaini
Javascript
Yes
时间复杂度: O(N 3 )
辅助空间: O(N 2 )
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。