we can start the loop from the len(nums) - 2 position since goal is already set at the last position when we declare it.
Thanks!
12:00 jaw dropping intuition, I could have never thought about it. Thanks for the explanation.
There is no need to start from the end and move backwards. You can naturally progress from the beginning, like this: int reach = 0; for (int i = 0; i < nums.length && i <= reach; i++) reach = Math.max(reach, i+nums[i]); return reach >= nums.length-1;
The tricky part of the greedy is to prove that it actually works; we clearly have multiple options for moving the goal and we always pick the first one. How do we guarantee that we are not going to get stuck using this approach?
Funnily enough I did the opposite of your sliding the goal approach by keeping track of your maximum remaining jump at current position. This allows early returning with a fail code instead of having to parse the whole array. in c#: public bool CanJump(int[] nums) { int j = 1; for (int i = 0; i < nums.Length - 1; i++) { j--; if (nums[i] > j) j = nums[i]; if (j == 0) return false; } return true; }
that explanation for greedy part was just awesome🔥🔥
greedy approach is brilliant. love it
These are the questions/solutions that make me fall in love with algorithms :) many many thanks @NeetCode
thats an awesome solution and explination!! I thought of an answer where we only stop our iteration once we come upon a zero. then we just check if we can if the zero can be jumped over by previous elements. the only problem is the edge case where nums= [0],where you got check for it. var jump = function (nums) { if (nums.length === 1) return true; let prevPosition, prevValue; let passFlag = true; for (let i = 0; i < nums.length - 1; i++) { if (nums[i] === 0) { passFlag = false; prevPosition = i - 1; while (prevPosition >= 0) { prevValue = nums[prevPosition]; if (prevPosition + prevValue > i) { passFlag = true; break; } prevPosition--; } if (!passFlag) return false; } } return true; };
Glad I watched the visual for the idea behind the greedy sol. My first idea was to use the BFS, with a visited array. then I optimized to use the input array as visited, but the runtime and memory was high among other submissions in leetcode. Then I found the greedy solution, and I wanted to know why and how of it. This video explains it.
I love how simple the solution is. I was sketching out a very complex one :D
For anyone who is interested in the dp solution ( C++ version). bool dfsJump(vector<int>& nums, int i, vector<int>& cache) { if (i >= nums.size() - 1) { // reaches or beyond last element return true; } if (cache[i] != -1) { return cache[i]; } // starts from i, maximum can jump for (int j = 1; j <= nums[i]; j++) { if (dfsJump(nums, i + j, cache)) { return true; } } cache[i] = false; return false; } bool canJump(vector<int>& nums) { vector<int> dp(nums.size(), -1); return dfsJump(nums, 0, dp); }
This channel is so much underrated. This video is just amazing!
You and Tech Dose are my go to for leetcodes.
Great Explanation! Thx for making it clearer for greedy algorithm
That greedy solution is ingenius. I am in awe!! Thank you.
Alternative: 1) Start on the right 2) Go to the left, skip all non-zeros 3) On each zero, find any position on the left that can skip it - i.e. larger than the distance from it 4) If there's none, return false 5) If there's any, continue from there, to the point 2) 6) Return true when reaching the left end.
The if condition can be modified to If nums [i] >= goal - i i.e if the value at the current index is greater than or equal to the difference between the goal and the index For better understanding 😄 thank you
@davidbanda4727