ASU SoDA Coding Challenge VI Medium Question #2

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Medium Question #2 concerns really big numbers, or numbers which have a large difference with the sum of their digits. The question reads:

ASU SoDA Coding Challenge VI Medium Question 2: Really Big Numbers Problem
Ivan likes to learn different things about numbers, but he is especially interested in really big numbers. Ivan thinks that a positive integer number x is really big if the difference between x and the sum of its digits (in decimal representation) is not less than s. To prove that these numbers may have different special properties, he wants to know how rare (or not rare) they are — in fact, he needs to calculate the quantity of really big numbers that are not greater than n.
Ivan tried to do the calculations himself, but soon realized that it's too difficult for him. So he asked you to help him in calculations.
 
Input:
The input consists of two integers, n and s
Output: 
Print one integer — the quantity of really big numbers that are not greater than n.
Test Cases:
input
12 1
output
3
input
25 20
output
0
input
10 9
output
1
Note
In the first example numbers 10, 11 and 12 are really big.
In the second example there are no really big numbers that are not greater than 25 (in fact, the first really big number is 30: 30 - 3 ≥ 20).
In the third example 10 is the only really big number (10 - 1 ≥ 9).

My solution for this problem is probably not as optimized as it could be. Here’s my solution:

Solution #1: Lower Bound Approach

We can observe that for any given difference s, there is a smallest number x such that for all values greater than or equal to x, x-sum(x) >= s. Thus, it suffices to count all really big numbers less than or equal to this lower bound and then count the numbers between the lower bound and n.

To find the lower bound, it suffices to check whether x is a really big number and whether x + 9*num(x) < ten(x) where num(x) is the number of digits in x and ten(x) is the smallest power of 10 which is greater than x. Doing this for every number, we can easily find the lower bound. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Medium Problem #2
 https://docs.google.com/document/d/14sk0u9ZVM1rrIsSCSwIWesI1ks8BukFMaT-NlJCr6FQ/edit
 '''
 
 import time
 import sys
 from numpy.f2py.auxfuncs import throw_error
 
 for x in sys.stdin:
     try:
         a = map(int,x.split())
         n = a[0]
         s = a[1]
     except:
         throw_error("Incorrect input format.")
 
 def sumDigits(a):
     total = 0
     for x in str(a):
         total+=int(x)
     return total
 
 def numDigits(i):
     return len(str(i))
 
 def power(i):
     power = 1
     while(power<=i):
         power*=10
     return power
 
 def reallyBigQuantity(n,s):
     total = 0
     i = 1
     while(i<=n):
         if i-sumDigits(i) >=s:
             total+=1
         if i-numDigits(i)*9>=s and i+numDigits(i)*9<=power(i):
             total+=n-i
             break
         i+=1
     return total
 
 start = time.time()
 print reallyBigQuantity(n, s)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 0
 --- 5.69820404053e-05 seconds ---
 
 for input of n = 25, s = 20.
 ''' 

And with that, we’re done. There may be more efficient ways to search for the upper bound, but this was the quickest method I could think of.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Medium Question #1

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Medium Question #1 concerns determining the minimum balanced ternary string that can be obtained by replacing the minimum number of digits in a given ternary string. The question reads:

ASU SoDA Coding Challenge VI Medium Question 1: Balanced String Problem
You are given a string s consisting of exactly n characters, and each character is either '0', '1' or '2'. Such strings are called ternary strings.
Your task is to replace minimum number of characters in this string with other characters to obtain a balanced ternary string (balanced ternary string is a ternary string such that the number of characters '0' in this string is equal to the number of characters '1', and the number of characters '1' (and '0' obviously) is equal to the number of characters '2').
Among all possible balanced ternary strings you have to obtain the lexicographically (alphabetically) smallest.
Note that you can neither remove characters from the string nor add characters to the string. Also note that you can replace the given characters only with characters '0', '1' and '2'.
It is guaranteed that the answer exists.
 
Input
An array of characters consisting of exactly n characters '0', '1' and '2'.
 
Output
Print one string — the lexicographically (alphabetically) smallest balanced ternary string which can be obtained from the given one with minimum number of replacements.
Because n is divisible by 3 it is obvious that the answer exists. And it is obvious that there is only one possible answer.

Test Cases:
input
121
output
021
input
000000
output
001122
input
211200
output
211200
input
120110
output
120120

My solution for this problem is quite messy, so I apologize if it’s difficult to understand. Here’s my solution:

