Fewest number of changes to an imperfect melody to make it perfect - python

I have just started learning how to code 'competitively' in competitions and came across this problem:
A 'perfect' melody is one that has the same 3 numbers repeating over, for example:
123123123
And so a 'non-perfect' one would be for example: 123122121
Now the question asks how many numbers need to be changed in an imperfect melody to make it 'perfect'. Below is an example: (in the first row of the input file , the first one is the amount of notes and the second one is the max value each note can take and then the rest of the numbers are the notes in order)
Example:
Example
I have produced a solution that doesn't solve most of the test cases and I don't see why. My code is below:
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1000000000)
# N is the number of notes.
N = None
# K is the largest number which could be a note.
K = None
# S contains the sequence of notes forming the song.
S = [None for x in range(100005)]
answer = None
# Open the input and output files.
input_file = open("melodyin.txt", "r")
output_file = open("melodyout.txt", "w")
# Read the value of N and K.
input_line = input_file.readline().strip()
N, K = map(int, input_line.split())
# Read each note in the song.
for i in range(0, N):
S[i] = int(input_file.readline().strip())
notes_list = []
for i in range(0, N):
notes_list.append(S[i])
count = 0
sep = []
for i in range(N//3):
sep.append([notes_list[count], notes_list[count+1], notes_list[count+2]])
count += 3
errors = 0
for i in range(len(sep)-1):
if sep[0][0] != sep[i+1][0]:
errors += 1
if sep[0][1] != sep[i+1][1]:
errors += 1
if sep[0][2] != sep[i+1][2]:
errors += 1
else:
pass
# Write the answer to the output file.
output_file.write("%d\n" % (errors))
# Finally, close the input/output files.
input_file.close()
output_file.close()
additionally these are the constraints:
• 3≤N≤99999.
• N is a multiple of three. • 1≤K≤100000.
• 1≤Si ≤K,for all i

Related

How to get percentage of combinations computed?

I have this password generator, which comute combination with length of 2 to 6 characters from a list containing small letters, capital letters and numbers (without 0) - together 61 characters.
All I need is to show percentage (with a step of 5) of the combinations already created. I tried to compute all the combinations of selected length, from that number a boundary value (the 5 % step values) and count each combination written in text file and when when the count of combinations meets the boundary value, print the xxx % completed, but this code doesn't seem to work.
Do you know how to easily show the percentage please?
Sorry for my english, I'm not a native speaker.
Thank you all!
def pw_gen(characters, length):
"""generate all characters combinations with selected length and export them to a text file"""
# counting number of combinations according to a formula in documentation
k = length
n = len(characters) + k - 1
comb_numb = math.factorial(n)/(math.factorial(n-length)*math.factorial(length))
x = 0
# first value
percent = 5
# step of percent done to display
step = 5
# 'step' % of combinations
boundary_value = comb_numb/(100/step)
try:
# output text file
with open("password_combinations.txt", "a+") as f:
for p in itertools.product(characters, repeat=length):
combination = ''.join(p)
# write each combination and create a new line
f.write(combination + '\n')
x += 1
if boundary_value <= x <= comb_numb:
print("{} % complete".format(percent))
percent += step
boundary_value += comb_numb/(100/step)
elif x > comb_numb:
break
First of all - I think you are using incorrect formula for combinations because itertools.product creates variations with repetition, so the correct formula is n^k (n to power of k).
Also, you overcomplicated percentage calculation a little bit. I just modified your code to work as expected.
import math
import itertools
def pw_gen(characters, length):
"""generate all characters combinations with selected length and export them to a text file"""
k = length
n = len(characters)
comb_numb = n ** k
x = 0
next_percent = 5
percent_step = 5
with open("password_combinations.txt", "a+") as f:
for p in itertools.product(characters, repeat=length):
combination = ''.join(p)
# write each combination and create a new line
f.write(combination + '\n')
x += 1
percent = 100.0 * x / comb_numb
if percent >= next_percent:
print(f"{next_percent} % complete")
while next_percent < percent:
next_percent += percent_step
The tricky part is a while loop that makes sure that everything will work fine for very small sets (where one combination is more than step percentage of results).
Removed try:, since you are not handling any errors with expect.
Also removed elif:, this condition is never met anyway.
Besides, your formula for comb_numb is not the right one, since you're generating combinations with repetition. With those changes, your code is good.
import math, iterations, string
def pw_gen(characters, length):
"""generate all characters combinations with selected length and export them to a text file"""
# counting number of combinations according to a formula in documentation
comb_numb = len(characters) ** k
x = 0
# first value
percent = 5
# step of percent done to display
step = 5
# 'step' % of combinations
boundary_value = comb_numb/(100/step)
# output text file
with open("password_combinations.txt", "a+") as f:
for p in itertools.product(characters, repeat=length):
combination = ''.join(p)
# write each combination and create a new line
f.write(combination + '\n')
x += 1
if boundary_value <= x:
print("{} % complete".format(percent))
percent += step
boundary_value += comb_numb/(100/step)
pw_gen(string.ascii_letters, 4)

Finding missing lines in file

I have a 7000+ lines .txt file, containing description and ordered path to image. Example:
abnormal /Users/alex/Documents/X-ray-classification/data/images/1.png
abnormal /Users/alex/Documents/X-ray-classification/data/images/2.png
normal /Users/alex/Documents/X-ray-classification/data/images/3.png
normal /Users/alex/Documents/X-ray-classification/data/images/4.png
Some lines are missing. I want to somehow automate the search of missing lines. Intuitively i wrote:
f = open("data.txt", 'r')
lines = f.readlines()
num = 1
for line in lines:
if num in line:
continue
else:
print (line)
num+=1
But of course it didn't work, since lines are strings.
Is there any elegant way to sort this out? Using regex maybe?
Thanks in advance!
the following should hopefully work - it grabs the number out of the filename, sees if it's more than 1 higher than the previous number, and if so, works out all the 'in-between' numbers and prints them. Printing the number (and then reconstructing the filename later) is needed as line will never contain the names of missing files during iteration.
# Set this to the first number in the series -1
num = lastnum = 0
with open("data.txt", 'r') as f:
for line in f:
# Pick the digit out of the filename
num = int(''.join(x for x in line if x.isdigit()))
if num - lastnum > 1:
for i in range(lastnum+1, num):
print("Missing: {}.png".format(str(i)))
lastnum = num
The main advantage of working this way is that as long as your files are sorted in the list, it can handle starting at numbers other than 1, and also reports more than one missing number in the sequence.
You can try this:
lines = ["abnormal /Users/alex/Documents/X-ray-classification/data/images/1.png","normal /Users/alex/Documents/X-ray-classification/data/images/3.png","normal /Users/alex/Documents/X-ray-classification/data/images/4.png"]
maxvalue = 4 # or any other maximum value
missing = []
i = 0
for num in range(1, maxvalue+1):
if str(num) not in lines[i]:
missing.append(num)
else:
i += 1
print(missing)
Or if you want to check for the line ending with XXX.png:
lines = ["abnormal /Users/alex/Documents/X-ray-classification/data/images/1.png","normal /Users/alex/Documents/X-ray-classification/data/images/3.png","normal /Users/alex/Documents/X-ray-classification/data/images/4.png"]
maxvalue = 4 # or any other maximum value
missing = []
i = 0
for num in range(1, maxvalue+1):
if not lines[i].endswith(str(num) + ".png"):
missing.append(num)
else:
i += 1
print(missing)
Example: here

Project Euler Project 67 - Python

I am doing the Project Euler #67 in Python. My program, which worked for Project 18, does not work for Project 67.
Code (excludes the opening of the file and the processing of information):
for i in range(len(temp)):
list1 = temp[i]
try:
list2 = temp[i+1]
trynum1 = list1[lastinput] + max(list2[lastinput],list2[lastinput+1])
try:
trynum2 = list1[lastinput+1] + max(list2[lastinput+1],list2[lastinput+2])
if trynum1 > trynum2:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
lastinput += 1
except IndexError:
outputlist.append(list1[0])
except IndexError:
if list1[lastinput] > list1[lastinput+1]:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
Variables:
temp is the triangle of integers
outputlist is a list which stores the numbers chosen by the program
I know the answer is 7273, but my program finds 6542. I cannot find an error which causes the situation. Please may you help me on it.
Logic
My approach to this program is to find one number (list1[lastinput]) and add it up with the larger number of the two below it (trynum1), compare with the number to the right of the first number (list1[lastinput+1]), adding the larger number of two below it (trynum2). I append the larger one to the output list.
This approach is logically flawed. When you're in row 1, you don't have enough information to know whether moving right or left will lead you to the largest sum, not with only a 2-row lookahead. You would need to look all the way to the bottom to ensure getting the best path.
As others have suggested, start at the bottom and work up. Remember, you don't need the entire path, just the sum. At each node, add the amount of the better of the two available paths (that's the score you get in taking that node to the bottom). When you get back to the top, temp[0][0], that number should be your final answer.
I thought day and night about problem 18 and I solved it, the same way I solved this one.
P.S. 100_triangle.txt is without 1st string '59'.
# Maximum path sum II
import time
def e67():
start = time.time()
f=open("100_triangle.txt")
summ=[59]
for s in f:
slst=s.split()
lst=[int(item) for item in slst]
for i in range(len(lst)):
if i==0:
lst[i]+=summ[i]
elif i==len(lst)-1:
lst[i]+=summ[i-1]
elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
lst[i]+=summ[i-1]
else:
lst[i]+=summ[i]
summ=lst
end = time.time() - start
print("Runtime =", end)
f.close()
return max(summ)
print(e67()) #7273
Though starting from the bottom is more efficient, I wanted to see if I could implement Dijkstra's algorithm on this one; it works well and only takes a few seconds (didn't time it precisely):
from math import inf
f = open("p067_triangle.txt", "r")
tpyramid = f.read().splitlines()
f.close()
n = len(tpyramid)
pyramid = [[100 - int(tpyramid[i].split()[j]) for j in range(i+1)] for i in range(n)]
paths = [[inf for j in range(i+1)] for i in range(n)]
paths[0][0] = pyramid[0][0]
def mini_index(pyr):
m = inf
for i in range(n):
mr = min([i for i in pyr[i] if i >= 0]+[inf])
if mr < m:
m, a, b = mr, i, pyr[i].index(mr)
return m, a, b
counter = 0
omega = inf
while counter < n*(n+1)/2:
min_weight, i, j = mini_index(paths)
if i != n-1:
paths[i+1][j] = min( paths[i+1][j], min_weight + pyramid[i+1][j])
paths[i+1][j+1] = min( paths[i+1][j+1], min_weight + pyramid[i+1][j+1])
else:
omega = min(omega, min_weight)
paths[i][j] = -1
counter += 1
print(100*n - omega)
Here is my solution. Indeed you have to take the bottom - up approach.
Result confirmed with PE. Thanks!
def get_triangle(listLink):
triangle = [[int(number) for number in row.split()] for row in open(listLink)]
return triangle
listOfLists = get_triangle('D:\\Development\\triangle.txt')
for i in range(len(listOfLists) - 2, -1, -1):
for j in range(len(listOfLists[i])):
listOfLists[i][j] += max(listOfLists[i+1][j], listOfLists[i+1][j+1])
print(listOfLists[0][0])

