Reduce time complexity of program - python-3.x

I have written a function to remove items specified in a given list.
def remove_given_elements(arr1) :
b = []
x = int(input("Enter the number of items to be removed :"))
for i in range(x) :
y = int(input("Enter the position to be removed :"))
b.append(y)
arr3 = []
pos = 0
for i in range(len(arr1)) :
arr3.append(arr1[i])
for j in range(len(b)):
if pos == b[j]:
arr3.pop(b[j])
arr3.append(None)
pos += 1
arr4 = []
for i in arr3:
if i != None :
arr4.append(i)
return arr4
a = [100,200,323,434,512,656]
print("After removing elements",remove_given_elements(a))
Output :
Enter the number of items to be removed :3
Enter the position to be removed :1
Enter the position to be removed :3
Enter the position to be removed :4
After removing elements [100, 323, 656]
As, i am new to programming. I really don't know any methods to decrease my worst case time complexity. Any kind of help is appreciated or please guide me to use proper methods which decreases time complexity.

You can ask before for the positions and store them in a tuple. Then apply the function.
def remove(_list, pos):
return [v for i, v in enumerate(_list) if i not in pos]
positions = (1, 2, 3)
l = [1, 2, 3, 4, 5, 6, 7]
result = remove(l, positions)
print(result)
The function return a List Comprehension

Related

How to add each element in list to another element of same list in less time?

Input : l1 = [1,2,3,4,5,6]
Output : [7, 8, 9, 10, 11, 11]
To find the maximum sum of each pair of all elements in a list.
In general, i have to add each element in list to another element (not to itself).
Below is the code what i tried. I know this is complexity of (n^2)
Any better way to reduce complexity (can be both time and space) ?
Any better approach (may be with some modules or with just single for loop) ?
list l1 need not to be in sorted.
l2=[]
l3=[]
for i in range(len(l1)):
for j in range(len(l1)):
if i!=j:
l2.append(l1[i]+l1[j])
l3.append(max(l2))
l2.clear()
print(l3)
[7, 8, 9, 10, 11, 11]
Update:
Submitted this solution in hackerrank, but it fails for few cases.
Reason for failure is TimeLimitExceed (TLE). I assume, it's failing because of large numbers.
**Constraints:**
n = size_of_list
1<= n <= 4*10^4
1<= l1[i] <= 1024
1<= i <= n
1<= j <= n
j != i
Is it because of time-complexity, failing to handle these scenarios in above snippet ?
you can do something like this:
l1 = [1,2,3,4,5,6]
l2=[]
for i in range(len(l1)):
for j in range(i+1,len(l1)):
l2.append(l1[i]+l1[j])
l3=set(l2)
l2=list(l3)
print(l2)
output:
[3, 4, 5, 6, 7, 8, 9, 10, 11]
Sorting your list before processing it also helps.
Let me know if i have made any mistake.
You can do this in O(n).
The basic idea is to get the indices of the maximum element and the second maximum element in the list. Then for each element in the list, append the element + max_element, if the element is not the max_element. Otherwise, append the max_element + second_max_element.
I used the get_first_second_max_index to get the indices of the maximum element and the second maximum element because there might be identical elements in the list.
The code should look like this:
def get_first_second_max_index(nums):
if len(nums) < 2:
return None, None
first_max_index = 0 if nums[0] > nums[1] else 1
second_max_index = 0 if nums[0] <= nums[1] else 1
for index in range(2, len(nums)):
if nums[index] > nums[first_max_index]:
first_max_index, second_max_index = index, first_max_index
elif nums[index] > nums[second_max_index]:
second_max_index = index
return (first_max_index, second_max_index)
def max_sum_pair(nums):
res = []
if len(nums) >= 2:
first_max_index, second_max_index = get_first_second_max_index(nums)
for index in range(len(nums)):
if index == first_max_index:
res.append(nums[index] + nums[second_max_index])
else:
res.append(nums[index] + nums[first_max_index])
return res
nums = [1,2,3,4,5,6]
res = max_sum_pair(nums)
print(res)
For starters, we can use sorting to our advantage. The Python sorting method, sorted, operates in O(n log n) time. (See this question: What is the complexity of this python sort method?)
Once our numbers are sorted, the maximum sums are trivial. The maximum for a number is simply that number added to the last element in the sorted list or, if the number is the maximum element, the second to last element. Rewriting your code we could obtain:
l3 = []
l1 = sorted(l1)
for i in range(len(l1)):
if i + 1 == len(l1):
l3.append(l1[i] + l1[i - 1])
else:
l3.append(l1[i] + l1[-1])
print(l3)
I hope this helps. Let me know if I've misunderstood your question.

