This is two sum problem from leetcode, I tried to solve, It got accepted. I am asking if this code is efficient enough in terms of memory and space complexity.
My code :
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
l = len(nums)
ans = []
for i in range(l):
compliment = target - nums[i];
# print(a.index(x))
if compliment in nums:
if nums.index(compliment)!=i:
# print(a.index(x))
ans.append(i)
ans.append(nums.index(compliment))
break;
return ans
Your code searches for compliment in nums, and then follows it up with an index function. Later on, you use this index again in nums.index(compliment). Essentially, you're searching through the array three times. A better way would be to search through the array and store the index if found, else -1. If the index is not -1, i.e., present in the array, you can append it to ans. This essentially skips the two lines (and that index function) and traverses the array once instead of thrice.
index_if_found = -1
for index in range(len(arr)):
if arr[index] == search_value:
index_if_found = index
break
You can now use this index index_if_found instead of using the index function.
EDIT: Thanks to Kelly for correcting me on the search algorithm.
Additionally, you have two append methods to the same array. A slightly faster approach would be to use the extend method and add them in the same operation. So instead of
ans.append(i)
ans.append(nums.index(compliment))
You'd have
ans.extend((i, nums.index(compliment)))
Related
I'm working on https://leetcode.com/problems/permutations/ and I'm trying to decide which approach for generating the permutations is more clear. The question is "Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order." I've got two different solutions below.
Solution 1
def permute(self, nums: List[int]) -> List[List[int]]:
results = []
N = len(nums)
def dfs(subset, permutation: List[int]):
if len(subset) == N:
results.append(subset.copy())
return
for i, num in enumerate(permutation):
subset.append(num)
dfs(subset, permutation[:i] + permutation[i+1:])
# backtracking
subset.pop()
dfs([], nums)
return results
Solution 2
def permute(self, nums: List[int]) -> List[List[int]]:
results = []
N = len(nums)
def dfs(subset, permutation: List[int]):
if len(subset) == N:
results.append(subset.copy())
return
for i, num in enumerate(permutation):
dfs(subset + [num], permutation[:i] + permutation[i+1:])
dfs([], nums)
return results
I believe in the first solution, when you append to a list in python (i.e append to the subset parameter), lists are pass by reference so each recursive call will share the same list. This is why we have to explicitly backtrack by popping from subset. However in the second solution when a list is passed to a recursive call with the syntax subset + [num], a copy of the list is passed to each recursive call so that's why we don't explicitly have to backtrack.
Can someone confirm if my assumptions are correct? Is one approach favored over another? I think the time and space complexities are identical for both approaches (O(N!) and O(N), respectively) where N = the number of elements in nums.
Yes you are right that the first permute passes the same object (subset) in each recursive call.
And this is possible in first permute because lists are mutable, if you had a string to permute upon then you have to pass a copy because they are immutable.
And in the second permute a copy of subset is created. You can test it with the statement print(id(subset)) at the beginning of dfs in each permute. You can observe that the statement prints same id in the first permute but not in the second permute.
To me even though both have same time complexity (depends on what you do at the base condition - its O(N.N!) and not O(N!) because you are appending a copy of list to the result list ), why do you want to create a copy of subset and place an entirely new object on stack when you can have the copy of object reference (not the object itself!) on the stack which consumes less memory. So I prefer first permute.
The code I have written that aims to solve the Two Sum problem:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dict = {}
for i in range(len(nums)):
complement = target - nums[i]
if complement in dict:
return [dict[complement], i]
dict[complement] = i
I have just started practicing on LeetCode and I am experiencing issues with solving the Two Sum problem.
The problem statement:
Given an array of integers nums and an integer target, return indices
of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
You can return the answer in any order.
My reasoning is to create a dictionary and iterate through the numbers, and for each number generate a complement number that I then look for in my dictionary, if it in fact is there, then I return the index that generates that complement and the current index i. Otherwise, I insert the key with the complement.
Somehow my function does not output anything, just two empty brackets. Below there is a sample input and correct output.
Input: nums = [3,2,4], target = 6
Output: [1,2]
The last line is wrong. It should read dict[nums[i]] = i, because you are storing indeces for their values. Here is the entire function with a better variable name that doesn't shadow the built-in type:
def twoSum(self, nums, target):
dct = {}
for i in range(len(nums)):
complement = target - nums[i]
if complement in dct:
return [dct[complement], i]
dct[nums[i]] = i
Or more concise using enumerate and storing indeces for their complement values:
def twoSum(self, nums, target):
dct = {}
for i, num in enumerate(nums):
if num in dct:
return [dct[num], i]
dct[target - num] = i
You may notice that you had a mixture of the two approaches. You looked for the complement in dct, and also wanted to store it for the current index. One of the two needs to be the current value.
I'm doing the leetcode question #217 : Contains Duplicate.
After checking the answer, I cannot understand some parts of the code. The question is as given below:
Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct.
Example 1:
Input: nums = [1,2,3,1]
Output: true
Example 2:
Input: nums = [1,2,3,4]
Output: false
The answer is the following:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
nums.sort()
for i in range(0,len(nums)-1):
if nums[i] == nums[i+1]:
return True
return False
The following is my question:
In my understanding, looping through range(0,len(nums)-1) allows us to check and compare characters in num[0:-2], but what about the last two characters?
How can we compare those two characters if we have nums like [2,14,18,22,22].
And for the last two lines, why can't we directly use return False instead of using the if...else... structure?
How is the logic been written here?
Thanks for anyone who can clarify my puzzle!
You are comparing the last two elements. When i == len(nums)-2, you compare nums[i] with nums[i+1]. Those are the last two elements.
You don't need if/else. As soon as you find a duplicate, you immediately return from the function. So the only way to get to the end of the loop is if there are no duplicates.
Python Solution:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
return len(set(nums)) != len(nums)
set() method in python takes parameters like Any iterable sequence like list, tuple, or dictionary and returns an empty set if no element is passed. Non-repeating element iterable modified as passed as argument.
Here, we are checking if the length of the list after iterating equals the length before? If yes implies there is no number repeated.
range(start, end, step function work from start, start+1, start+2 ... end-1, where end is exclusive and start is inclusive.
ie for range(0,100,1) it wil go as 0,1,2,3,4,5......96,97,98,99.
if your code you are checking character ith and(i+1)th character. so in at last index ie (len(num)-2), you are checking len(num)-2 and len(num)-1 character which include the last elements.
now why return directly false. it is considering that all element are distinct if the program is reached till this statement. if any duplicate is found then it will be found in the for loop.
I am currently on LeetCode and am looking through the solutions for the Two Sum problem. Here are the instructions,
"Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order."
I ran across a couple solutions and I saw this answer:
def twoSum(self, nums: [int], target: int) -> tuple:
num2idx = {}
for idx, val in enumerate(nums):
if target - val in num2idx:
return num2idx[target - val], idx
num2idx[val] = idx
The part that I am unsure of is this,
if target - val in num2idx:
return num2idx[target - val], idx
num2idx[val] = idx
How exactly will this return both indices of the numbers that add up to the target? It looks to me like what is being return is solely the, "target-val" as well as the index of the current num being iterated over.
num2idx is holding the location of each number, not the number itself. The statement
return num2idx[target - val], idx
returns the index of the current number, as well as the index of the number that makes up the difference between the current number and the target.
While Trying to solve few question from LeetCode I am facing a really weird issue.
Question 26: Remove Duplicates from Sorted Array
https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/
Example:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of
nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the new length.
In order to code this question I used :
class Solution(object):
def removeDuplicates(self, nums):
nums = list(set(nums))
return len(nums)
what this code is doing is first converting the list into a set and
then back to list, which in turn will remove the Duplicates
But when I am trying to submit this code to the leetcode solution, modified length of nums is returned but when the program is trying to access the nums array it is not updated.
This is only Happening in Leetcode editor, in my system If I try to print the nums, the modified value is displayed, not sure what is wrong.
Now the same case is Happening to other question as well, for example:
Rotate Array
https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/646/
Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
My solution to this problem is as follows:
class Solution(object):
def rotate(self, nums, k):
newIndex = k % len(nums)
nums = nums[newIndex+1:len(nums)] + nums[0:newIndex+1]
print nums
But again I am amazed by the output I am getting back from the submission.
Note Here in the "Your STDOUT" we can see the list is modified accordingly.
link to the Screenshot
Please let me know if anyone else is facing this issue or anyone knows the solution to this.
Turns out the solution to this is to use: nums[:] = nums[newIndex+1:len(nums)] + nums[0:newIndex+1].
Doing nums = nums[newIndex+1:len(nums)] + nums[0:newIndex+1] simply changes the reference, while nums[:] changes the values of the list.
You can use
sudo service network-manager restart
what was happening in your code is the length you were returning is been used to travel the nums in back-end to print the unique values of the nums list. So, the requirement off the problem was the length you returned will be traveled from index 0 to the length returned. Hence with returning the length of unique values, we also have to modify the original list i.e., nums .
Solution for the 1st link
class Solution:
def removeDuplicates(self, nums):
if(len(nums) == 0):
return 0
elif len(nums) == 1 :
return 1
else:
l = 1
for i in range (1,len(nums)):
if nums[i] != nums[i-1] :
#l+=1
nums[l] = nums[i]
l+=1
return l