How do I close the loop? - python

I am given an array of n numbers [a0,a1, a2, …, an-1] and I am supposed to write a function named sumOfThree that takes in the array and a number K as the only 2 arguments and outputs the number of unique unordered triplets in the array that sum to K. This is my code:
def sumOfArray(arr,K):
arr.sort()
s=set()
for i in range(len(arr)-2):
j=i+1
k=len(arr)-1
while j<k:
if arr[i]+arr[j]+arr[k]==K:
s.add((arr[i],arr[j],arr[k]))
elif arr[i]+arr[j]+arr[k]<K:
j+=1
else:
k-=1
return len(s)
However I am unable to find the answer. Any help please?

Just as MZ mentioned,
when arr[i]+arr[j]+arr[k]==K, the i,j,k never changed.
However, if you just add a single break as cewaphi mentioned, the while loop will stop at first match for every i loop, instead of walking through all the combinations.
Here is another way to solve the problem:
def sumOfArray(arr, K):
arr.sort()
s = set()
count = 0
for i in range(len(arr) - 2):
for j in range(i+1,len(arr)-1):
for k in range(j+1,len(arr)):
if arr[i] + arr[j] + arr[k] == K:
s.add((arr[i], arr[j], arr[k]))
print('Done')
length = print('length: ' + str(len(s)))
return length

As MZ stated, you are stuck in your if condition.
Either increment j or decrement k so that the condition j < k is met.
Or if you are done with increment i and want to continue with i+1, simply add a break:
if arr[i]+arr[j]+arr[k]==K:
s.add((arr[i],arr[j],arr[k]))
break

Related

Palindrome Partitions

Given a string split it into as few strings as possible such that each string is a palindrome
k = "racecarannakayak"
palin = [] # to get palindrome strs
i, j = 0, 2
while j != len(k) + 1:
if k[i:j] == k[:j][::-1]:
palin.append(k[i:j])
i += 1
j += 1
print(palin)
the result is ["racecar"] but it should be ["racecar", "anna", "kayak"]
what is wrong with my code??
There are a few issues with your code.
First, your pointer i keeps iterating even though your point j is
smaller than it in most of the iterations. Meaning you are doing
stuff like k[10:2] which will be pointless.
Second, your pointer j works only once over the whole array. Meaning
you either need multiple passes OR you need to reset the i pointer to
the last position of j pointer IF you find a palindrome.
Third, there is no condition to make sure that single alphabet string
is not considered a palindrome by your inversion logic
Last, there seems to be a typo, as mentioned by #fas in the comments. k[i:j]==k[i:j][::-1] instead of what you have written.
If you consider the above 3 and make the necessary changes you should get the right results to your code as below -
k = "racecarannakayak"
palin = [] # to get palindrome strs
i, j = 0, 2
while j != len(k) + 1:
if k[i:j] == k[i:j][::-1] and len(k[i:j])>2: #Check length is >2
palin.append(k[i:j])
i=j #Reset i pointer to current j
j += 1
print(palin)
['racecar', 'anna', 'kayak']

Efficient permutations of array elements with no repetitions in python [duplicate]