Solution #1: Casework Approach

First we count the number of 0’s, 1’s, and 2’s in the string. To minimize the number of replacements, any digit with more than the average frequency must be replaced with digits with less than the average frequency. By doing casework on which digits have larger than average frequency and which digits have lower than average frequency, it is possible, to find the corresponding minimal balanced string. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Medium Problem #1
 https://docs.google.com/document/d/14sk0u9ZVM1rrIsSCSwIWesI1ks8BukFMaT-NlJCr6FQ/edit
 '''
 
 import time
 import sys
 
 for x in sys.stdin:
     myInput = x
 
 def getBalancedString(myString):
     l = len(myString)/3
     zeros = []
     ones = []
     twos = []
     for i in range(len(myString)):
         if myString[i]=="0":
             zeros.append(i)
         elif myString[i]=="1":
             ones.append(i)
         else:
             twos.append(i)
     l1 = len(zeros)
     l2 = len(ones)
     l3 = len(twos)
     if(l1==l2 and l1==l3):
         return myString
     t = (abs(l1-l)+abs(l2-l)+abs(l3-l))/2
     if(l<l1):
         if(l<l2):
             o = l2-l
             for i in ones[l2-o:l2]:
                 myString = myString[0:i]+"2"+myString[i+1:]
             for i in zeros[l1-t+o:l1]:
                 myString = myString[0:i]+"2"+myString[i+1:]
         elif(l<l3):
             o = l3-l
             for i in twos[0:o]:
                 myString = myString[0:i] + "1" + myString[i+1:]
             for i in zeros[l1-t+o:l1]:
                 myString = myString[0:i] + "1" + myString[i+1:]
         else:
             o = l-l3
             for i in zeros[l1-o:l1]:
                 myString = myString[0:i]+"2"+myString[i+1:]
             for i in zeros[l1-t:l1-o]:
                 myString = myString[0:i]+"1"+myString[i+1:]
         return myString
     elif(l==l1):
         if (l2<l3):
             for i in twos[0:t]:
                 myString = myString[0:i]+"1"+myString[i+1:]
         else:
             for i in ones[l2-t:l2]:
                 myString = myString[0:i]+"2"+myString[i+1:]
         return myString
     else:
         if(l2<l):
             o = l-l2
             for i in twos[t-o:t]:
                 myString = myString[0:i]+"1"+myString[i+1:]
             for i in twos[0:t-o]:
                 myString = myString[0:i]+"0"+myString[i+1:]
         elif(l3<l):
             o = l-l3
             for i in ones[0:t-o]:
                 myString = myString[0:i]+"0"+myString[i+1:]
             for i in ones[l2-o:l2]:
                 myString = myString[0:i]+"2"+myString[i+1:]
         else:
             o = l2-l
             for i in ones[0:o]:
                 myString = myString[0:i]+"0"+myString[i+1:]
             for i in twos[0:t-o]:
                 myString = myString[0:i]+"0"+myString[i+1:]
         return myString
 
 start = time.time()
 print getBalancedString(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 120120
 --- 1.69277191162e-05 seconds ---
 
 for input of myInput = "120110"
 ''' 

And with that, we’re done. I apologize if my solution was a bit messy, but I thought that casework was the simplest method for solving this problem. This is a great example of a problem that is intuitively easy for humans to solve but somewhat difficult for a human to implement a solution.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Easy Question #5

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Easy Question #5 concerns determining the maximum product which can be formed by the digits of a number in a given range. The question reads:

ASU SoDA Coding Challenge VI Easy Question 5: Maximum numerical product
The problem is simple: Find the maximum possible product you can form using integers from 1,n.
Input: 
The only input contains the integer n (1≤n≤2⋅10^9).
Output: 
 Print the maximum product of digits among all integers from 1 to n
Test Cases:
input
390
 
output
216
 
input
7
 
output
7
 
input
1000000000
 
output
387420489
 
Note
In the first example the maximum product is achieved for 389 (the product of digits is 3⋅8⋅9=216). In the second example the maximum product is achieved for 7 (the product of digits is 7). In the third example the maximum product is achieved for 999999999 (the product of digits is 9^9) =387420489

I must confess, I am unsure whether my solution will get the correct answer for all possible inputs. Here is my solution:

Solution #1: Recursive First Digit Approach