Stuck: My own vesion for generating permutation

I am trying to write my own code for generating permutation of items represented by numbers. Say 4 items can be represented by 0,1,2,3
I've seen the code from itertools product. That code is pretty neat. My way of coding this is using binary or ternary,... My code below only works for bits of less than 10. Part of this code split the str using list(s). Number 120 in base 11 is 1010, splitting '1010' yields, 1,0,1,0. For it to work correctly, I need to to split to 10, 10. Is there a way around this and still work with the rest of the code?
Alternatively, what is a recursive version for this? Thanks
aSet = 11
subSet = 2
s = ''
l = []
number = aSet**subSet
#finding all permutation, repeats allowed
for num in range(number):
s = ''
while num//aSet != 0:
s = str(num%aSet) + s
num = num//aSet
else:
s = str(num%aSet) + s
s = s.zfill(subSet)
l.append(list(s))
Indeed, the problem with using a string, is that list(s) will chop it into individual characters. You should not create a string at all, but use a list for s from the start:
aSet = 11
subSet = 2
l = []
number = aSet**subSet
#finding all permutation, repeats allowed
for num in range(number):
s = []
for _ in range(subSet):
s.insert(0, num%aSet)
num = num//aSet
l.append(s)

Turbo sort - Time Limit Exceeded

