1

I need to write a function to find the smallest window that contains all the elements in an array. Below is what I have tried:

def function(item):
    x = len(set(item))
    i = 0
    j = len(item) - 1
    result = len(item)
    while i <= j:
        if len(set(item[i + 1: j + 1])) == x:
            result = min(result, len(item[i + 1: j + 1]))
            i += 1 
        elif len(set(item[i:j])) == x:
            result = min(result, len(item[i:j]))
            j -= 1
        else:
            return result
    return result

print(function([8,8,8,8,1,2,5,7,8,8,8,8]))

The time complexity is in O(N^2), Can someone help me to improve it to O(N) or better? Thanks.

Stephan
  • 365
  • 1
  • 5
  • 18
  • perhaps this question is a better match for [codereview](https://codereview.stackexchange.com/), but consider reading their [how to ask](https://codereview.stackexchange.com/help/how-to-ask) before posting there. – Paul Rooney Aug 16 '18 at 05:08
  • No, this test case is random. – Stephan Aug 16 '18 at 05:34
  • 3
    Please refer to algorithms in this similar question: https://stackoverflow.com/questions/2459653/how-to-find-smallest-substring-which-contains-all-characters-from-a-given-string – Kevin Fang Aug 16 '18 at 05:49

2 Answers2

0

You can use the idea from How to find smallest substring which contains all characters from a given string? for this specific case and get a O(N) solution.

Keep a counter for how many copies of each unique number is included in the window and move the end of the window to the right until all unique numbers are included at least once. Then move the start of the window until one unique number disappears. Then repeat:

from collections import Counter
def smallest_window(items):
    element_counts = Counter()
    n_unique = len(set(items))
    characters_included = 0
    start_enumerator = enumerate(items)
    min_window = len(items)
    for end, element in enumerate(items):
        element_counts[element] += 1
        if element_counts[element] == 1:
            characters_included += 1
        while characters_included == n_unique:
            start, removed_element = next(start_enumerator)
            min_window = min(end-start+1, min_window)
            element_counts[removed_element] -= 1
            if element_counts[removed_element] == 0:
                characters_included -= 1
    return min_window 

>>> smallest_window([8,8,8,8,1,2,5,7,8,8,8,8])
5
kuppern87
  • 1,125
  • 9
  • 14
0

This problem can be solved as below.

def lengthOfLongestSublist(s):
    result = 0
    #set a dictionary to store item in s as the key and index as value
    d={}
    i=0
    j=0
    while (j < len(s)):
        #if find the s[j] value is already exist in the dictionary,
        #move the window start point from i to i+1
        if (s[j] in d):
            i = max(d[s[j]] + 1,i)
        #each time loop, compare the current length of s to the previouse one
        result = max(result,j-i+1)
        #store s[j] as key and the index of s[j] as value
        d[s[j]] = j
        j = j + 1
    return result

lengthOfLongestSubstring([8,8,8,8,8,5,6,7,8,8,8,8,])

Output: 4
  1. Set a dictionary to store the value of input list as key and index of the list as the value. dic[l[j]]=j

  2. In the loop, find if the current value exists in the dictionary. If exist, move the start point from i to i + 1.

  3. Update result.

The complexity is O(n).

Shuhan
  • 13
  • 5