Java 如何在O(n)时间内找到到达数组末尾的最小跳跃次数 问题:
给定一个整数数组,其中每个元素表示可以从该元素向前执行的最大步数。 编写一个函数以返回到达目标的最小跳转次数 数组的结尾(从第一个元素开始)。如果元素是 0,则无法通过该元素移动 例子 输入:arr[]={1,3,5,8,9,2,6,7,6,8,9}Java 如何在O(n)时间内找到到达数组末尾的最小跳跃次数 问题:,java,arrays,algorithm,Java,Arrays,Algorithm,给定一个整数数组,其中每个元素表示可以从该元素向前执行的最大步数。 编写一个函数以返回到达目标的最小跳转次数 数组的结尾(从第一个元素开始)。如果元素是 0,则无法通过该元素移动 例子 输入:arr[]={1,3,5,8,9,2,6,7,6,8,9} 输出:3(1->3->8->9) 找到了多种从线性方法到其他线性方法的方法。我无法理解所谓的时间线性方法。是建议采用线性方法的链接 我一点也不懂。我能理解的是,作者建议采取贪婪的方法,看看我们是否能达到目的。。如果不是,那么回溯?站点上建议的解决方
输出:3(1->3->8->9) 找到了多种从线性方法到其他线性方法的方法。我无法理解所谓的时间线性方法。是建议采用线性方法的链接
我一点也不懂。我能理解的是,作者建议采取贪婪的方法,看看我们是否能达到目的。。如果不是,那么回溯?站点上建议的解决方案的时间复杂度是线性的,因为您只在数组上迭代一次。通过使用一些巧妙的技巧,该算法避免了我提出的解决方案的内部迭代 变量
maxReach
始终存储数组中的最大可达位置<代码>跳跃存储到达该位置所需的跳跃量step
存储我们仍然可以执行的步数(并用第一个数组位置的步数初始化)
在迭代过程中,上述值更新如下:
首先,我们测试是否已经到达数组的末尾,在这种情况下,我们只需要返回jump
变量
接下来我们更新最大可达位置。这等于maxReach
和i+A[i]
的最大值(我们可以从当前位置执行的步数)
我们使用了一个步骤来获取当前索引,因此必须减少步骤
如果没有剩余的步骤(即steps=0
,则我们必须使用跳转。因此,增加jump
。因为我们知道可以以某种方式达到maxReach
,我们将步骤初始化为从i
位置达到maxReach
的步骤量
public class Solution {
public int jump(int[] A) {
if (A.length <= 1)
return 0;
int maxReach = A[0];
int step = A[0];
int jump = 1;
for (int i = 1; i < A.length; i++) {
if (i == A.length - 1)
return jump;
if (i + A[i] > maxReach)
maxReach = i + A[i];
step--;
if (step == 0) {
jump++;
step = maxReach - i;
}
}
return jump;
}
}
我的次优算法在O(nk)
时间内工作,数组中的元素数n
和k
是数组中最大的元素,并在array[i]
上使用一个内部循环。下面的算法避免了这个循环
代码
public static int minimum_steps(int[] array) {
int[] min_to_end = new int[array.length];
for (int i = array.length - 2; i >= 0; --i) {
if (array[i] <= 0)
min_to_end[i] = Integer.MAX_VALUE;
else {
int minimum = Integer.MAX_VALUE;
for (int k = 1; k <= array[i]; ++k) {
if (i + k < array.length)
minimum = Math.min(min_to_end[i+k], minimum);
else
break;
}
min_to_end[i] = minimum + 1;
}
}
return min_to_end[0];
}
公共静态int最小_步数(int[]数组){
int[]min_to_end=新的int[array.length];
对于(int i=array.length-2;i>=0;--i){
if(数组[i]这里是另一个线性解决方案。代码比leet代码链接中建议的要长,但我认为更容易理解。它基于两个观察结果:达到I+1
位置所需的步骤数绝不少于达到I
位置和每个元素所需的步骤数每个元素将其值+1分配给i+1…i+a[i]
段
public class Solution {
public int jump(int[] a) {
int n = a.length;
// count[i] is the number of "open" segments with value i
int[] count = new int[n];
// the number of steps to reach the i-th position
int[] dp = new int[n];
Arrays.fill(dp, n);
// toDelete[i] is the list of values of segments
// that close in the i-th position
ArrayList<Integer>[] toDelete = new ArrayList[n];
for (int i = 0; i < n; i++)
toDelete[i] = new ArrayList<>();
// Initially, the value is 0(for the first element).
toDelete[0].add(0);
int min = 0;
count[0]++;
for (int i = 0; i < n; i++) {
// Finds the new minimum. It uses the fact that it cannot decrease.
while (min < n && count[min] == 0)
min++;
// If min == n, then there is no path. So we can stop.
if (min == n)
break;
dp[i] = min;
if (dp[i] + 1 < n) {
// Creates a new segment from i + 1 to i + a[i] with dp[i] + 1 value
count[dp[i] + 1]++;
if (i + a[i] < n)
toDelete[i + a[i]].add(dp[i] + 1);
}
// Processes closing segments in this position.
for (int deleted : toDelete[i])
count[deleted]--;
}
return dp[n - 1];
}
}
公共类解决方案{
公共整数跳转(整数[]a){
int n=a.长度;
//count[i]是值为i的“开放”段数
int[]计数=新的int[n];
//到达第i个位置的步数
int[]dp=新的int[n];
数组填充(dp,n);
//toDelete[i]是段的值列表
//在第i个位置接近
ArrayList[]toDelete=新的ArrayList[n];
对于(int i=0;i
复杂性分析:
toDelete
列表中的元素总数为O(n)
。这是因为在每个位置i
最多添加一个元素。这就是为什么处理所有toDelete
列表中的所有元素需要线性时间
min
值只能增加。这就是为什么内部while
循环总共最多进行n次迭代
外部for
循环显然会进行n
迭代,因此时间复杂度是线性的
派对晚了几年,但这里有另一个对我来说有意义的O(n)解决方案
/// <summary>
///
/// The actual problem is if it's worth not to jump to the rightmost in order to land on a value that pushes us further than if we jumped on the rightmost.
///
/// However , if we approach the problem from the end, we go end to start,always jumping to the leftmost
///
/// with this approach , these is no point in not jumping to the leftmost from end to start , because leftmost will always be the index that has the leftmost leftmost :) , so always choosing leftmost is the fastest way to reach start
///
/// </summary>
/// <param name="arr"></param>
static void Jumps (int[] arr)
{
var LeftMostReacher = new int[arr.Length];
//let's see , for each element , how far back can it be reached from
LeftMostReacher[0] = -1; //the leftmost reacher of 0 is -1
var unReachableIndex = 1; //this is the first index that hasn't been reached by anyone yet
//we use this unReachableIndex var so each index's leftmost reacher is the first that was able to jump to it . Once flagged by the first reacher , new reachers can't be the leftmost anymore so they check starting from unReachableIndex
// this design insures that the inner loop never flags the same index twice , so the runtime of these two loops together is O(n)
for (int i = 0; i < arr.Length; i++)
{
int maxReach = i + arr[i];
for (; unReachableIndex <= maxReach && unReachableIndex < arr.Length; unReachableIndex++)
{
LeftMostReacher[unReachableIndex] = i;
}
}
// we just go back from the end and then reverse the path
int index = LeftMostReacher.Length - 1;
var st = new Stack<int>();
while (index != -1)
{
st.Push(index);
index = LeftMostReacher[index];
}
while (st.Count != 0)
{
Console.Write(arr[st.Pop()] + " ");
}
Console.WriteLine();
}
static void Main ()
{
var nrs = new[] { 1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9 };
Jumps(nrs);
}
//
///
///实际的问题是,如果不跳到最右边是为了得到一个比跳到最右边更能推动我们前进的值,这是否值得。
///
///然而,如果我们从头开始解决问题,我们就会从头到脚,总是跳到最左边
///
///使用这种方法,不从一端跳到另一端是没有意义的,因为最左边的索引总是包含最左边的:),所以总是选择最左边是到达起点的最快方法
///
///
///
静态空跳(int[]arr)
{
var LeftMostReacher=新整数[arr.Length];
//让我们看看,对于每一个元素,它可以到达的距离有多远
LeftMostReacher[0]=-1;//最左边的访问器
/// <summary>
///
/// The actual problem is if it's worth not to jump to the rightmost in order to land on a value that pushes us further than if we jumped on the rightmost.
///
/// However , if we approach the problem from the end, we go end to start,always jumping to the leftmost
///
/// with this approach , these is no point in not jumping to the leftmost from end to start , because leftmost will always be the index that has the leftmost leftmost :) , so always choosing leftmost is the fastest way to reach start
///
/// </summary>
/// <param name="arr"></param>
static void Jumps (int[] arr)
{
var LeftMostReacher = new int[arr.Length];
//let's see , for each element , how far back can it be reached from
LeftMostReacher[0] = -1; //the leftmost reacher of 0 is -1
var unReachableIndex = 1; //this is the first index that hasn't been reached by anyone yet
//we use this unReachableIndex var so each index's leftmost reacher is the first that was able to jump to it . Once flagged by the first reacher , new reachers can't be the leftmost anymore so they check starting from unReachableIndex
// this design insures that the inner loop never flags the same index twice , so the runtime of these two loops together is O(n)
for (int i = 0; i < arr.Length; i++)
{
int maxReach = i + arr[i];
for (; unReachableIndex <= maxReach && unReachableIndex < arr.Length; unReachableIndex++)
{
LeftMostReacher[unReachableIndex] = i;
}
}
// we just go back from the end and then reverse the path
int index = LeftMostReacher.Length - 1;
var st = new Stack<int>();
while (index != -1)
{
st.Push(index);
index = LeftMostReacher[index];
}
while (st.Count != 0)
{
Console.Write(arr[st.Pop()] + " ");
}
Console.WriteLine();
}
static void Main ()
{
var nrs = new[] { 1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9 };
Jumps(nrs);
}
ar=[1, 3, 6, 3, 2, 3, 6, 8, 9, 5]
minJumpIdx=0
res=[0]*len(ar)
i=1
while(i<len(ar) and i>minJumpIdx):
if minJumpIdx+ar[minJumpIdx]>=i:
res[i]=res[minJumpIdx]+1
i+=1
else:
minJumpIdx+=1
if res[-1]==0:
print(-1)
else:
print(res[-1])
def minJump(a):
end=len(a)
count=0
i=a[0]
tempList1=a
while(i<=end):
if(i==0):
return 0
tempList1=a[count+1:count+i+1]
max_index=a.index(max(tempList1))
count+=1
i=a[max_index]
end=end-max_index
return count+1
static void minJumps(int a[] , int n)
{
int dp[] = new int[n];
dp[0] = 0; //As the min jumps needed to get to first index is zero only.
//Fill the rest of the array with INT_MAX val so we can make math.min comparisions.
for(int i=1;i<n;i++)
dp[i] = Integer.MAX_VALUE;
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{ //If we have enough jumps from the position j to reach i.
if(j+a[j]>=i)
{ //Take the min of current stored value & jumps req to
//reach i from j by getting jumps req to reach j plus 1.
//(Plus 1 because since we have enough jumps to reach 1 from j we
//simply add 1 by taking the jumps required to reach j.)
dp[i] = Math.min(dp[i],dp[j]+1);
}
}
}
//If first element has zero jumps in store or if the final jumps value
//becomes MAX value because there's an element in between which gives zero
//jumps.
if(a[0]==0 || dp[n-1] == Integer.MAX_VALUE )
System.out.println("-1");
else System.out.println(dp[n-1]);
}
public class Solution {
public int jump(int[] A) {
if (A.length <= 1)
return 0;
int maxReach = A[0];
int step = A[0];
int jump = 1;
for (int i = 1; i < A.length; i++) {
if (i == A.length - 1)
return jump;
if (i + A[i] > maxReach)
maxReach = i + A[i];
step--;
if (step == 0) {
jump++;
step = maxReach - i;
}
}
return jump;
}
}
Input Array : {1, 3, 5, 9, 6, 2, 6, 7, 6, 8, 9} -> index position starts with 0
Steps :
Initial step is considering the first index and incrementing the jump
Jump = 1
1, { 3, 5, 9, 6, 2, 6, 7, 6, 8, 9} -> 1 is considered as a first jump
next step
From the initial step there is only one step to move so
Jump = 2
1,3, { 5, 9, 6,2, 6, 7, 6, 8, 9} -> 1 is considered as a first jump
next step
Now we have a flexibility to choose any of {5,9,6} because of last step says we can move upto 3 steps
Consider it as a subarray, evaluate the max distance covers with each index position
As {5,9,6} index positions are {2,3,4}
so the total farther steps we can cover:
{7,12,10} -> we can assume it as {7,12} & {10} are 2 sub arrays where left part of arrays says max distance covered with 2 steps and right side array says max steps cover with remaining values
next step:
Considering the maximum distanc covered in first array we iterate the remaining next elements
1,3,9 {6,2, 6, 7, 6, 8, 9}
From above step ww already visited the 4th index we continue with next 5th index as explained above
{6,2, 6, 7, 6, 8, 9} index positions {4,5,6,7,8,9,10}
{10,7,12,14,14,17,19}
Max step covers here is 19 which corresponding index is 10
//
// Created by Praveen Kanike on 07/12/20.
//
#include <iostream>
using namespace std;
// Returns minimum number of jumps
// to reach arr[n-1] from arr[0]
int minJumps(int arr[], int n)
{
// The number of jumps needed to
// reach the starting index is 0
if (n <= 1)
return 0;
// Return -1 if not possible to jump
if (arr[0] == 0)
return -1;
// stores the number of jumps
// necessary to reach that maximal
// reachable position.
int jump = 1;
// stores the subarray last index
int subArrEndIndex = arr[0];
int i = 1;
//maximum steps covers in first half of sub array
int subArrFistHalfMaxSteps = 0;
//maximum steps covers in second half of sub array
int subArrSecondHalfMaxSteps =0;
// Start traversing array
for (i = 1; i < n;) {
subArrEndIndex = i+subArrEndIndex;
// Check if we have reached the end of the array
if(subArrEndIndex >= n)
return jump;
int firstHalfMaxStepIndex = 0;
//iterate the sub array and find out the maxsteps cover index
for(;i<subArrEndIndex;i++)
{
int stepsCanCover = arr[i]+i;
if(subArrFistHalfMaxSteps < stepsCanCover)
{
subArrFistHalfMaxSteps = stepsCanCover;
subArrSecondHalfMaxSteps = 0;
firstHalfMaxStepIndex = i;
}
else if(subArrSecondHalfMaxSteps < stepsCanCover)
{
subArrSecondHalfMaxSteps = stepsCanCover;
}
}
if(i > subArrFistHalfMaxSteps)
return -1;
jump++;
//next subarray end index and so far calculated sub array max step cover value
subArrEndIndex = arr[firstHalfMaxStepIndex];
subArrFistHalfMaxSteps = subArrSecondHalfMaxSteps;
}
return -1;
}
// Driver program to test above function
int main()
{
int arr[] = {100, 3, 5, 9, 6, 2, 6, 7, 6, 8, 9};
int size = sizeof(arr) / sizeof(int);
// Calling the minJumps function
cout << ("Minimum number of jumps to reach end is %d ",
minJumps(arr, size));
return 0;
}