So I received a challenge that states the following:
"Design a program that takes as input a 9 digit number where no digit appears twice and produces as output an arrangement of the same 9 digits corresponding to the next highest number. If no such number exists, the algorithm should indicate this. So for example, if the input is 781623954 the output would be 781624359."
So I came up with this idea to flip the indexes, so check the last index with the one right before to see which is bigger and compare then flip if necessary but for some reason my code isn't working. I only did the work for checking the last two digits not all the digits, so if you can help me out and check it for me and if you have any better ideas on how to tackle this problem, please share.
input = raw_input("Enter 9 Digits: ")
x = 9
while x>0:
x-=1
if input[8] > input[7]:
temp = input[8]
input[8] == input[7]
input[7] == temp
print input
break
Here's a more efficient approach, using the algorithm of the 14th century Indian mathematician Narayana Pandita, which can be found in the Wikipedia article on Permutation. This ancient algorithm is still one of the fastest known ways to generate permutations in order, and it is quite robust, in that it properly handles permutations that contain repeated elements.
The code below includes a simple test() function that generates all permutations of an ordered numeric string.
#! /usr/bin/env python
''' Find the next permutation in lexicographic order after a given permutation
This algorithm, due to Narayana Pandita, is from
https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists,
the permutation is the last permutation.
2. Find the largest index k greater than j such that a[j] < a[k].
3. Swap the value of a[j] with that of a[k].
4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
Implemented in Python by PM 2Ring 2015.07.28
'''
import sys
def next_perm(a):
''' Advance permutation a to the next one in lexicographic order '''
n = len(a) - 1
#1. Find the largest index j such that a[j] < a[j + 1]
for j in range(n-1, -1, -1):
if a[j] < a[j + 1]:
break
else:
#This must be the last permutation
return False
#2. Find the largest index k greater than j such that a[j] < a[k]
v = a[j]
for k in range(n, j, -1):
if v < a[k]:
break
#3. Swap the value of a[j] with that of a[k].
a[j], a[k] = a[k], a[j]
#4. Reverse the tail of the sequence
a[j+1:] = a[j+1:][::-1]
return True
def test(n):
''' Print all permutations of an ordered numeric string (1-based) '''
a = [str(i) for i in range(1, n+1)]
i = 0
while True:
print('%2d: %s' % (i, ''.join(a)))
i += 1
if not next_perm(a):
break
def main():
s = sys.argv[1] if len(sys.argv) > 1 else '781623954'
a = list(s)
next_perm(a)
print('%s -> %s' % (s, ''.join(a)))
if __name__ == '__main__':
#test(4)
main()
I am not convinced that your approach of flipping digits is guaranteed to find the next highest number (at least not without further checks)
Here a simple solution:
Simply increment the input number and check if the conditions are met or if no number can be found.
set() can be used to get the set of unique digits in the number.
input_num = '781623954'
next_num = int(input_num) + 1
input_digits = set(input_num)
found = False
while not found:
next_num += 1
next_digits = set(str(next_num))
found = len(next_digits) == 9 and input_digits == next_digits
if next_num > 987654321:
break
if found:
print(next_num)
else:
print("No number was found.")
input[8] == input[7]
input[7] == temp
you probably meant:
input[8] = input[7]
input[7] = temp
didn't you?
Which, as stated in the comments, wouldn't work directly on the string, as it is immutable in Python. So, as a first step, you could make a list of characters from that string:
input = list(input)
and as a last step, get a string back from the modified list:
input = ''.join(input)
BTW, you might want to benefit from Python tuple unpacking which allows you to swap two variables without having to introduce a third one:
input[7], input[8] = input[8], input[7]

Checking loop in Python

I have this question about loops.
Imagine You have this data array:
list = [1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1]
How would You write a loop which checks if the previous number is lower, and the next after the checked one (Condition looks like this [5,6,5]). So the loop will get to number 9 and print it or save it, whatever.
Using next with a generator expression:
lst = [1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1]
res = next(j for i, j, k in zip(lst, lst[1:], lst[2:]) if i < j and i == k)
If you need all such numbers, use a list comprehension instead:
res = [j for i, j, k in zip(lst, lst[1:], lst[2:]) if i < j and i == k]
If you need a condition that will show all numbers that are higher than their previous and next ones:
lst = [1,2,3,4,3,2,3,1,2,1,2,3,4,5,6,7,8,6]
res = [j for i, j, k in zip(lst, lst[1:], lst[2:]) if i < j > k]
[4, 3, 2, 8] is printed.
Explanation
You can iterate the list with shifted versions of itself via zip.
For each triplet, test your two conditions.
Use next to extract such triplets; if no such triplet exists, you will meet StopIteration error.
Never name a variable after a built-in, e.g. use lst instead of list.
You could just write a simple loop that checks the previous number is less than the current number, and the next number is equal to the previous number:
lst = [1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1]
for i in range(len(lst)):
if lst[i-1] < lst[i] and lst[i-1] == lst[i+1]:
print(lst[i])
# 9

Can't get this break statement to work [duplicate]

