I have written a code and run it, and it works fine. But I wanted to understand what is happening in the following:
nums = [4, 5, 1, 8]
target = 12
def TwoSum(nums, target):
comps = dict()
for i in range(len(nums)):
comp = target - nums[i]
if nums[i] in comps:
return [comps[nums[i]], i]
else:
comps[comp] = i
print(TwoSum(nums, target))
I understand that this is using a dict, and the idea is to add elements from nums to it, then doing target - nums[i] and then checking if this is in the dict, and if it is, then returning the indices of the two numbers that sum to the target.
But how is comps = dict() used? Is it necessary? Because in the code it doesn't seem to be storing anything! Except for the last line it is used- but I don't understand what it does- can someone please explain?
First, your code was using self as first argument of TwoSum. It should be eliminated given that this is a static function, not a class method. (Fixed).
The line comp = dict() is an initialization of comp to an empty dict. It could be written in a more pythonic way: comp = {}.
comp appears to store the complement (the difference between target and nums[i]) as comps[diff] = i. Thereafter, when you examine a number nums[j], if the complement is already in comps, that j and the corresponding previous i is the pair of indices you are looking for.
In our case, it stores number as a key thats required to find a target, and index of opposit number in nums as value.
So, for example, when we have target at 12 and nums [4,5,1,8] , at the iteration on the number 4, 8->0 will be added to comps, when iteration will get to the number 8, we will check if we have number 8 in comps, and then return value of that number in comps, which is 0, and index of current iterating number, which is 3.
Related
class Solution:
def firstRepeated(self,A, n):
#arr : given array
#n : size of the array
D={}
for i in range(n):
if A[i] not in D:
D[A[i]]=[i]
else:
D[A[i]].append(i)
c=0
for i in D:
if(len(D[i])>1):
c+=1
return (D[i][0]+1)
if(c==0): return -1
A=[1 ,5 ,3, 4, 3, 5, 6]
n=len(A)
M=Solution()
print(M.firstRepeated(A,n))
this is a problem from geeks for geeks.
" Given an array arr[] of size n, find the first repeating element. The element should occurs more than once and the index of its first occurrence should be the smallest"
the index positions(returned) are assumed to start from 1. If there is no
such element that has frequency more than 1 , we gotta return -1
This code is actually working correctly in VS code, but whenever I use
it in GFG IDE, it's failing(shows 3 as output instead of 2)
Kindly help, as I have no idea what's wrong here.
Your code is returning the index of the repeating element based on the order that keys are stored in the dictionary. After having collected all values in a dictionary keyed by number, your code iterates that dictionary like this:
for i in D:
The order in which this loop will visit the dictionary keys (indexes), depends on the Python version. See Are dictionaries ordered in Python 3.6+?.
At the time of writing Geeks for Geeks uses version 3.5.2, and so the order the keys are visited is undefined, which means that sometimes your function will not return the expected answer on their web site, while on your own environment it will always be correct (if you have a more recent version).
Correction
You can change your code so it does not rely on the order of the dictionary. Instead, during insertion, check which is the dictionary key with the least value. Here is your code corrected just with that change in mind:
class Solution:
def firstRepeated(self,A, n):
D = {}
c = len(A)
for i in range(n):
if A[i] not in D:
D[A[i]] = i # No need to maintain a list
elif D[A[i]] < c: # When the dupe's first index is earlier...
c = D[A[i]]
if c == len(A):
return -1
return c + 1
This will do the trick.
I checked in https://www.onlinegdb.com/online_python_compiler and works correctly.
it works also in https://ide.geeksforgeeks.org/
x = [1,2,3,4,50,6,3,2,3,8]
for i in x:
if i > x[x.index(i)+1:10]:
print(i)
TypeError: '>' not supported between instances of 'int' and 'list'
I want to determine which number is larger than all the numbers afterward, in this circumstance, 50.
However, came out this error.
Does anyone have any idea to solve this problem?
This should work:
for i in range(len(x)):
if all(x[i] > x[j] for j in range(i + 1, len(x))):
print(i)
Please try these simple solutions and see which one fits best for your need. I have left comments briefly explaining what each case does. Keep coding in Python, it is a great computer language, pal!
numbers_lst = [1, 2, 3, 4, 50, 6, 3, 2, 3, 8]
# 1- Fast approach using built in max function
print("Using Max Built-in function: ", max(numbers_lst))
# 2- Manual Approach iterating all the elements of the list
max_num = numbers_lst[0]
for n in numbers_lst:
max_num = n if n >= max_num else max_num
print("Manual Iteration: ", max_num)
# 3- Using comprehensions, in this case for the list
max_num = numbers_lst[0]
[max_num:=n for n in numbers_lst if n >= max_num]
print("List Comprehension: ", max_num)
# 4- Sort the list in ascending order and print the last element in the list.
numbers_lst.sort()
# printing the last element, which is in this case the largest one
print("Using the sort list method:", numbers_lst[-1])
# 5 - Using the built in sorted function and getting the last list element afterwards
sorted_lst = sorted(numbers_lst, reverse=True)
max_num = sorted_lst[0]
print("Sorted List: ", max_num)
Although answer given by #Green Cloak Guy is a perfectly valid answer, it is inefficient as it is O(n^2) solution. I present below an O(n) solution by storing the greatest elements from the right.
x = [1,2,3,4,50,6,10,2,3,1]
largest = [0 for i in range (len(x))] # temporary array to store, for every index i, the largest number from the right to index i
largest[-1] = x[-1]
ans = [] # list to store numbers satisfying condition
for i in range (len(x) - 2, -1, -1):
if (x[i] > largest[i+1]):
ans.append(x[i])
largest[i] = max (x[i], largest[i+1])
for i in range (len(ans)-1,-1,-1): # print elements in the same order as given list
print (ans[i])
You could also make use of python's built in sorted method.
x = [1,2,3,4,50,6,3,2,3,8]
y = sorted(x, reverse=True)
print(y[0])
The issue is that you are comparing an individual value against a whole list of values. You will either have to make another loop or use the max() function on that sublist to get the highest value it contains.
A more efficient strategy is to process the list backwards while keeping track of the maximum number encountered.
By accumulating the maximum value backwards in the list and comparing it to the previous number, you can find all the numbers that are greater than all their successor. This produces results in reverse but the accumulate() function from the itertools module can be used to get these reversed maximum and the zip() function will allow you to combine them with the numbers in the original list for comparison/selection purposes.
x = [1,2,3,4,50,6,3,2,3,8]
from itertools import accumulate
r = [n for n,m in zip(x[-2::-1],accumulate(x[::-1],max)) if n>m]
print(r)
[50]
This returns a list because, depending on the data, there could be multiple numbers satisfying the condition:
x = [1,2,3,4,50,6,3,2,3,1]
r = [n for n,m in zip(x[-2::-1],accumulate(x[::-1],max)) if n>m][::-1]
print(r)
[50, 6, 3]
Question: Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
class Solution:
def twoSum(self, nums, target):
lookup={}
for cnt, num in enumerate (nums):
if target-num in lookup:
return lookup[target-num], cnt
lookup[num]=cnt
I am not able to understand the steps after for loop is used.I am new on Python, someone please help me.
Let me help you understand by explaining what the code does and how it solves the problem.
We need to find two numbers that sum to 9, to achieve this, we can iterate over every number in the array and then look if we already encountered a number that equals the target number minus the number we are currently on. If we haven't encountered such a number yet, we store the current number and its corresponding index.
Because we need to return the indices, we want to be able to look for the number-target pairs and immediately get the index. The solution uses a dictionary to store a number (key) and return an index as (value).
We iterate over every number, if we already encountered target-number before, we can return the current index and the index of the target-number, if we haven't encountered that number, we simply store the current number and its index.
The enumerate part, simply provides an index along with the value of the array that is being iterated, in the form of (id, item).
class Solution:
def twoSum(self, nums, target):
# Here a dictionary is created, which will store value, index as key, value pairs.
lookup={}
# For every number in the array, get the index (cnt) and number (num)
for cnt, num in enumerate (nums):
# If we find target-num, we know that num + target-num = target
if target-num in lookup:
# Hence we return the index of the target-num we stored in the dict, and the index of the current value (cnt)
return lookup[target-num], cnt
# Otherwise we store the current number as key with its index as value
lookup[num]=cnt
enumerate() method adds a counter to an iterable and returns it in a form of enumerate object. This enumerate object can then be used directly in for loops or be converted into a list of tuples using list() method.
For e.g.
>>>list(enumerate("abc"))
Gives
[(0, 'a'), (1, 'b'), (2, 'c')]
For easy understanding, I'm commenting your program. Go through it, you'll surely understand.
class Solution:
def twoSum(self, nums, target):
# lookup is a dictionary that stores the number and its index
# e.g. '{7:1}'
# number 7 at index 1
lookup={}
# As explained above cnt and num will receive values one by one along with index.
for cnt, num in enumerate (nums):
# We look if the number required to be added into the 'num' is present in dictionary
if target-num in lookup:
# if value found in lookup then we return the current index along with the index of number found in lookup.
return lookup[target-num], cnt
# After every loop insert the current value and its index into the lookup dictionary.
lookup[num]=cnt
Hope, I answered your query in the way you wanted. Please comment below, if anything is left unanswered, I'll surely try to answer that as well.
This question already has answers here:
Are Python variables pointers? Or else, what are they?
(9 answers)
Closed 3 years ago.
I am writing a little program to create a list of permutations. I read about the algorithm on wikipedia.
My algorithm basically takes an initially sorted list of numbers, and permutes it in place. It then appends this new permutation to a list. When all permutations are found, it returns the list of lists containing all the permutations. It is very good at printing out the expected results, but when I try to add those results to a list, things get a little funny.
I noticed that every time I find the next permutation and append it to, the previous list elements get updated to the new permutation. So, at the end of it all, what gets returned is a list containing a bunch of copies of the same permutation (exactly the last permutation).
I've read that Python is pass by value, pass by reference and I've also read that it's neither. I'm not smart enough to argue with any of those people, but I am wondering why my program is doing this, and how to remedy it:
def lexi_order(nums):
permutations = []
length = len(nums)
while True:
# find largest index i such that nums[i] < nums[i + 1]
exists = False
for j, elem in enumerate(nums):
# check if last element
if j == length - 1:
break
if elem < nums[j + 1]:
i = j
exists = True
if not exists:
break
# find largest index k, such that i < k AND nums[i] < nums[k]
for j in range(i + 1, length):
if nums[j] > nums[i]:
k = j
# swap order of nums[i] and nums[k]
nums[i], nums[k] = nums[k], nums[i]
# reverse order of elements starting at position i+1
to_reverse = nums[i+1:][::-1]
nums[i+1::] = to_reverse
permutations.append(nums)
print(permutations)
return permutations
You're modifying the input (nums) in place each iteration through the loop, and then you keep adding a reference to the input to permutations. To fix it, make a copy of nums at the beginning of the loop and use it instead of the original everywhere inside it.
When you append nums to permutations, you are appending a reference to it, not copying all of the data over. When you modify nums, it gets modified everywhere. Python is pass by reference. If you make a change to a variable (not to be confused with reassigning it), that change will be reflected everywhere.
You need to make a copy of the passed nums, otherwise you are working on the passed reference. E.g.
def lexi_order(nums):
permutations = []
nums = list(nums) # We are now working on a copy, and won't mutate the original whatsoever.
length = len(nums)
...
I'm new to python and trying to solve my homework... I'm trying to create a recursion function that takes a list of numbers [a, b, c....] and turns it to this list: [a, a+b, a+b+c, ....].
This is my code:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
new_list=numbers
last=new_list[-1]
if numbers==[]:
return numbers
if len(numbers) == 1:
return numbers[0]
new_list.remove(last)
rec= rec_cumsum(new_list)
new_list.append(rec+last)
return last+rec
this works but because I used return for last+rec, I can't use return to get the list back (new_list). Please explain to me what did I do wrong... thanks!
Let's write some test cases and practice some test-driven development:
tests = [[], # Desired answer: []
[1], # [1]
[1,2], # [1, 3]
[1,2,3], # [1, 3, 6]
[1,2,1,3]] # [1, 3, 4, 7]
for t in tests:
print(rec_cumsum(t))
If we add this to your code and run it, we get:
last=new_list[-1]
IndexError: list index out of range
Why is this? Apparently -1 is an out-of-range index. Why wouldn't new_list have a -1 index?
Aha. That happens if new_list is empty. So we need to address the base case first. While we're at it, let's also use #MartijnPieters' suggestion:
if len(numbers) <= 1:
return numbers
to obtain
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
new_list.append(rec[-1]+last)
return last+rec
Now run the test again. This time we get
return last+rec
TypeError: unsupported operand type(s) for +: 'int' and 'list'
So now Python is saying last is an int and rec is a list, and we can not add the two together.
Okay, rec should be a list since it is the return value of rec_cumsum(new_list). What should replace last+rec?
Let's think in terms of a concrete example. If rec is [a, a+b] then we want to return [a, a+b, a+b+c]. How do we form a+b+c?
How about adding the last element in rec with the last element of numbers:
rec[-1]+last
We want to append this to the end of rec:
rec.append(rec[-1]+last)
Let's make that change and see what happens. But while we're editing, let's also clean up some code we never use. We can delete new_list.append(rec[-1]+last):
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Now our program returns
[]
[1]
[1, 3]
[1, 3, 6]
[2, 3, 4, 7]
Hurray, our program runs without errors. But wait... it returns the wrong results. Look at the last line.
rec_cumsum([1,2,1,3]) is returning [2,3,4,7] whereas the correct answer is [1,3,4,7]. Why is the first number wrong?
It has to do with new_list.remove(last). This command removes the first occurrence of last from new_list. We want to remove the last occurrence.
So instead, let's use
new_list = numbers[:-1]
So the program becomes:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers[:-1]
last=numbers[-1]
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Run the tests. It works! Now it is a good practice to look back at our solution and see how it can be tightened up and made more elegant.
I see we used new_list and last as temporary variables. Do we really need them?
def rec_cumsum(numbers):
if len(numbers)<=1:
return numbers
result = rec_cumsum(numbers[:-1])
result.append(result[-1]+numbers[-1])
return result
Your function should always return a list; for the empty list case, an empty list, and for the case where there is only one element, a list with only one element.
But your code returns the one element, not a list with one element:
if len(numbers) == 1:
return numbers[0]
Change that to returning just numbers:
if len(numbers) == 1:
return numbers
You can combine this with the other end-state test:
if len(numbers) < 2:
return numbers
Next problem is that you are not creating a copy of a list when you create the variable new_list; you create a reference to the same list, you'd have to use a slice or create an explicit new list:
new_list = numbers[:]
If you are going to remove a value from that list anyway, you may as well adjust the slice a little, and put this after testing numbers (why do the work otherwise):
if len(numbers) < 2:
return numbers
new_list = numbers[:-1]
last = numbers[-1]
Nowhere in your code do you actually compute a sum; nothing is added to your numbers. You never add a to b, c, etc. Moreover, you seem to be focusing on the last number, while your assignment states you needed to sum the first value to the rest of the list.
And there is a pattern there. Not only do you add a to b, but the sum of a + b is added to c, and that sum is then added to d, etc. Let's make use of that:
def rec_cumsum(numbers, culmulated_sum=0):
if len(numbers) < 1:
return numbers
sum = numbers[0] + culmulated_sum
return [sum] + rec_cumsum(numbers[1:], sum)
Note that I don't even bother storing a copy of numbers now; may as well just pass it to the next recursion as a slice of everything but the first element. We also use the first element from numbers to create our sum (numbers[0]).
Also, we now pass along the culmulative sum so far, starting at 0; and that means we need to change the end condition of the recursive function; we are essentially adding [0] to the start of the list, and we want to make sure we sum that with the next element always.
This now does what you need:
>>> rec_cumsum([5, 1, 10, 2, 3])
[5, 6, 16, 18, 21]