How many times should I loop to cover all cases of possible sums?

I am trying to solve this competitive programming problem using python3. The problem asks, given an array of size n, split the array into three consecutive, contiguous parts such that the first part has maximum sum and equals the sum of the third part. The elements in the array are positive integers.
My approach:
inputN = int(input())
inputString = input()
usableString = stringToList(inputString)
counting = 0
sum1 = usableString[0]
sum3 = usableString[-1]
maxSum1 = 0
countFromLeft = 1
countFromRight = 2
while counting < inputN-1:
if sum1 > sum3:
sum3 += usableString[-countFromRight]
countFromRight += 1
elif sum3 > sum1:
sum1 += usableString[countFromLeft]
countFromLeft += 1
elif sum1 == sum3:
maxSum1 = sum1
sum1 += usableString[countFromLeft]
countFromLeft += 1
counting += 1
print(maxSum1)
We read in the array elements and store them in a list usableString.
We set two variables sum1 and sum3 to the first and last elements of the list respectively.
We set a variable to keep track of the maximum sum of the first part of the list.
Finally, we set a variable counting to 0 which will represent the number of elements we have added from the list into sum1 or sum3.
The rest of the logic is in the while loop, which just checks if sum1 is larger than sum3 or the other way around and otherwise if they equal. After each iteration we add 1 to counting as an extra element has been included in a part. The while loop should stop when the number of elements used (i.e counting) is equal to the number of elements in the array - 1, since we added the first and last elements before entering the loop, which makes (array - 2), however, we still need to loop one additional time to check if sum1 and sum3 are equal.
I checked your submitted algorithm, and the problem is your stringToList function:
def stringToList(s):
list=[]
for elem in s:
if elem != " ":
list.append(int(elem))
return list
As far as I can tell, your main algorithm is completely fine, but stringToList does one crucial thing incorrectly:
>>> stringToList('2 4 6 8 10')
[2, 4, 6, 8, 1, 0]
# should be
[2, 4, 6, 8, 10]
As it treats each character individually, the two digits of 10 are turned into 1, 0. A simpler method which performs correctly would be to do the following:
# explanation
>>> input()
'2 4 6 8 10'
>>> input().split(' ')
['2', '4', '6', '8', '10']
>>> map(int, input().split(' ')) # applies the int function to all elements
<map object at 0x...>
>>> list(map(int, input().split(' '))) # converts map object into list
[2, 4, 6, 8, 10]
Sorry it took so long, I ended up making my own algorithm to compare to yours, ran my own tests, and then ran your code with the input to list method I just explained, and figured the only difference was your stringToList function. Took a while, but I hope it helps!
Just for the fun, here's my algorithm and turns out it was pretty similar to yours!
array = [1, 3, 2, 1, 4]
n = len(array)
slice = [0, n]
sum = [array[0], 0]
bestSum = 0
while slice[0] < slice[1]-1:
i = 0 if (sum[0] < sum[1]) else 1
slice[i] += 1-(2*i)
sum[i] += array[slice[i]]
if sum[0] == sum[1]: bestSum = sum[0]
# print(array[ : slice[0]+1], array[slice[0]+1 : slice[1]], array[slice[1] : ])
print(bestSum)

how to separate and sort numbers in python?