This question already has answers here:
How can I break out of multiple loops?
(39 answers)
Closed 5 years ago.
I want to find the highest number not in the list. The break should end the last for loop and leave me with Ans = highest number not in list. Why doesn't it work
A = [1,3,5,9,11]
u = A[0]
for i in range(1, len(A)):
if A[i] > u:
u = A[i]
if u <= 0:
Ans = 1
else:
for j in range(u ,0, -1):
if j not in A:
Ans = j
print(Ans)
break
break gets you out of the inner loop, you also need to exit the outer one. You could do this using a boolean flag, etc... but I prefer using a for - else construct
for-else, means no break, that is the loop will resume in the else attached to the for when there is no break in the inner loop, otherwise, it will execute the following.
continue, takes you to the end of the loop.
Now, it seems your logic may also have a problem, the answer printed is 2
A = [1,3,5,9,11]
u = A[0]
for i in range(1, len(A)):
if A[i] > u:
u = A[i]
if u <= 0:
Ans = 1
else:
for j in range(u ,0, -1):
if j not in A:
Ans = j
print(Ans)
break
else: # <-- attention, this "else" must be aligned with the preceding "for", not the "if"
continue
break
As already mentioned, the break works fine, breaking from the loop it is in -- but not from the loop above that!
Alternatively to using for/else or moving the entire calculation into a function and using return instead of break, you could also replace the nested loop with a generator, lazily finding the next value that satisfies the condition. If that value is not None (the default), break from the outer loop.
else:
r = next((j for j in range(u ,0, -1) if j not in A), None)
if r is not None:
Ans = r
print(Ans)
break
# foo bar et al.
Seems the indentation was wrong as per your suggestions. While all your other suggestions were more elegant my solution turned out to be:
A = [1,3,5,9,11]
u = A[0]
for i in range(1, len(A)):
if A[i] > u:
u = A[i]
if u <= 0:
Ans = 1
print(Ans)
else:
for j in range(u ,0, -1):
if j not in A:
Ans = j
print(Ans)
break
Your break doesn't work, because your indentation for if u <= 0: and further is wrong.
A = [-1, -3, -5, -9, -11]
Ans = 1
for j in range(max(A)-1, max(0, min(A)), -1):
if j not in A:
Ans = j
print(Ans)
break
However, I advise you to use NumPy if your list is huge, because it is much faster.
# Find the highest number not in the list
import numpy as np
l = [1,3,5,9,11]
a = np.array(l)
ans = 1
for i in range(a.max()-1, max(0, a.min()), -1):
if i not in a:
ans = i
print(i)
break

Program terminated due to time out

PROBLEM :
You are given a list of size N, initialized with zeroes. You have to perform M operations on the list and output the maximum of final values of all the elements in the list. For every operation, you are given three integers a,b and k and you have to add value to all the elements ranging from index a to b(both inclusive).
Input Format
First line will contain two integers N and M separated by a single space.
Next lines will contain three integers a,b and k separated by a single space.
Numbers in list are numbered from 1 to N.
Here is the code which I have written:
n,m=map(int,input().split())
arr=[]
for i in range(n+1):
arr.append(0)
for j in range(m):
a,b,k=map(int,input().split())
for i in range(a,b+1):
arr[i]+=k;
print(max(arr))
When I try to submit my solution I get a "TERMINATED DUE TO TIMOUT" message.Could you please suggest a strategy to avoid these kind of errors and also a solution to the problem.
Thanks in advance!
Don't loop over the list range; instead, use map again to increment the indicated values. Something like
for j in range(m):
a,b,k=map(int,input().split())
arr[a:b+1] = map(lambda <increment-by-k>, arr[a:b+1])
This should let your resident optimization swoop in and save some time.
You probably need an algorithm that has better complexity than O(M*N).
You can put interval delimiters in a list:
n,m=map(int,input().split())
intervals = []
arr = [0 for i in range(n)]
for j in range(m):
a,b,k=map(int,input().split())
intervals += [(str(a), "begin", k)]
intervals += [(str(b), "end", k)]
intervals = sorted(intervals, key=lambda x: x[0]+x[1])
k, i = 0, 0
for op in intervals:
ind = int(op[0])
if op[1] == "begin":
while ind > i:
arr[i] += k
i += 1
k += op[2]
else:
while i <= ind:
arr[i] += k
i+= 1
k -= op[2]
print(arr)
If the sorting algorithm is O(MlogM), this is O(MlogM + N)

Categories