We recursively find the number with the largest product by finding the largest possible left-most digit that can provide the maximum possible product and then calling the function for all digits to the right of the leftmost possible digit. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Easy Problem #5
 https://docs.google.com/document/d/1E_8BtPkGH5iQSBVOxr_lZpjrS5pToaWtDBS1WEZTxWw/edit
 '''
 
 import time
 import sys
 
 for x in sys.stdin:
     myInput = int(x)
 
 def maxProductDigits(n):
     if(n<=1):
         return 1
     if(n<10):
         return n
     power = 1
     while(power<=n):
         power*=10
     power/=10
     mySum = power
     if(2*power<=n):
         mySum = 3*power
         while(mySum<=n):
             mySum+=power
         mySum-=power
     v = mySum-1
     total = 1
     for x in str(v):
         total*=int(x)
     return(max(total,int(str(n)[0])*maxProductDigits(int(str(n)[1:]))))
 
 start = time.time()
 print maxProductDigits(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 472392
 --- 2.19345092773e-05 seconds ---
 
 for input of n = 900,000.
 ''' 

And with that, we’re done. Like I said, I am unsure whether this solution will always get the correct answer. It worked for all of the test cases on the day of the competition, and I am too lazy to rigorously check it, so I assume it works.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Easy Question #4

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Easy Question #4 concerns restoring an internet address from a partial internet address. The question reads:

ASU SoDA Coding Challenge VI Easy Question 4: Internet Address
Vasya is an active Internet user. One day he came across an Internet resource he liked, so he wrote its address in the notebook. We know that the address of the written resource has format:
<protocol>://<domain>.ru[/<context>]
where:
<protocol> can equal either "http" (without the quotes) or "ftp" (without the quotes),
<domain> is a non-empty string, consisting of lowercase English letters,
the /<context> part may not be present. If it is present, then <context> is a non-empty string, consisting of lowercase English letters.
If string <context> isn't present in the address, then the additional character "/" isn't written. Thus, the address has either two characters "/" (the ones that go before the domain), or three (an extra one in front of the context).
When the boy came home, he found out that the address he wrote in his notebook had no punctuation marks. Vasya must have been in a lot of hurry and didn't write characters ":", "/", ".".
Help Vasya to restore the possible address of the recorded Internet resource.
 
Input
An array of characters representing a string that Vasya wrote in his notebook
It is guaranteed that the given string contains at most 50 letters. It is guaranteed that the given string can be obtained from some correct Internet resource address, described above.
 
Output
Print a single line — the address of the Internet resource that Vasya liked. If there are several addresses that meet the problem limitations, you are allowed to print any of them.
Test Cases
input
httpsunrux
output
http://sun.ru/x
input
ftphttprururu
output
ftp://http.ru/ruru
Note
In the second sample there are two more possible answers: "ftp://httpruru.ru" and "ftp://httpru.ru/ru".

My solution for this question is very bad because I am unfamiliar with regular expressions. Here is my solution:

Solution #1: Brute Force Parsing Approach

We simply check for each part of the address and add the necessary characters. The important parts are that the string must start with either “http” or “ftp”, and there must be the characters “ru” after this prefix with some characters in between. Using Python’s index method, it is easy to parse for these components. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Easy Problem #4
 https://docs.google.com/document/d/1E_8BtPkGH5iQSBVOxr_lZpjrS5pToaWtDBS1WEZTxWw/edit
 '''
 
 import time
 import sys
 
 for x in sys.stdin:
     if(x[len(x)-1]=='\n'):
         x = x[0:len(x)-1]
     myInput = x
 
 def findPossible(concat):
     l = len(concat)
     s = ""
     i = 0
     if(l>3 and concat[0:4]=="http"):
         s += "http://"
         i = 4
     elif(l>2 and concat[0:3] == "ftp"):
         s += "ftp://"
         i = 3
     else:
         return "None possible: Starting sequence is wrong"
     concat = concat[i:]
     try:
         a = concat.index("ru",1)
     except:
         return "None possible: ru subsequence not found"
     s+=concat[0:a]
     s+=".ru"
     concat = concat[a+2:]
     if(len(concat)>0):
         s+="/"
         s+=concat
     while True:
         try:
             i = s.index("..")
             s = s[0:i]+"."+s[i+2:]
         except:
             break
     return s
 
 start = time.time()
 print findPossible(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 http://sun.ru/x
 --- 1.59740447998e-05 seconds ---
 
 for input of myInput = "httpsunrux"
 ''' 