Am trying to solve a Codechef problem (Turbo Sort). The problem is
Given the list of numbers, you are to sort them in non decreasing
order.
Input
t – the number of numbers in list, then t lines follow [t <= 10^6].
Each line contains one integer: N [0 <= N <= 10^6]
Output
Output given numbers in non decreasing order.
Example
Input:
5 5 3 6 7 1
Output:
1 3 5 6 7
My Solution is :
l = []
t = input()
MAX = 10**6
while t <= MAX and t != 0:
n = input()
l.append(n)
t = t - 1
st = sorted(l)
for x in st:
print x
The challenge is this program should run in 5 sec. When i submit the file, codechef says it is exceeding the time and needs optimization.
Can some one help, how to optimize it ?
My accepted solutions:
import sys
from itertools import imap
T = int(raw_input())
lines = sys.stdin.readlines()
lis = imap(str, sorted(imap(int, lines)))
print "\n".join(lis)
A readable version(accepted solution) :
import sys
T = raw_input()
lines = sys.stdin.readlines() #fetch all lines from the STDIN
lines.sort(key=int) #sort the list in-place(faster than sorted)
print "\n".join(lines) #use `str.join` instead of a for-loop
Things like readlines should be supported. I've just made an attempt and got this as an accepted solution:
import sys
print '\n'.join(map(str, sorted(map(int, sys.stdin.read().split()[1:]))))
Not pretty but functional. Took me a bit before I figured out you had to skip the first number, debugging is a bit annoying with this system ;)

Categories

Resources