Fastrail08

(Leetcode 300) LIS (V.IMPORTANT) INITIAL ANALYSIS FOR JUMP DP STATE REDUCTION WITH LOOP & BS

Jul 20th, 2025
357
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.08 KB | None | 0 0
  1. class Solution {
  2. public:
  3.     int getLIS(int level, vector<int> &nums, vector<int> &memo){
  4.         if(level >= nums.size()){
  5.             return 0;
  6.         }
  7.         //ALWAYS INCLUDE THE ELEMENT OF THE CURRENT LEVEL (INCLUDING GIVES THE LONGEST CHAIN, by increasing length by 1 always)
  8.         //element itself is a VALID SUBSEQUENCE OF LENGTH 1 (VALID = PROPERTY HOLDS)
  9.  
  10.         //******IMPORTANT
  11.         //THIS length = 1, is for the case where the LOOP NEVER RUNS(no j > i, where nums[j] > nums[i]), IF THE LOOP NEVER RUNS length = 1
  12.         // Length should 1, if loop never runs, as that makes sure that there is no other VALID LEVEL TO JUMP TO,
  13.         //but the CURRENT LEVEL ELEMENT MUST BE INCLUDED, no matter if it calls forward or not, as it is VALID LEVEL
  14.         //(we must have jumped to this level from some previous level) and WE ARE INCLUDING EVERY LEVEL's element we jump to
  15.         //USE BOOL flag for more clarity.
  16.         //bool loopRan = false;
  17.         //if the flag becomes true; if loop runs make this true, which ensures that this level must have called forward somewhere,
  18.         //and the length will  be correctly counted by doing 1 + getLIS().
  19.         //But if flag is false, then it is LAST VALID LEVEL, and it should be added to the subsequence explicitly by returning 1.
  20.         /*
  21.         So
  22.         bool loopRan = false;
  23.         loop(){
  24.             loopRan = true;
  25.         }
  26.         return memo[level] = loopRan ? length : 1;
  27.         */
  28.         int length = 1;
  29.         //include
  30.         //directly jump to next valid level (some level j, where nums[j] > nums[i], j > i)
  31.         //it reduces the state memo(level, lastIdx) to memo(level)
  32.  
  33.         //we needed lastIdx to take decision if current element can be included or not
  34.         //But with the help of LOOP we directly JUMP to next VALID INDEX
  35.         //IT IS LIKE THAT JUMP DP, where we directly jump to JUST NEXT VALID INDEX with the help of Binary Search
  36.         //Here we CAN'T use Binary Search as the array is NOT in SORTED ORDER and we CAN'T SORT the array, as we need to find Longest Increasing SUBSEQUENCE
  37.         //SUBSEQUENCE IS ORDER DEPENDENT, ELEMENT MUST BE PICKED IN THE SAME ORDER AS THEY APPEAR IN THE ARRAY
  38.         //SUBSET IS ORDER INDEPENDENT, ELEMENT CAN BE PICKED IN ANY ORDER IRRESPECTIVE OF THEIR ORDER IN THE ARRAY
  39.         //So we want to find SUBSEQUENCE, so we can't sort, BUT we can LOOP INSTEAD.
  40.         // WE USED BINARY SEARCH TO DIRECTLY JUMP TO THE NEXT VALID LEVEL, which REDUCES THE NEED FOR lastIdx, as we are ALWAYS ON A VALID LEVEL
  41.         //IF you can SORT THE ARRAY, USE BINARY SEARCH TO DO THE JUMP(log(n)) BUT if you CAN'T SORT the array, USE LOOP(O(n))
  42.         //With LOOP as with BINARY SEARCH, WE GUARANTEE THAT WE ONLY EXPLORE VALID LEVELS ONLY, so no need to check if current element can be included
  43.         // YOU WILL ALWAYS HAVE BOTH OPTIONS AS VALID (at every level, you can always INCLUDE and EXCLUDE)
  44.         // Earlier we always have to check if can INCLUDE the CURRENT LEVEL ELEMENT with the help of conditional (nums[level] > nums[lastIdx])
  45.         //Now no CONDITIONAL is needed, as we can explore both the options at EVERY LEVEL we go to, as we are only jumping to a level with both options enabled.
  46.         //NO conditional was being used to explore the option to exclude, as excluding the CURRENT LEVEL ELEMENT from the SUBSEQUENCE doesn't violate the property of subsequence
  47.         //As we are going to exclude the element from the subsequence, it won't violate ...
  48.         //CONDITIONAL is only NEEDED when we are going to INCLUDE the CURRENT LEVEL ELEMENT into the subsequence, because the element that is going to be included in the subsequence
  49.         //should be larger than the element that was previously included in the subsequence.
  50.         //But while exploring the options, we do level + 1 BLINDLY, and check at every LEVEL, whether to explore the include option or not.
  51.         //We only explore INCLUDE option, when adding the element doesn't violate the property of subset(a1 < a2 < a3)
  52.         // BUT with the help of LOOP(JUST AS WITH BINARY SEARCH), we make SURE to not explore INVALID LEVELS.
  53.         //WE ONLY MOVE TO THOSE LEVELS, WHICH HAVE BOTH OPTIONS AS VALID, so we can explore BOTH. So whatever level we go to, we can exclude the element(doesn't violate the property anyway)
  54.         // and we can also EXPLORE the OPTION to include the element WITHTOUT NEEDING TO USE A CONDITIONAL(nums[j] > nums[i], j > i), as WITH THE HELP OF THE LOOP,
  55.         // WE ONLY GO TO THOSE LEVELS at which the PROPERTY OF THE SUBSEQUENCE HOLDS.
  56.        
  57.         //include
  58.         //directly jump to next valid level where property HOLDS (some level j, where nums[j] > nums[i], j > i)
  59.         //AS property is always going to HOLD no matter what options we explore as all are VALID, we don't need to USE CONDITIONAL
  60.         //REDUCES THE need of another parameter such as lastIdx
  61.         //REMEMBER
  62.         //IF ASKED FOR SUBSEQUENECE(ORDER DEPENDEDENT), ORDER OF ORIGINAL ARRAY CAN'T BE CHANGED, CAN'T BE SORTED, SO NO BINARY SEARCH, USE LOOP INSTEAD
  63.         //IF ASKED FOR SUBSET(ORDER INDEPENDENT), ORDER OF ORIGINAL ARRAY CAN BE CHANGED TO FORM THE BEST ANSWER, CAN BE SORTED, SO BINARY SEARCH INSTEAD OF LOOP TO OPTIMISE
  64.         for(int j = level + 1; j < nums.size(); j++){
  65.             if(nums[j] > nums[level]){
  66.                 length = max(length, 1 + getLIS(j, nums, memo));
  67.             }
  68.         }
  69.         //Exclude
  70.         //*******IMPORTANT
  71.         //EXPLORE THE OPTION TO EXCLUDE explicitly to HANDLE the CASE from where the LIS will START FROM, TO CHOOSE WHAT IS THE FIRST ELEMENT
  72.         //AFTER THE FIRST ELEMENT IS CHOSEN at some level i, we ALWAYS JUMP TO A VALID LEVEL WHERE PROPERTY WILL ALWAYS HOLD (nums[j] > nums[i], j > i) with
  73.         // the help of LOOP or BS, depending if the array is SORTED OR NOT(SUBSEQUENCE OR SUBSET)
  74.         //BUT for the first element, We start from level 0.
  75.         // As per our definition we always are on a VALID LEVEL, which makes level 0 always VALID(certainly not true), and we INCLUDE THIS ELEMENT as our STARTING POINT always.
  76.         // We explore every VALID OPTION ONCE THE FIRST ELEMENT IS CHOSEN WITH THE HELP OF LOOP or BS, but what about the FIRST ELEMENT ITSELF.
  77.         // USING FOR LOOP GUARANTEES WE LAND ON A VALID LEVEL (where both options are valid), but the FIRST RECURSIVE CALL start from 0, which by definition
  78.         // that we only EXPLORE VALID LEVELS, makes an FALSE assumption that LEVEL 0 is always valid, which MAKES each of our LIS that is formed
  79.         // start from level 0, MAKING level 0/index 0 element a STARTING POINT OF EVERY LIS THAT WE EVER FORM, which is not TRUE, as our LIS can literally start from anywhere.
  80.         //It is just we decided to start from level 0, to start recursion, makes it VALID BY ACCIDENT, and we choose 0th index element
  81.         //as our FIRST ELEMENT OF ALL THE POSSIBLE INCREASING SUBSEQUENCES THAT WE FORM
  82.  
  83.         //RECTIFY IT BY GIVING FREEDOM TO CHOOSE THE FIRST ELEMENT OF THE EVERY LIS THAT WE FORM, i.e. it  can START FROM ANY INDEX
  84.         //BASICALLY GIVE AN OPTION TO EXCLUDE IF WE CHOOSE OUR FIRST ELEMENT.
  85.        
  86.         //IT CAN BE DONE SIMPLY APPLYING THE SAME FOR LOOP TO THE FIRST CALL IN THE SERIES ITSELF
  87.         //BUT AS IT IS THE FIRST ELEMENT OF THE SEQUENCE(subsequence, subset) no need to compare, as a subsequence of length 1 is always a VALID LIS
  88.         //CURRENTLY WE START FROM 0, BUT WE COULD HAVE STARTED FROM ANYWHERE ON THE ARRAY
  89.         //LOOPING ON THE FIRST RECURSIVE CALL, gives every element of the array to be the STARTING POINT of LIS.
  90.         return length;
  91.     }
  92.     //*********IMPORTANT
  93.     //AS WE ARE USING LOOP, we only EXPLORE VALID OPTIONS. We have both INCLUDE AND EXCLUDE. BUT WHY EXCLUDE THE CURRENT ELEMENT explicitly??????
  94.     //INCLUDING THE CURRENT ELEMENT WILL ALWAYS INCREASE THE SIZE OF LIS by 1 and we are always on a VALID LEVEL ALWAYS(where we can explore both), which guarantees that we can explore INCLUDE
  95.     //without any hesitation that if it would make the subsequence INVALID.
  96.     //EXCLUDING THE CURRENT ELEMENT WILL HAPPEN WITH THE FOR LOOP IMPLICITLY ANYWAYS, no NEED to exclude explicitly.
  97.     // WE ONLY EXPLORE LEVELS WITH BOTH OPTIONS AVAILABLE, SO WE CHOOSE WHAT GIVES US THE BEST ANSWER EVERYTIME!!!! & Including always increases
  98.     //LENGTH, so WE ALWAYS INCLUDE THE ELEMENT WE LAND ONTO!!!!!!!!!!
  99.     int lengthOfLIS(vector<int>& nums) {
  100.         vector<int> memo(nums.size(), -1);
  101.         //as we are on this LEVEL, we are going to include this ELEMENT (AS on every level we will always include, because include is the BEST OPTION)
  102.         int length = 1;
  103.         //IMPORTANT******** Each 'i' is a VALID STARTING INDEX FOR LIS, as the first element in LIS is always VALID(increasing(nothing to compare it to) and a valid subsequence of array)
  104.         for(int i = 0; i < nums.size(); i++){
  105.             //no need to add 1 here (1 + getLIS()), we already have done length = 1, which makes sure that we included the element
  106.            length = max(length, getLIS(i, nums, memo));
  107.         }
  108.         return length;
  109.     }
  110. };
Advertisement
Add Comment
Please, Sign In to add comment