Home > Software design >  memoization of recursive function
memoization of recursive function

Time:01-11

I am solving this problem and I solved it recursively. For the larger test case, it was giving me error of time out so I tried to create memoization.

https://leetcode.com/problems/frequency-of-the-most-frequent-element/description/

The frequency of an element is the number of times it occurs in an array.

You are given an integer array of nums and an integer k. In one operation, you can choose an index of nums and increment the element at that index by 1.

Return the maximum possible frequency of an element after performing at most k operations.

Example 1:

Input: nums = [1,2,4], k = 5 Output: 3 Explanation: Increment the first element three times and the second element two times to make nums = [4,4,4]. 4 has a frequency of 3.

But the problem is that parameter of the function is an array like [1, 2, 4, 6] and k which is an integer value.

I want memoization where I can check for a key which basically checks if the array and k value are already solved or not.

My problem here in the code is that

suppose for a function there is an array [1, 4, 5] and k =3, I check for a key of "1-4-5-3" and if it is not present I do a recursion call whereas if there was the solution for [1, 5, 4] and k=3, or [5, 1, 4] for k = 3 it should have also said that it is already solved.

var maxFrequency = function(nums, k, memo = {}) {
    if(k==0){
        return countFrequency(nums);
    }
    let key = ""
    nums.forEach((element, index)=>{
        key = key   "-"   element
    })
    key = key   "-"    k
    if(nums[key]){
        return nums[key]
    }
    let result = []
    for(let i=0, _length = nums.length; i<_length; i  ){
        let tempArray = [...nums]
        tempArray[i]  = 1
        result[i] = maxFrequency(tempArray, k-1)
    }

    nums[key] = Math.max(...result)
    return nums[key]
};

function countFrequency(arr){
    let map = {}
    let maxFreq = 1
    for(let i=0, _length = arr.length; i<_length; i  ){
        if(map.hasOwnProperty(arr[i])){
            map[arr[i]]  = 1
            if(map[arr[i]]>maxFreq){
                maxFreq = map[arr[i]]
            }
        }
        else{
            map[arr[i]] = 1
        }
    }
    return maxFreq
}

It works for smaller data like

nums = [1,4,8,13] k = 5 got Output 2 for Expected 2

How can I apply memoization to this kind of problem?

Thank you

CodePudding user response:

Memoization is not going to help reduce the time complexity of your solution. Your algorithm is as brute force as can be, where every possible combination of increment-steps is attempted. With memoization you would eliminate cases where you come to the same result by applying the same increments but in a different order, but:

  1. Those "duplicate" cases could be easily avoided by only producing increments from left-to-right and never to an element the precedes an element that was already incremented. This approach makes the memoization unnecessary.
  2. That still represents a very inefficient algorithm

The right way to approach this problem is:

  • Sort the elements in non-decreasing order

  • Apply a sliding window algorithm starting with a small window at the left side of the array (a window with 1 element):

    • Extend the window at the right when the window can be flattened to one value with k increments

    • Reduce the window at the left when the window cannot be flattened to one value with k increments

      Note that knowing how many increments are necessary to flatten a window can be deduced with a mathematical (incremental) formula -- you don't really have to perform those increments.

    • Keep track of what the largest window was that could be flattened to one value.

    • Repeat until the window reaches the right end of the array

  • Return the number of values in the largest valid window that was found.

  • Related