And with that, we’re done. I really need to learn some RegEx, because I know it allows for really easy string parsing in cases such as this problem. I didn’t attempt to optimize my solution seeing as the string is at most 50 characters long.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Easy Question #3

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Easy Question #3 concerns determining the length and the frequency of the longest regular bracket subsequence in a string of parentheses. The question reads:

ASU SoDA Coding Challenge VI Easy Question 3: Longest Bracket Subsequence

This is yet another problem dealing with regular bracket sequences.
We should remind you that a bracket sequence is called regular, if by inserting «+» and «1» into it we can get a correct mathematical expression. For example, sequences «(())()», «()» and «(()(()))» are regular, while «)(», «(()» and «(()))(» are not.
You are given a string of «(» and «)» characters. You are to find its longest substring that is a regular bracket sequence. You are to find the number of such substrings as well.
 
Input:
The first line of the input file contains a non-empty string, consisting of «(» and «)» characters. Its length does not exceed 10^6.
 
Output:
Print the length of the longest substring that is a regular bracket sequence, and the number of such substrings. If there are no such substrings, write the only line containing "0 1".
Test Cases:
input
)((())))(()())
output
6 2
input
))(
output
0 1

My solution for this problem was very messy as I used manual string parsing in Python rather than RegEx or some other method. Here’s my solution:

Solution #1: O(n^2) Approach

We simply search for every regular bracket subsequence from each starting open parentheses. For each starting point, we count from that parentheses, adding 1 for open parentheses and subtracting 1 for closed parentheses. If the total is ever negative, we can stop searching for the given start point. If the total is ever 0, we have found a regular subsequence. In this manner, we can find and count all maximal regular bracket subsequences in O(n^2) time complexity. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Easy Problem #3
 https://docs.google.com/document/d/1E_8BtPkGH5iQSBVOxr_lZpjrS5pToaWtDBS1WEZTxWw/edit
 '''
 
 import time
 import sys
 
 for x in sys.stdin:
     if(x[len(x)-1]=='\n'):
         x = x[0:len(x)-1]
     myInput = x
 
 def maxSubsequence(par):
     maxFound = 0
     total = 0
     times = 0
     start = []
     for i in range(len(par)):
         if(par[i]=="("):
             start.append(i)
     for i in start:
         total = 0
         v = 0
         a = par[i:]
         for x in a:
             v+=1
             if x=="(":
                 total+=1
             elif x==")":
                 total-=1
             if(total<0):
                 break
             if(total==0):
                 if(v==maxFound):
                     times+=1
                 elif(v>maxFound):
                     times = 1
                     maxFound = v
     if(maxFound == 0):
         return "0 1"
     else:
         return str(maxFound) + " " + str(times)
 
 start = time.time()
 print maxSubsequence(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 12 1
 --- 2.71797180176e-05 seconds ---
 
 for input of myInput = ")((())))(()())))))(((())))(()))()"
 ''' 

And with that, we’re done. While this may have been efficient enough for the purposes of the coding challenge, I am sure that an O(n) solution exists, so I may come back to this problem at some point.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Easy Question #2

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Easy Question #2 concerns determining whether a given outcome of a repeated game is possible. The question reads:

ASU SoDA Coding Challenge VI Easy Question 2: 3 Person Chess

Alex, Bob and Carl will soon participate in a team chess tournament. Since they are all in the same team, they have decided to practise really hard before the tournament. But it's a bit difficult for them because chess is a game for two players, not three.
So they play with each other according to following rules:
Alex and Bob play the first game, and Carl is spectating;
When the game ends, the one who lost the game becomes the spectator in the next game, and the one who was spectating plays against the winner.
Alex, Bob and Carl play in such a way that there are no draws.
Today they have played n games, and for each of these games they remember who was the winner. They decided to make up a log of games describing who won each game. But now they doubt if the information in the log is correct, and they want to know if the situation described in the log they made up was possible (that is, no game is won by someone who is spectating if Alex, Bob and Carl play according to the rules). Help them to check it!
Input:
The first parameter contains one integer n (1 ≤ n ≤ 100) — the number of games Alex, Bob and Carl played.
The second parameter entered as an array, describing the game log. i-th line contains one integer ai (1 ≤ ai ≤ 3) which is equal to 1 if Alex won i-th game, to 2 if Bob won i-th game and 3 if Carl won i-th game.
Output: 
Print YES if the situation described in the log was possible. Otherwise print NO.
Test Cases:
input
3
1
1
2
output
YES
input
2
1
2
output
NO

This problem was also a good warm up for the complex questions in the competition. Here’s my solution:

Solution #1: O(n) Approach

We simply keep track of the spectator after each game, and if the winner is ever equal to the spectator, we know the outcome is impossible. After a little thought, you can convince yourself that this is the only condition for determining whether an outcome is possible. Here’s an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Easy Problem #2
 https://docs.google.com/document/d/1E_8BtPkGH5iQSBVOxr_lZpjrS5pToaWtDBS1WEZTxWw/edit
 '''
 
 import time
 import sys
 
 myInput = []
 i = 0
 for x in sys.stdin:
     if(i>0):
         myInput.append(int(x))
     else:
         n = int(x)
     i+=1
 
 def isPossible(myList):
     spectator = 3
     for x in myList:
         if x==spectator:
             return "NO"
         temp = spectator
         if(temp==3):
             if(x==1):
                 spectator=2
             else:
                 spectator=1
         elif(temp==2):
             if(x==1):
                 spectator=3
             else:
                 spectator=1
         else:
             if(x==2):
                 spectator=3
             else:
                 spectator=2
     return "YES"
 
 start = time.time()
 print isPossible(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 NO
 --- 9.05990600586e-06 seconds ---
 
 for input of n = 12, myInput = [1,1,2,1,2,1,3,1,2,3,1,1]
 ''' 

And with that, we’re done. Once again, I thought this was a good problem. It is not completely trivial, but it can be understood by people without USACO experience. During the competition, I heard more people discuss this question than nearly any other question.

Thanks for reading! See you tomorrow.

ASU SoDA Coding Challenge VI Easy Question #1

On Sunday, November 24, 2019, I participated in the ASU SoDA Coding Challenge VI. The ASU Software Developer’s Association (SoDA) is a club that is dedicated to teaching aspiring programmers how to solve complex problems that will prepare them for industry. The club runs recruiting events, Hackathons, Interview Prep sessions, and other activities that I have personally found invaluable during my first semester at ASU. I would strongly recommend anyone with a remote interest in computer science to join the club.

The SoDA Coding Challenge had 15 questions which were divided into three categories of three questions based on their respective difficulty levels. The Easy Questions, the Medium Questions, and the Hard Questions were made available to the contestants through Google Forms, and participants would have proctors manually check their code to make sure their programs worked.

Easy Question #1 concerns updating a list of integers to make the product of the list equal to 1. The question reads:

ASU SoDA Coding Challenge VI Easy Question 1: Make the Product One

Say you are given n numbers, a1 a2 ….an . With the cost of 1 point you can add or subtract 1 from each number. 
You can apply this operation to the same number any number of times.
Our goal is to make the product of the numbers equal 1.
For example, for n=3 and numbers [1,−3,0] we can make product equal to 1 in 3 points: add 1 to the second element, add 1 to second element again, subtract 1 from third element, so that array becomes [1,−1,−1]. And 1⋅(−1)⋅(−1)=1.
What is the minimum cost we will have to pay to do that?

Input:
The input is an array of integers a1,a2,…,an a1,a2,…,an (−10^9≤ai≤10^9) — the numbers.
Output: 
Output a single number — the minimal number of coins you need to pay to make the product equal to 1.

Test Cases:
input
-1 1
output
2
input
0 0 0 0
output
4
input
-5 -3 5 3 0
output
13

This problem was a great warm up for the later questions in the competition. Here’s my solution:

Solution #1: O(n) Approach

We can observe that the list will only have a product of 1 if all of the elements are either 1 or -1 and the number of -1’s in the list is even. Thus, it suffices to iterate through the array. For each negative entry e, the total cost to update it to -1 will be (-1 – e). For each positive entry e, the total cost to update it to 1 will be (e – 1). For any 0 entry, the total cost to update it to either 1 or -1 will be 1. With this iteration, it is possible to find the total cost to update every entry to either 1 or -1.

To ensure that the product is 1 and not -1, it suffices to count the number of negative elements while iterating through the array. If the number of negative elements is odd, the product will be -1. In cases where there are no 0 elements in the list, this would require an additional cost of 2, because one of the -1 elements would need to be updated to +1. However, when there is a 0 element, this would not change the total cost, because the 0 element could just be updated to a +1 instead of a -1. All of this can be done while iterating through the array once, so this solution runs with O(n) time complexity. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 SoDA Coding Challenge VI Easy Problem #1
 https://docs.google.com/document/d/1E_8BtPkGH5iQSBVOxr_lZpjrS5pToaWtDBS1WEZTxWw/edit
 '''
 
 import sys
 import time
 
 for x in sys.stdin:
     myInput = map(int,x.split())
 
 def minimumCost(myList):
     tn = 0
     total = 0
     z = 0
     for x in myList:
         if(x<0):
             total+=(-1-x)
             tn+=1
         elif(x==0):
             total+=1
             z+=1
         else:
             total+=(x-1)
     if(tn%2==1):
         if(z>0):
             return total
         return total+2
     return total
 
 start = time.time()
 print minimumCost(myInput)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 1001006
 --- 1.00135803223e-05 seconds ---
 
 for input of myInput = [0,0,0,0,0,0,0,0,0,0,999,999999]
 ''' 

And with that, we’re done. I like this problem. It is approachable for anyone with basic experience with arrays, and it is not too difficult for people with no USACO experience to solve. At the same time, it is not completely trivial, as handling the relationship between negative elements and zero elements requires some thought.

Thanks for reading! See you tomorrow.

Project Euler Problem #100

Before I begin, I’d like to state that I will probably take a break from Project Euler for a little while. While writing these first 100 blog posts, I finally accomplished my goal of solving the first 100 problems on Project Euler. When I started, I never expected to make it this far. Writing a blog post per day really helped to give me a sense of purpose during my first semester of college. As a result, I would like to continue blogging about my problem-solving endeavors. However, I must confess that recently it has become more and more difficult to keep up with this schedule for solving Project Euler problems. Thus, in the future, I may discuss Project Euler from time to time, but it probably will not be daily, and it may not be in chronological order as many of the easier Project Euler problems are not at the start of the archives. With that being said, let’s get right into the math.

Problem #100 concerns discrete arrangements which will cause a probability to be equal to 50%. The question reads:

Project Euler Problem 100: Arranged probability
If a box contains twenty-one coloured discs, composed of fifteen blue discs and six red discs, and two discs were taken at random, it can be seen that the probability of taking two blue discs, P(BB) = (15/21)×(14/20) = 1/2.
The next such arrangement, for which there is exactly 50% chance of taking two blue discs at random, is a box containing eighty-five blue discs and thirty-five red discs.
By finding the first arrangement to contain over 1012 = 1,000,000,000,000 discs in total, determine the number of blue discs that the box would contain.

My solution to this problem involves Pell Equations. Here is my solution:

Solution #1: Pell Equation Approach

Let the number of blue disks be b and let the total number of disks be t. We want to search for integer pairs (b,t) such that 2*b*(b-1) = t*(t-1). Writing this as 2b^2-2b+t-t^2 = 0 and solving for b, we get b = (2+sqrt(4+8t^2-8t))/4 = (1+sqrt(1+2t^2-2t))/2. Thus, it suffices to find values of t such that 2t^2-2t+1 = c^2 for some integer c. Solving for t, we get t = (2+sqrt(8c^2-4))/4 = (1+sqrt(2c^2-1))/2. Thus, it suffices to find values of c such that d^2-2c^2 = -1 for some integer d. The first three solutions to this are (1,1), (7,5), It follows that if (d,c) is a solution, (3*d+4*c,2*d+3*c) is the next solution. Thus, the integer solutions for c can be recursively generated, and each one can be translated to a distinct solution for the value of b. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 Pell Equation Approach to Project Euler Problem #100
 '''
 
 import time
 
 def projectEulerProblemOneHundred(n):
     y = 7
     x = 5
     maxY = 2*n-1
     while(y<=maxY):
         tempX = 2*y+3*x
         tempY = 3*y+4*x
         y = tempY
         x = tempX
     return (x+1)/2
 
 start = time.time()
 print projectEulerProblemOneHundred(10**12)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 756872327473
 --- 1.12056732178e-05 seconds ---
 
 for input of 10**12.
 ''' 

And with that, we’re done. This is yet another example of the powers of Pell Equations. We wanted to find all solutions up to 1 trillion, and yet the program only took a hundredth of a millisecond to run.

Thanks for reading! See you tomorrow. As I mentioned above, I may or may not discuss Project Euler depending on whether I am stuck from this point onwards.

Project Euler Problem #99

Problem #99 concerns comparing large exponential numbers. The question reads:

Project Euler Problem 99: Largest exponential
Comparing two numbers written in index form like 211 and 37 is not difficult, as any calculator would confirm that 211 = 2048 < 37 = 2187.
However, confirming that 632382518061 > 519432525806 would be much more difficult, as both numbers contain over three million digits.
Using base_exp.txt (right click and 'Save Link/Target As...'), a 22K text file containing one thousand lines with a base/exponent pair on each line, determine which line number has the greatest numerical value.
NOTE: The first two lines in the file represent the numbers in the example given above.

With a minimal knowledge of mathematics, this problem is quite easy for its placement. Here is my solution:

Solution #1: Logarithm Approach

Because log(x) is an increasing function, log(x)<log(y) implies x<y and vice versa. It is well known that log(a^b) = b*log(a). Thus, the lines can easily be sorted by the value of b*log(a) and the maximal line can be found. Here is an implementation of this approach in Python 2.7:

 '''
 Author: Walker Kroubalkian
 Logarithm Approach to Project Euler Problem #99
 '''
 
 import time
 from math import log
 
 f = open("PE99Exponents.txt","r")
 
 if(f.mode == "r"):
     contents = f.readlines()
     realContents = []
     for x in contents:
         realContents.append(map(int,x.split(",")))
 else:
     raise ValueError("Cannot read from file")
 
 def projectEulerProblemNinetyNine(myList):
     a = sorted(myList, key = lambda x: x[1]*log(x[0]))
     return myList.index(a[len(a)-1])+1
 
 start = time.time()
 print projectEulerProblemNinetyNine(realContents)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 709
 --- 0.000494003295898 seconds ---
 
 for input of given list of exponents.
 ''' 

And with that, we’re done. Looking back on it, my solution actually solves the more complex problem of sorting all of the lines. Its efficiency could be improved by searching specifically for the maximal line. I probably won’t return to make this change because the problem was so simplistic.

Thanks for reading! See you tomorrow.

Project Euler Problem #98

Problem #98 concerns searching for anagrams in a list of words. The question reads:

Project Euler Problem 98: Anagramic squares
By replacing each of the letters in the word CARE with 1, 2, 9, and 6 respectively, we form a square number: 1296 = 362. What is remarkable is that, by using the same digital substitutions, the anagram, RACE, also forms a square number: 9216 = 962. We shall call CARE (and RACE) a square anagram word pair and specify further that leading zeroes are not permitted, neither may a different letter have the same digital value as another letter.
Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, find all the square anagram word pairs (a palindromic word is NOT considered to be an anagram of itself).
What is the largest square number formed by any member of such a pair?
NOTE: All anagrams formed must be contained in the given text file.

My solution for this problem involves a ton of brute force, and it took a bit of manual trouble shooting for my program to run in a reasonable amount of time. Here’s my solution:

Solution #1: Brute Force Approach

We simply search for all pairs of anagrams and then look for ones that have the same arrangement as perfect squares. The part that caused me to use manual trouble shooting was determining the number of digits that the largest square number could have. Clearly, the more digits in the square number, the larger the number. However, it becomes considerably more difficult to search for square numbers with more digits. When I ran the program without a cap on the number of digits, it took forever to run only to find that there were no 7-digit square pairs and there were no 6-digit square pairs. When I set the cap to 5-digit numbers and below, the program ran efficiently. This arguably makes my solution less complete, but it also makes the run time much faster. Here is my solution:

 '''
 Author: Walker Kroubalkian
 Brute Force Approach to Project Euler Problem #98
 '''
 
 import time
 from math import sqrt
 
 f = open("PE98Words.txt","r")
 
 if(f.mode == "r"):
     contents = f.readlines()
     realContents = []
     for x in contents:
         realContents.append(x.split(","))
 else:
     raise ValueError("Cannot read from file")
 
 finalContents = realContents[0]
 goodContents = []
 for x in finalContents:
     goodContents.append(x[1:len(x)-1])
 
 def sieveEratosthenes(n):
     myPrimes = []
     
     primePossible = [True]*(n+1)
     primePossible[0] = False
     primePossible[1] = False
     
     for (i,possible) in enumerate(primePossible):
         if possible:
             for x in range(i*i, (n+1), i):
                 primePossible[x] = False
             myPrimes.append(i)
 

     return myPrimes
 
 def isAnagram(a,b):
     return sorted(a) == sorted(b)
 
 def subset(myList,n):
     l = len(myList)
     if(l==0):
         if(n==0):
             return [[]]
         return []
     if(l<n):
         return []
     if(l==n):
         return [sorted(myList)]
     a = myList[0]
     total = subset(myList[1:],n)
     possible = subset(myList[1:],n-1)
     for x in possible:
         t = x[:]
         t.append(a)
         total.append(sorted(t))
     return total
 
 def permutations(myList):
     l = len(myList)
     if(l==0):
         return []
     if(l==1):
         return [myList]
     a = myList[0]
     b = permutations(myList[1:])
     total = []
     for c in b:
         for x in range(l):
             t = c[0:x]
             t.append(a)
             t.extend(c[x:])
             total.append(t)
     return total
 
 def isSquare(n):
     a = int(sqrt(n))
     if(a*a==n):
         return True
     return False
 
 def getOtherNumber(myPair, myNumber):
     a = myPair[0]
     b = myPair[1]
     la = []
     ia = []
     lb = []
     ib = []
     for x in range(len(a)):
         l = a[x]
         if l in la:
             ia[la.index(l)].append(x)
         else:
             la.append(l)
             ia.append([x])
     for x in range(len(b)):
         l = b[x]
         if l in lb:
             ib[lb.index(l)].append(x)
         else:
             lb.append(l)
             ib.append([x])
     aFirst = True
     foundA = []
     for x in range(len(la)):
         v = myNumber[ia[x][0]]
         if v in foundA:
             aFirst = False
             break
         else:
             foundA.append(v)
         for z in ia[x]:
             if myNumber[z]!=v:
                 aFirst = False
                 break
         if not aFirst:
             break
     bFirst = True
     foundB = []
     for x in range(len(lb)):
         v = myNumber[ib[x][0]]
         if v in foundB:
             bFirst = False
             break
         else:
             foundB.append(v)
         for z in ib[x]:
             if myNumber[z]!=v:
                 bFirst = False
                 break
         if not bFirst:
             break
     if not aFirst and not bFirst:
         return False
     final = []
     if aFirst:
         t = " "*len(a)
         for x in range(len(la)):
             v = foundA[x]
             for n in ib[lb.index(la[x])]:
                 t = t[0:n] + v + t[n+1:]
         final.append(t)
     if bFirst:
         t = " "*len(a)
         for x in range(len(lb)):
             v = foundB[x]
             for n in ia[la.index(lb[x])]:
                 t = t[0:n] + v + t[n+1:]
         final.append(t)
     return final
 
 def projectEulerProblemNinetyEight(myList):
     anagramPairs = []
     maxLength = 4
     for a in myList:
         for b in myList:
             if(a!=b and len(a)==len(b) and 6>len(a)>=maxLength and isAnagram(a, b)):
                 if(len(a)>maxLength):
                     maxLength = len(a)
                     anagramPairs = [sorted([a,b])]
                 else:
                     v = sorted([a,b])
                     if v not in anagramPairs:
                         anagramPairs.append(v)
     digitChoices = subset([0,1,2,3,4,5,6,7,8,9],maxLength)
     realDigitChoices = []
     for x in digitChoices:
         t = 0
         for y in x:
             t+=y
         if(t%9==0 or t%9==1 or t%9==4 or t%9==7):
             realDigitChoices.append(x)
     
     orderList = []
     for c in range(maxLength):
         orderList.append(c)
     orders = permutations(orderList)
     maxSquare = -1
     for myPair in anagramPairs:
         for a in realDigitChoices:
             for x in orders:
                 s = ""
                 for c in range(maxLength):
                     s+=str(a[x[c]])
                 if s[0]!="0" and isSquare(int(s)):
                     t = getOtherNumber(myPair, s)
                     if t!=False:
                         for x in t:
                             if x[0]!="0" and isSquare(int(x)):
                                 if max(int(s),int(x)) > maxSquare:
                                     maxSquare = max(int(s),int(x))
     
     return maxSquare
 
 # Accidentally found largest prime number at first. Oops!
 
 start = time.time()
 print projectEulerProblemNinetyEight(goodContents)
 print ("--- %s seconds ---" % (time.time()-start))
 
 '''
 Prints
 
 18769
 --- 0.592419862747 seconds ---
 
 for input of given list of words.
 ''' 

And with that, we’re done. I would like to return to this solution at some point to implement a complete, efficient solution. However, for the purposes of the given list of words, manual troubleshooting resulted in the best runtime.

Thanks for reading! See you tomorrow.

Design a site like this with WordPress.com
Get started