Given a variable containing integer numbers with the provisions of the number 0 (zero) in the variable is a separator between one number with another number. The numbers will be separated and ordered by the numbers in the numbers themselves. After that, the numbers from the sort will be rejoined without separating with the output in the form of integer numbers. Make a method / function that accepts parameters only a series of numbers and produces output like the description above.
def sort(nums):
for i in range (15):
minpos = 1
for j in range (i,6):
if nums[j] < nums[minpos]:
minpos = j
temp = nums[i]
nums[i] = nums[minpos]
nums[minpos] = temp
nums = [5,9,5,6,5,6,0,1,5,9,4,6,6,0,5,6]
sort(nums)
print(nums)
The output should be 55566914566956 , but actual output is [5, 5, 5, 5, 6, 6, 9, 0, 1, 5, 9, 4, 6, 6, 0, 6]
You can try the following function:
def sort(nums):
curr = []
ret = ''
for i in nums:
if i == 0:
ret += ''.join(map(str, sorted(curr)))
curr = []
else:
curr.append(i)
ret += ''.join(map(str, sorted(curr)))
return ret
print(sort([5,9,5,6,5,6,0,1,5,9,4,6,6,0,5,6]))
Prints:
55566914566956
def sort(nums):
result = list()
sub_array = list()
for i in nums:
if i == 0:
# sort sub array and append it to result
sub_array.sort()
result.extend(sub_array)
sub_array = list()
else:
sub_array.append(i)
# ensure that the last sub_array is also treated
sub_array.sort()
result.extend(sub_array)
return result
nums = [5,9,5,6,5,6,0,1,5,9,4,6,6,0,5,6]
result = sort(nums)
print(result)
The easiest way is to loop through your list and create a sub array of numbers up until you find a '0'. At this point, simply order your sub array, append it to your result list and continue until the end of your input string.

I am trying to print a list,which will have all the values which occurred more than once in the source list ,complexity should be as less as possible

I am trying to print a list, which will have all the values which occurred more than once in the source list, below is the solution I have used but it have time complexity of O(n*n), can somebody help me to print same result with less time complexity.
arr = [1,7,0,2,2,1,3,2,6,7]
req_arr = []
arrlen = len(arr)
for i in range(arrlen):
for j in range(i+1,arrlen):
if arr[i] == arr[j]:
if arr[i] in req_arr:
continue
else :
req_arr.append(arr[i])
print(req_arr)
#output : [1, 7, 2]
#time complexity : O(n*n)
Here is an O(2n) solution. We have two separate for-loops
arr = [1,7,0,2,2,1,3,2,6,7]
count = dict.fromkeys(arr,0)# initializing to zero
for i in arr:
count[i] += 1
[i for i,j in count.items() if j>1]
[1, 7, 2]
I tried this:
c = []
for i in a:
if i not in c:
if a.count(i) >1:
c.append(i)
print(c)
for the given list it took 4.0531158447265625e-06 time

Program thats asks for a number then prints out all its factors, 150 --> 2,3,5,5

n = int(input("What number do you want factored out"))
def factors(n):
for i in range(2,n):
if n % i == 0:
return i
n = n/i
return factors(n)
print(factors(n))
I'm currently using the current code, however I can only get the first factor. Can I not use recursion to repeat the code and generate all factors?
Is there a better way to approach this question?
Use a while loop instead:
def factors(n):
f = []
while n != 1:
for i in range(2, n + 1):
if n % i == 0:
f.append(i)
n //= i
break
return f
print(factors(150))
Or, with recursion:
def factors(n):
if n == 1:
return []
for i in range(2, n + 1):
if n % i == 0:
return [i] + factors(n // i)
print(factors(150))
Both output:
[2, 3, 5, 5]
The return keyword essentially terminates the execution of the function. Any statements immediately following a return statement will never be reached. So as soon as you find a factor and do return i, your function ends. Maybe you're confusing return i and print i? Alternatively, add it to an array and pass that down through the next recursive function call.
This can be done recursively, but it's probably best to do this algorithm iteratively because it's faster and more readable:
def factors(n):
for i in range(1, int(n ** 0.5) + 1):
if n % i == 0:
yield i
yield n // i
print(list(factors(25)))
This is far from industrial strength but should be reasonably fast. It allows duplicates, so you may wish to call set() before list(). You only need to iterate up to the square root of n and for any number i that is a factor, include the number that can be multiplied by i to get n as well.
if you want all the factors then you can do:
import numpy as np
fact = lambda x : np.arange(1,x+1)[x % np.arange(1,x+1)==0]
fact(100)
array([ 1, 2, 4, 5, 10, 20, 25, 50, 100])
fact(27)
array([ 1, 3, 9, 27])
if you just want the prime multipliers:
def facts(x,m=None,i=2):
if m is None:
m = []
if x //i >0:
if x % i ==0:
m.append(i)
facts(x // i,m ,i)
else:
facts(x,m,i+1)
return(m)
facts(150)
[2, 3, 5, 5]
facts(2*3*5*7*9*10)
[2, 2, 3, 3, 3, 5, 5, 7]

Resources