There is this question, 189 Rotate array on Leetcode. enter link description here Its statement is "Given an array, rotate the array to the right by k steps, where k is non-negative."
To understand it better, here's an example.
enter image description here
So, My code for this is
for _ in range(k):
j = nums[-1]
nums.remove(nums[-1])
nums.insert(0, j)
It cannot pass some of the test cases in it.
In the discussion panel, I found a code claiming it got submitted successfully that went like
for _ in range(k):
nums.insert(0, nums.pop(-1))
I would like to know, what is the difference between these two and why my code isn't able to pass some of the test cases.
If you do this on python shell [].remove.__doc__, you'll see the purpose of list.remove is to:
Remove first occurrence of value. Raises ValueError if the value is
not present.
In your code nums.remove(nums[-1]) does not remove the last item, but first occurrence of the value of your last item.
E.g.
If you have a list with values nums = [2, 4, 8, 3, 4] and if you do nums.remove(nums[-1]) the content of nums becomes [2, 8, 3, 4] not [2, 4, 8, 3] that you're expecting.
Just use slicing:
>>> def rotate(l, n):
... return l[-n:] + l[:-n]
...
>>> lst = [1, 2, 3, 4, 5, 6, 7]
>>> rotate(lst, 1)
[7, 1, 2, 3, 4, 5, 6]
>>> rotate(lst, 2)
[6, 7, 1, 2, 3, 4, 5]
>>> rotate(lst, 3)
[5, 6, 7, 1, 2, 3, 4]
In your code j = nums[-1] and you are trying to insert(0, nums[-1]).
In
for _ in range(k):
nums.insert(0, nums.pop(-1))
inserting other number - (0, nums.pop(-1))
Answer given by cesarv is good and simple, but on large arrays numpy will definitely perform better. Consider:
np.roll(lst, n)
The remove() method takes a single element as an argument and removes it's first occurence from the list.
The pop() method takes a single argument (index). The argument passed to the method is optional. If not passed, the default index -1 is passed as an argument (index of the last item).
If the test case has the same item before the last index then test case will fail.
Hence to correct your code replace remove with pop
for _ in range(k):
poppedElement = nums.pop()
nums.insert(0, poppedElement)
or to make it even concise -
for _ in range(k):
nums.insert(0, nums.pop())
I have a list, let us call it l = [1,2,3,7,8,9,10,7]. Given this list l, I am trying to remove the first occurrence of the number 7 without using the .pop() or .remove() built-in functions.
I have tried
def remove_item(l, item_to_remove):
newlst = []
for item in l:
if item != item_to_remove:
newlst.append(item)
return newlst
However, this removes all instances of the item I am trying to remove when in fact I only want to remove the very first instance of that said specific item. Does anyone have some tips on how to accomplish this??
You only need to take care that the removing part of your code doesn't run twice.
lst = [1,2,3,7,8,9,10,7] # [1, 2, 3, 7, 8, 9, 10, 7]
print(lst)
for i in range(len(lst)):
if lst[i] == 7:
del lst[i] # [1, 2, 3, 8, 9, 10, 7]
break
print(lst)
It does exactly the same as the following:
lst = [1,2,3,7,8,9,10,7]
print(lst) # [1, 2, 3, 7, 8, 9, 10, 7]
for i in range(len(lst)):
if lst[i] == 7:
lst.pop(i)
break
print(lst) # [1, 2, 3, 8, 9, 10, 7]
as well as this
lst = [1,2,3,7,8,9,10,7]
print(lst) # [1, 2, 3, 7, 8, 9, 10, 7]
for i in range(len(lst)):
if lst[i] == 7:
lst.remove(lst[i])
break
print(lst) # [1, 2, 3, 8, 9, 10, 7]
Overview of the used methods:
del list[i] - The del statement can also be used to remove slices from a list
list.pop - remove and return item at index (default last). Raises IndexError if list is empty or index is out of range.
list.remove - remove first occurrence of value.Raises ValueError if the value is not present.
You just need to add a little logic to it. I add a looking variable which signifies that we havent found the entry were looking for. Heres the code
def remove_item(l, item_to_remove):
newlst = []
looking = True
for item in l:
if item != item_to_remove or not looking:
newlst.append(item)
else:
looking = False
return newlst
list = [1,3,4,5,6,7,3,10]
print(remove_item(list, 3))
which returns [1, 4, 5, 6, 7, 3, 10]
Very wasteful, but here you go, a solution:
def remove_first(sequence, element):
return sequence[:sequence.index(element)] + sequence[sequence.index(element)+1:]
Then you can:
>>> remove_first(["a", "b", "a", "c"], "a"):
['b', 'a', 'c']
index returns the index of the first found occurrence of an element.
The rest is sequence splicing and catenation.
Of course, you could generalize this to remove(sequence, element, n) to remove the n-th found element.
EDIT: I just stated falsely that index also supports that. Statement removed.
Or you could choose to mutate the input, but for one, returning the output is cleaner, and you could not have a general "sequence" argument, as not all sequences are mutable. See the tuple type.
.index(x) returns the first index location of x within the list, so just delete it. If x is not found, it returns ValueError.
my_list = [1, 2, 3, 7, 8, 9, 10, 7]
val = 7
if val in my_list:
del my_list[my_list.index(val)]
>>> my_list
[1, 2, 3, 8, 9, 10, 7]
Signature: my_list.index(value, start=0, stop=9223372036854775807, /)
Docstring:
Return first index of value.
Raises ValueError if the value is not present.
Welcome to StackOverflow!
Minor modification to your code,.
I would prefer remove but here is your modified code to do the required job
def remove_item(l, item_to_remove):
newlst = []
for item in l:
if item != item_to_remove:
newlst.append(item)
else:
return newlst + l[len(newlst) + 1 :]
return newlst
In Python, you can add the lists. Using list comprehensions, you select sub-lists(l[len(newlst) + 1 :]).
Testing
>>> list = [1,3,4,5,6,7,3,10]
>>> print(remove_item(list, 3))
[1, 4, 5, 6, 7, 3, 10]
lst = [1,2,3,7,8,9,10,7]
new_lst = lst[:lst.index(7)] + lst[lst.index(7) + 1:]
new_lst
[1, 2, 3, 8, 9, 10, 7]
Similar idea to CEWeinhauer's solution, but one which takes advantage of Python features to minimize overhead once we've found the item to remove:
def remove_item(l, item_to_remove):
newlst = []
liter = iter(l) # Make single pass iterator, producing each item once
for item in liter:
if item == item_to_remove: # Found single item to remove, we're done
break
newlst.append(item) # Not found yet
newlst += liter # Quickly consume all elements after removed item without tests
return newlst
The above works with any input iterable in a single pass, so it's better if the input might not be a list and/or might be huge. But it's admittedly more complex code. The much simpler solution is to just find the element with index and remove it. It might be slightly slower in some cases, since it's two O(n) steps instead of just one, but it uses C built-ins more, so it's likely to be faster in practice:
def remove_item(l, item_to_remove):
newlst = list(l)
del newlst[newlst.index(item_to_remove)]
return newlst
Whenever I code on online platforms and somehow I have to compare the elements of a list to one another, I use the following code which according to me is the most efficient possible. This is the last code which I was practicing. It was to find the maximum index between 2 same elements.
max=0
for i in range(len(mylist)):
if max==(len(mylist)-1):
break
for j in range(i + 1, len(mylist)):
if mylist[i] == mylist[j]:
if max>(abs(i-j)):
max=abs(i-j)
It runs most of the test cases, but sometimes it shows "time limit exceeded." I know it is related to the constraints and time complexity but I still can't find a better way. If anyone could help me, that would be great.
It's easier to use C based functions in Python. Also don't name variables python types like list.
x = [item for i, item in enumerate(l) if item in l[i+1:]]
# do something with list of values
You could group by equal elements and then find the difference in-group, and keep the maximum:
lst = [1, 3, 5, 3, 7, 8, 9, 1]
groups = {}
for i, v in enumerate(lst):
groups.setdefault(v, []).append(i)
result = max(max(group) - min(group) for group in groups.values())
print(result)
Output
7
The complexity of this approach is O(n).
def get_longest_distance_between_same_elements_in_list(mylist):
positions = dict()
longest_distance = 0
if len(mylist) < 1:
return longest_distance
for index in range(0, len(mylist)):
if mylist[index] in positions:
positions[mylist[index]].append(index)
else:
positions[mylist[index]] = [index]
for key, value in positions.items():
if len(value) > 1 and longest_distance < value[len(value)-1] - value[0]:
longest_distance = value[len(value)-1] - value[0]
return longest_distance
l1 = [1, 3, 5, 3, 7, 8, 9, 1]
l2 = [9]
l3 = []
l4 = [4, 4, 4, 4, 4]
l5 = [10, 10, 3, 4, 5, 4, 10, 56, 4]
print(get_longest_distance_between_same_elements_in_list(l1))
print(get_longest_distance_between_same_elements_in_list(l2))
print(get_longest_distance_between_same_elements_in_list(l3))
print(get_longest_distance_between_same_elements_in_list(l4))
print(get_longest_distance_between_same_elements_in_list(l5))
Output -
7
0
0
4
6
Time Complexity : O(n)
This is a practice problem that I've been trying to solve for a while:
Write a recursive Python function that rearranges a sequence of integer values so that all the even values appear before all the odd values.
What I have:
def arrange(x):
even = ''
odd = ''
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even += y[0]
if y[1:] != '':
arrange(int(y[1:]))
else:
odd += y[0]
if y[1:] != '':
arrange(int(y[1:]))
final = int(even + odd)
After running the visualizer, I think the problem in the code lies within the fact that even and odd are reset everytime. Though, I need it all to be in one function. Any advice?
EDIT: Completed in case anyone wanted to use the same practice problem -
even = []
odd = []
def arrange(x):
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even.append(y[0])
if y[1:] != '':
arrange(int(y[1:]))
else:
odd.append(y[0])
if y[1:] != '':
arrange(int(y[1:]))
def complete(x):
evens = ''
odds = ''
arrange(x)
for i in even:
evens += i
for i in odd:
odds += i
return int(evens + odds)
Disclaimer
I do not know any python. I am answering this question as much as a learning exercise for me as the problem is an exercise for you.
I have not checked this answer for syntax errors.
I think your hunch that the problem is due to even and odd being reset on each call is correct - you need to pass them in to rearrange. Here is my attempt:
def arrange(x, evenInput, oddInput):
even = str(evenInput)
odd = str(oddInput)
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even += y[0]
if y[1:] != '':
arrange(int(y[1:]), even, odd)
else:
odd += y[0]
if y[1:] != '':
arrange(int(y[1:]), even, odd)
final = int(even + odd)
I have a different solution, it isn't very efficient if you're working with larger lists*, but I guess for an assignment it's fine:
def evenBeforeOdd(x):
if not x:
return []
if x[0] % 2 == 0: #even
return [x[0]] + evenBeforeOdd(x[1:])
else:
return evenBeforeOdd(x[1:]) + [x[0]]
*: If I remember correctly, adding lists together is pricy (O(n), plus the slicing, which is O(1) in our case, I think), which it needs to do for each item of the list, so the whole thing should be O(n^2). Also it's not very memory efficient, since it must create new lists all the time.
If I actually wanted to solve the problem without the recursivity requirement, it'd simply be something like this:
sorted(myList, key=lambda x: x%2!=0)
Here's a simple solution. For a given index ind recursively apply func for the list, ind ownwards, followed by checking whether the value at ind is even or odd. If odd, just move that value to the end of the list.
When the recursion starts to unwrap, it will begin rearrangement from the end of list and as the stack unwinds, the pervious elements of the list would start to fall in the right places.
def func(lst, ind=0):
if ind < len(lst):
func(lst, ind+1)
if lst[ind] % 2 != 0:
lst.append(lst.pop(ind))
return lst
print func([3,4,6,2,1])
I wasn't sure what your desired output was, or if you wanted it to recurse and keep the structure/order. Here's a swiss army knife.
from pprint import pprint
def even_before_odd(values, keep_structure=False, sort=False):
evens, odds = even_odd(values, keep_structure, sort)
return evens + odds
def even_odd(values, keep_structure=False, sort=False):
evens = []
odds = []
for value in values:
if isinstance(value, list):
_evens, _odds = even_odd(value, keep_structure, sort)
if keep_structure:
# This will insert a sub array
evens.append(_evens)
odds.append(_odds)
else:
# This will append them to the list
evens += _evens
odds += _odds
continue
if value % 2 == 0:
evens.append(value)
else:
odds.append(value)
if sort:
evens = sorted(evens)
odds = sorted(odds)
return evens, odds
values = []
for x in range(0,10):
values.append(list(range(0,10)))
result = even_before_odd(values, False, True)
print "result 1:", ",".join(map(str, result))
result = even_before_odd(values, False, False)
print "result 2:", ",".join(map(str, result))
print "result 3:"
result = even_before_odd(values, True, True)
pprint(result)
Output:
result 1: 0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,6,6,6,6,8,8,8,8,8,8,8,8,8,8,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,7,7,9,9,9,9,9,9,9,9,9,9
result 2: 0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9
result 3
[[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9]]
Here is an efficient, short way to do this (not recursive however).
A string in Python is an iterable, so there actually is no need to keep taking substrings of the original input. Instead, you could filter out the odd and even digits and later concatenate them.
def splitEvenOdd(x):
even = [e for e in x if int(e)%2 == 0]
odd = [o for o in x if int(o)%2 == 0]
even = "".join(even)
odd = "".join(odd)
return even + odd