Quantcast
Channel: Active questions tagged python - Stack Overflow
Viewing all articles
Browse latest Browse all 23305

Reduce the sum of differences between adjacent array elements

$
0
0

I came across a coding challenge on the internet the question is listed below:

Have the function FoodDistribution(arr) read the array of numbersstored in arr which will represent the hunger level of differentpeople ranging from 0 to 5 (0 meaning not hungry at all, 5 meaningvery hungry). You will also have N sandwiches to give out which willrange from 1 to 20. The format of the array will be [N, h1, h2, h3,...] where N represents the number of sandwiches you have and the restof the array will represent the hunger levels of different people.Your goal is to minimize the hunger difference between each pair ofpeople in the array using the sandwiches you have available.

For example: if arr is [5, 3, 1, 2, 1], this means you have 5sandwiches to give out. You can distribute them in the following orderto the people: 2, 0, 1, 0. Giving these sandwiches to the people theirhunger levels now become: [1, 1, 1, 1]. The difference between eachpair of people is now 0, the total is also 0, so your program shouldreturn 0. Note: You may not have to give out all, or even any, of yoursandwiches to produce a minimized difference.

Another example: if arr is [4, 5, 2, 3, 1, 0] then you can distributethe sandwiches in the following order: [3, 0, 1, 0, 0] which makes allthe hunger levels the following: [2, 2, 2, 1, 0]. The differencesbetween each pair of people is now: 0, 0, 1, 1 and so your programshould return the final minimized difference of 2.

My first approach was to try to solve it greedily as the following:

  1. Loop until the sandwiches are zero
  2. For each element in the array copy the array and remove one hunger at location i
  3. Get the best combination that will give you the smallest hunger difference
  4. Reduce the sandwiches by one and consider the local min as the new hunger array
  5. Repeat until sandwiches are zero or the hunger difference is zero

I thought when taking the local minimum it led to the global minimum which was wrong based on the following use case [7, 5, 4, 3, 4, 5, 2, 3, 1, 4, 5]

def FoodDistribution(arr):    sandwiches = arr[0]    hunger_levels = arr[1:]    # Function to calculate the total difference    def total_difference(hunger_levels):        return sum(abs(hunger_levels[i] - hunger_levels[i + 1]) for i in range(len(hunger_levels) - 1))    def reduce_combs(combs):        local_min = float('inf')        local_min_comb = None        for comb in combs:            current_difference = total_difference(comb)            if current_difference < local_min:                local_min = current_difference                local_min_comb = comb        return local_min_comb    # Function to distribute sandwiches    def distribute_sandwiches(sandwiches, hunger_levels):        global_min = total_difference(hunger_levels)        print(global_min)        while sandwiches > 0 and global_min > 0:            combs = []            for i in range(len(hunger_levels)):                comb = hunger_levels[:]                comb[i] -= 1                combs.append(comb)            local_min_comb = reduce_combs(combs)            x = total_difference(local_min_comb)            print( sandwiches, x, local_min_comb)            global_min = min(global_min, x)            hunger_levels = local_min_comb            sandwiches -= 1        return global_min    # Distribute sandwiches and calculate the minimized difference    global_min = distribute_sandwiches(sandwiches, hunger_levels)    return global_minif __name__ == "__main__":    print(FoodDistribution([7, 5, 4, 3, 4, 5, 2, 3, 1, 4, 5]))

I changed my approach to try to brute force and then use memorization to optimize the time complexity

  1. Recurse until out of bounds or sandwiches are zero
  2. For each location there are two options either to use a sandwich or ignore
  3. When the option is to use a sandwich decrement sandwiches by one and stay at the same index.
  4. When the option is to ignore increment the index by one.
  5. Take the minimum between the two options and return it.

The issue here is that I didn't know what to store in the memo and storing the index and sandwiches is not enough. I am not sure if this problem has a better complexity than 2^(n+s). Is there a way to know if dynamic programming or memorization is not the way to solve the problem and in this case can I improve the complexity by memorization or does this problem need to be solved with a different approach?

def FoodDistribution(arr):    sandwiches = arr[0]    hunger_levels = arr[1:]    # Distribute sandwiches and calculate the minimized difference    global_min = solve(0, sandwiches, hunger_levels)    return global_mindef solve(index, sandwiches, hunger_levels):    if index >= len(hunger_levels) or sandwiches == 0:        return total_difference(hunger_levels)    # take a sandwich    hunger_levels[index] += -1    sandwiches += -1    minTake = solve(index, sandwiches, hunger_levels)    hunger_levels[index] += 1    sandwiches += 1    # dont take sandwich    dontTake = solve(index + 1, sandwiches, hunger_levels)    return min(minTake, dontTake)def total_difference(hunger_levels):    return sum(abs(hunger_levels[i] - hunger_levels[i + 1]) for i in range(len(hunger_levels) - 1))if __name__ == "__main__":    print(FoodDistribution([7, 5, 4, 3, 4, 5, 2, 3, 1, 4, 5]))

Edit: Multiple states will give you the optimal answer for the use case above

sandwiches = 7 hunger = [5, 4, 3, 4, 5, 2, 3, 1, 4, 5]optimal is 6states as follow[3, 3, 3, 3, 3, 2, 2, 1, 4, 5][4, 3, 3, 3, 3, 2, 2, 1, 4, 4][4, 4, 3, 3, 2, 2, 2, 1, 4, 4][4, 4, 3, 3, 3, 2, 1, 1, 4, 4][4, 4, 3, 3, 3, 2, 2, 1, 3, 4][4, 4, 3, 3, 3, 2, 2, 1, 4, 4][5, 4, 3, 3, 3, 2, 2, 1, 3, 3]

Viewing all articles
Browse latest Browse all 23305

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>