2

The problem is as follow:

Our input is an array of 14 numbers and our output is whether this is a winning hand. For a hand to be a winning hand it must be possible to divide its numbers into groups with the following rules:

  1. Each group of 3 must be of identical numbers or a straight (111 or 123)
  2. We are allowed to have only 1 pair of identical numbers (22 is OK but 45 is not)

For example:

[1,1,1,2,2,2,3,3,3,4,4,4,5,5]: True
[1,1,1,2,2,2,3,3,3,4,4,4,5,6]: False
[1,1,2,2,3,3,4,4,4,6,6,6,8,8]: True

I wrote the following solution for problem using a backtracking technique:

Note: Ignore all occurrence of seen it is part of the memorization for the second part of my question below.

def is_winning_hand(hand):
  hand.sort()
  seen = set()
  return is_winning_hand_step(hand, True, seen)
  
def is_winning_hand_step(hand, can_take_two, seen):
  if len(hand) == 0:
    return True
    
  if len(hand) == 1:
    return False
    
  if str(hand)+str(can_take_two) in seen:
    return False
    
  if can_take_two:
    valid, new_hand = take_two(hand)
    if valid:
      if is_winning_hand_step(new_hand, False, seen):
        return True
    
  if len(hand) >= 3:
    valid, new_hand = take_three(hand)
    if valid:
      if is_winning_hand_step(new_hand, can_take_two, seen):
        return True
          
    valid, new_hand = take_straight(hand)
    if valid:
      if is_winning_hand_step(new_hand, can_take_two, seen):
        return True
        
  seen.add(str(new_hand)+str(can_take_two))
  return False

def take_two(hand):
  if hand[0] == hand[1]:
    return True, hand[2:]
  else:
    return False, None
    
def take_three(hand):
  if hand[0] == hand[1] and hand[1] == hand[2]:
    return True, hand[3:]
  else:
    return False, None

def take_straight(hand):
  cnt = 1
  last_val = hand[0]
  indices = set([0])
  
  for i in xrange(1, len(hand)):
    if hand[i] == last_val:
      continue
    elif hand[i] == last_val + 1:
      cnt += 1
      indices.add(i)
      last_val = hand[i]
      if cnt == 3:
        return True, [x for j, x in enumerate(hand) if j not in indices]
    else:
      return False, None
      
  return False, None

Now I am trying to find out what is the time complexity of that problem. Let's assume the input is already sorted for us so leave aside it's O(N log N) .

My guess is since in each step I have a potential split to 3 branches the complexity is O(3^N) where N should be the length of the input array. In our case it is always 14 length array but I am talking about the general case. Am I correct?

In the next step I added a memorization to my solution. What can we tell about the time complexity now? Thanks to the memorization I'm avoiding from solving the same sub-problems again and again, so is that making it an O(N) solution?

user1692261
  • 1,197
  • 3
  • 16
  • 30

0 Answers0