I have a solution for this problem on codewars.com that works when I run it in Sublime, but when I try to submit, I get this error:
Process was terminated. It took longer than 12000ms to complete
Why did my code time out?
Our servers are configured to only allow a certain amount of time for your code to execute. In rare cases the server may be taking on too much work and simply wasn't able to run your code efficiently enough. Most of the time though this issue is caused by inefficient algorithms. If you see this error multiple times you should try to optimize your code further.
The goal of the function is to find the next biggest number after a given number that you can make by rearranging the digits of a given number. For example, if I was given 216, I would need to return 261.
This is the code I have now:
import itertools
def next_bigger(n):
# takes a number like 472 and puts it in a list like so: [4, 7, 2]
num_arr = [int(x) for x in str(n)]
perms = []
total = ''
# x would be a permutation of num_arr, like [7, 2, 4]
for x in itertools.permutations(num_arr):
for y in x:
total += str(y)
perms.append(int(total))
total = ''
# bigger is all permutations that are bigger than n,
# so bigger[0] is the next biggest number.
# if there are no bigger permutations, the function returns -1
bigger = sorted([x for x in perms if x > n])
return bigger[0] if bigger else -1
I'm new to coding in Python, so is there some mistake I am making which causes my code to be extremely inefficient? Any suggestions are welcome.
Thanks for all the help you guys gave me. I ended up finding a solution from here using the Next Lexicographical Permutation Algorithm
This is my tidied up version of the solution provided here:
def next_bigger(n):
# https://www.nayuki.io/res/next-lexicographical-permutation-algorithm/nextperm.py
# https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
# Find non-increasing suffix
arr = [int(x) for x in str(n)]
i = len(arr) - 1
while i > 0 and arr[i - 1] >= arr[i]:
i -= 1
if i <= 0:
return -1
# Find successor to pivot
j = len(arr) - 1
while arr[j] <= arr[i - 1]:
j -= 1
arr[i - 1], arr[j] = arr[j], arr[i - 1]
# Reverse suffix
arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
return int(''.join(str(x) for x in arr))
Why are you getting TLE (time limit exceeded)?
Because your algorithm has wrong complexity. How much permutations you will find for list with 3 elements? Only 6. But what if we use list with 23 elements? 25852016738884976640000.
This is too much for time limit.
So, if you want to have solve this problem you have to find solution without permutations. Please rethink how the numbers are written. The number 271 is bigger then 216 because the number on the second position has bigger value 7>1.
So, your solution has to find two numbers and swap them position. The number on the left have to smaller then the second one.
For example - for 111115444474444 you should find 5 and 7.
Then you swap them - and now you should sort sublist on right from the first position.
For example after swapped the values (111117444454444) you have to sort (444454444) -> (444444445). Now merge all, and you have solution.
import functools
def next_bigger(a):
a = map(int, str(a))
tmp = list(reversed(a))
for i, item_a in enumerate(reversed(a)):
for j in (range(i)):
if item_a < tmp[j]:
#you find index of number to swap
tmp[i]=tmp[j]
print(list(reversed(tmp[i:])))
tmp[j]=item_a
fin = list(reversed(tmp[i:])) + sorted(tmp[:i])
return functools.reduce(lambda x,y: x*10+y, fin)
return -1
A simple backtracking approach is to consider the digits one at a time. Starting from the most significant digit, pick the smallest number you have left that doesn't prevent the new number from exceeding the input. This will always start by reproducing the input, then will have to backtrack to the next-to-last digit (because there aren't any other choices for the last digit). For inputs like 897654321, the backtracking will immediately cascade to the beginning because there are no larger digits left to try in any of the intermediate slots.
You should sorting the num_arr in desc order and creating a number by combining the result.
Since OP required, next largest, OP needs to check starting from right, which right digit is larger then its very left digit and rotate their position.
Here is the final code:
def next_bigger(n):
num_arr = [int(x) for x in str(n)]
i = 0
i = len(num_arr) - 1
while(i > 0):
if num_arr[i] > num_arr[i-1]:
a = num_arr[i]
num_arr[i] = num_arr[i-1]
num_arr[i-1] = a
break
else:
i = i-1
newbig = "".join(str(e) for e in num_arr)
return int(newbig)
Now I edit to calculate next bigger element.
def perms(s):
if(len(s)==1):
return [s]
result=[]
for i,v in enumerate(s):
result += [v+p for p in perms(s[:i]+s[i+1:])]
return result
a=input()
b=perms(str(a))
if len(b)!=1:
for i in range(0,len(b)):
if b[i]==a:
print (b[i+1])
break
else:
print ("-1")
Related
As the title suggests, I'm trying to define a function that takes an array of numbers and returns the index at which the numbers stop increasing and begin decreasing or stop decreasing and begin increasing. For example, if the array were [1, 2, 4, 6, 4, 3, 1], the function should return 3. The following code only returns the left bracket, and I'm wondering why that is the case.
def ArrayChallenge(arr):
for i in range(len(arr)):
if arr[i] > arr[i+1]:
return i
Any help would be appreciated.
I think it was my version of visual studio code that was causing the problem. The left bracket only printed out when I was running it locally on VS code. It was fine in a repl and when using colab.
Anyways, I wanted to post the solution I came up with... It took me a little longer than I would like to admit, but I suppose this is to be expected being new to programming. Here is my code for the problem. I welcome any and all critiques.
for i in range(len(arr)):
if (arr[0] == min(arr) and arr[-1] == max(arr)) or (arr[0] == max(arr) and arr[-1] == min(arr)):
return -1
if arr[i+1] > arr[i]:
return arr.index(max(arr))
else:
return arr.index(min(arr))
Assuming your array will always increase and then decrease with no duplicated highest value, you’re essentially looking for the highest value in the list. An easier option is to simply find the max value and return its index. If that is not the case, this may lead you to your solution:
def ArrayChallenge(arr):
return arr.index(max(arr))
Edit: Given poster’s comments, the following should work (but is not the nicest looking). An assumption here is that the first cannot be used since it did not have a lower preceding value and the last cannot because it does not have a lower following value:
def ArrayChallenge(arr):
peaks = []
for i in range(1, len(arr) - 1):
if arr[i - 1] < arr[i] > arr[i + 1]:
peaks.append(i)
return peaks if len(peaks) > 0 else -1
I have been working on a problem on https://www.lintcode.com/ and I have ran into a problem while doing one of the questions. The problem requires me to write a function with two parameters. A list of nums and a target num. You have to take all instances of the target from the list and move them to the front of the original list and the function cannot have a return value. The length of the list is between 1 and 1000000. You also have to do it within a time limit, which is around 400 milliseconds. I can solve the problem, I can't pass the last test case where the length of the list is 1000000. Does anyone know how I can make my code faster?
Original Problem Description for anyone who still isn't clear:
Current Code:
def MoveTarget(nums, target):
if len(set(nums)) == 1:
return nums
index = [i for i in range(len(nums)) if nums[i] == target]
for i in index:
nums.insert(0, nums.pop(i))
It works if you do:
def MoveTarget(nums, target):
count = 0
left, right = len(nums) - 1, len(nums) - 1
while left >= 0:
if nums[left] != target:
nums[right] = nums[left]
right -= 1
else:
count += 1
left -= 1
for i in range(count):
nums[i] = target
but I was wondering if there was another, less complicated way.
Here is a simple and relatively efficient implementation:
def MoveTarget(nums, target):
n = nums.count(target)
nums[:] = [target] * n + [e for e in nums if e != target]
It creates a new list with the n target values in the front and append all the other values that are not target. The input list nums is mutated thanks to the expression nums[:] = ....
The solution run in linear time as opposed to the previously proposed implementations (running in quadratic time). Indeed, insert runs in linear time in CPython.
Your code uses 2 loops. One in:
index = [i for i in range(len(nums)) if nums[i] == target]
And one in:
for i in index:
nums.insert(0, nums.pop(i))
Instead, you can combine finding the target and moving it to the front of array with only one loop, which will greatly reduce the execution time:
def MoveTarget(nums, target):
if len(set(nums)) == 1:
return nums
for num in nums:
if num == target:
nums.insert(0, nums.pop(num))
I would like to write a function which performs efficiently this "strange" sort (I am sorry for this pseudocode, it seems to me to be the clearest way to introduce the problem):
l=[[A,B,C,...]]
while some list in l is not sorted (increasingly) do
find a non-sorted list (say A) in l
find the first two non-sorted elements of A (i.e. A=[...,b,a,...] with b>a)
l=[[...,a,b,...],[...,b+a,...],B,C,...]
Two important things should be mentioned:
The sorting is dependent on the choice of the first two
non-sorted elements: if A=[...,b,a,r,...], r<a<b and we choose to
sort wrt to (a,r) then the final result won't be the same. This is
why we fix the two first non-sorted elements of A.
Sorting this way always comes to an end.
An example:
In: Sort([[4,5,3,10]])
Out: [[3,4,5,10],[5,7,10],[10,12],[22],[4,8,10]]
since
(a,b)=(5,3): [4,5,3,10]->[[4,3,5,10],[4,8,10]]
(a,b)=(4,3): [[4,3,5,10],[4,8,10]]->[[3,4,5,10],[7,5,10],[4,8,10]]
(a,b)=(7,5): [[3,4,5,10],[7,5,10],[4,8,10]]->[[3,4,5,10],[5,7,10],[12,10],[4,8,10]]
(a,b)=(12,10): [[3,4,5,10],[5,7,10],[12,10],[4,8,10]]->[[3,4,5,10],[5,7,10],[10,12],[22],[4,8,10]]
Thank you for your help!
EDIT
Why am I considering this problem:
I am trying to do some computations with the Universal Enveloping Algebra of a Lie algebra. This is a mathematical object generated by products of some generators x_1,...x_n. We have a nice description of a generating set (it amounts to the ordered lists in the question), but when exchanging two generators, we need to take into account the commutator of these two elements (this is the sum of the elements in the question). I haven't given a solution to this question because it would be close to the worst one you can think of. I would like to know how you would implement this in a good way, so that it is pythonic and fast. I am not asking for a complete solution, only some clues. I am willing to solve it by myself .
Here's a simple implementation that could use some improvement:
def strange_sort(lists_to_sort):
# reverse so pop and append can be used
lists_to_sort = lists_to_sort[::-1]
sorted_list_of_lists = []
while lists_to_sort:
l = lists_to_sort.pop()
i = 0
# l[:i] is sorted
while i < len(l) - 1:
if l[i] > l[i + 1]:
# add list with element sum to stack
lists_to_sort.append(l[:i] + [l[i] + l[i + 1]] + l[i + 2:])
# reverse elements
l[i], l[i + 1] = l[i + 1], l[i]
# go back if necessary
if i > 0 and l[i - 1] > l [i]:
i -= 1
continue
# move on to next index
i += 1
# done sorting list
sorted_list_of_lists.append(l)
return sorted_list_of_lists
print(strange_sort([[4,5,3,10]]))
This keeps track of which lists are left to sort by using a stack. The time complexity is pretty good, but I don't think it's ideal
Firstly you would have to implement a while loop which would check if all of the numbers inside of the lists are sorted. I will be using all which checks if all the objects inside a sequence are True.
def a_sorting_function_of_some_sort(list_to_sort):
while not all([all([number <= numbers_list[numbers_list.index(number) + 1] for number in numbers_list
if not number == numbers_list[-1]])
for numbers_list in list_to_sort]):
for numbers_list in list_to_sort:
# There's nothing to do if the list contains just one number
if len(numbers_list) > 1:
for number in numbers_list:
number_index = numbers_list.index(number)
try:
next_number_index = number_index + 1
next_number = numbers_list[next_number_index]
# If IndexError is raised here, it means we don't have any other numbers to check against,
# so we break this numbers iteration to go to the next list iteration
except IndexError:
break
if not number < next_number:
numbers_list_index = list_to_sort.index(numbers_list)
list_to_sort.insert(numbers_list_index + 1, [*numbers_list[:number_index], number + next_number,
*numbers_list[next_number_index + 1:]])
numbers_list[number_index] = next_number
numbers_list[next_number_index] = number
# We also need to break after parsing unsorted numbers
break
return list_to_sort
Given a set of integers 1,2, and 3, find the number of ways that these can add up to n. (The order matters, i.e. say n is 5. 1+2+1+1 and 2+1+1+1 are two distinct solutions)
My solution involves splitting n into a list of 1s so if n = 5, A = [1,1,1,1,1]. And I will generate more sublists recursively from each list by adding adjacent numbers. So A will generate 4 more lists: [2,1,1,1], [1,2,1,1], [1,1,2,1],[1,1,1,2], and each of these lists will generate further sublists until it reaches a terminating case like [3,2] or [2,3]
Here is my proposed solution (in Python)
ways = []
def check_terminating(A,n):
# check for terminating case
for i in range(len(A)-1):
if A[i] + A[i+1] <= 3:
return False # means still can compute
return True
def count_ways(n,A=[]):
if A in ways:
# check if alr computed if yes then don't compute
return True
if A not in ways: # check for duplicates
ways.append(A) # global ways
if check_terminating(A,n):
return True # end of the tree
for i in range(len(A)-1):
# for each index i,
# combine with the next element and form a new list
total = A[i] + A[i+1]
print(total)
if total <= 3:
# form new list and compute
newA = A[:i] + [total] + A[i+2:]
count_ways(A,newA)
# recursive call
# main
n = 5
A = [1 for _ in range(n)]
count_ways(5,A)
print("No. of ways for n = {} is {}".format(n,len(ways)))
May I know if I'm on the right track, and if so, is there any way to make this code more efficient?
Please note that this is not a coin change problem. In coin change, order of occurrence is not important. In my problem, 1+2+1+1 is different from 1+1+1+2 but in coin change, both are same. Please don't post coin change solutions for this answer.
Edit: My code is working but I would like to know if there are better solutions. Thank you for all your help :)
The recurrence relation is F(n+3)=F(n+2)+F(n+1)+F(n) with F(0)=1, F(-1)=F(-2)=0. These are the tribonacci numbers (a variant of the Fibonacci numbers):
It's possible to write an easy O(n) solution:
def count_ways(n):
a, b, c = 1, 0, 0
for _ in xrange(n):
a, b, c = a+b+c, a, b
return a
It's harder, but possible to compute the result in relatively few arithmetic operations:
def count_ways(n):
A = 3**(n+3)
P = A**3-A**2-A-1
return pow(A, n+3, P) % A
for i in xrange(20):
print i, count_ways(i)
The idea that you describe sounds right. It is easy to write a recursive function that produces the correct answer..slowly.
You can then make it faster by memoizing the answer. Just keep a dictionary of answers that you've already calculated. In your recursive function look at whether you have a precalculated answer. If so, return it. If not, calculate it, save that answer in the dictionary, then return the answer.
That version should run quickly.
An O(n) method is possible:
def countways(n):
A=[1,1,2]
while len(A)<=n:
A.append(A[-1]+A[-2]+A[-3])
return A[n]
The idea is that we can work out how many ways of making a sequence with n by considering each choice (1,2,3) for the last partition size.
e.g. to count choices for (1,1,1,1) consider:
choices for (1,1,1) followed by a 1
choices for (1,1) followed by a 2
choices for (1) followed by a 3
If you need the results (instead of just the count) you can adapt this approach as follows:
cache = {}
def countwaysb(n):
if n < 0:
return []
if n == 0:
return [[]]
if n in cache:
return cache[n]
A = []
for last in range(1,4):
for B in countwaysb(n-last):
A.append(B+[last])
cache[n] = A
return A
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
My solution:
def findDuplicate(nums):
slow = fast = finder = 0
while fast is not None:
slow = nums[slow]
fast = nums[nums[fast]]
if fast is slow:
return slow
return False
nums = [1,2,2,3,4]
print findDuplicate(nums)
My above solution works and gives me o/p 2 but it doesn't work for every input for example it doesn't work for [11,15,17,17,14] or [3,1,2,6,2,3] and gives me error IndexError: list index out of range. I am not able to find patterns and am not able to track down the exact problem. Also tried to change my while condition:
while fast is not None and nums[nums[fast]] is not None:
your help will be greatly appreciated! Thank you.
Since the numbers are between 1 and n and you have been told there is only one duplicate, you can use difference between the sum of the numbers in the array and the sum of numbers from 1 to n to get the duplicate.
def findDuplicate(l):
n = len(l) - 1 # Get n as length of list - 1
return sum(l) - (n * (n + 1) / 2) # n*(n+1)/2 is the sum of integers from 1 to n
So the duplicate is the sum of the list - n*(n+1)/2
Of course, this doesn't generalize to finding duplicates for any list. For that case, you need to use #Jalepeno112 's answer.
The fact that the first one works is a fluke. Let's look at what it does on the first pass.
nums = [1,2,2,3,4]
# slow starts as index 0. So now, you've reassigned slow to be nums[0] which is 1.
# so slow equals 1
slow = nums[slow]
# now you are saying that fast equals nums[nums[0]].
# nums[0] is 1. nums[1] is 2
# so fast = 2
fast = nums[nums[fast]]
On the next pass, slow will be nums[1] which is 2. fast will be nums[nums[2]] which is nums[2] which is 2. At this point slow and fast are equal.
In your second example, you are getting an IndexError because of fast = nums[nums[fast]] If the value at nums[fast] is not a valid index, then this code will fail. Specifically in the second example, nums[0] is 11. nums doesn't have an element at index 11, so you get an error.
What you really want to be doing is performing a nested for loop on the array:
# range(0,len(nums)-1) will give a list of numbers from [0, to the length of nums-1)
# range(1, len(nums)) does the same,
# except it will start at 1 more than i is currently at (the next element in the array).
# So it's range is recomputed on each outer loop to be [i+1, length of nums)
for i in range(0,len(nums)-1):
for j in range(i+1,len(nums)):
# if we find a matching element, return it
if nums[i] == nums[j]:
return nums[i]
# if we don't find anything return False
return False
There are likely other more Pythonic ways to achieve this, but that wasn't your original question.
first you must ensure all numbers in list satisfy your constrains.
to find duplicated numbers in a list Use Counter in collections it will return each number and number of occurrence example :
>>> from collections import Counter
>>> l=Counter([11,15,17,17,14])
>>> l
Counter({17: 2, 11: 1, 14: 1, 15: 1})
to get the most common one use :
>>> l.most_common(n=1)
[(17, 2)]
where n is the number most common numbers you want to get
def duplicates(num_list):
if type(num_list) is not list:
print('No list provided')
return
if len(num_list) is 0 or len(num_list) is 1:
print('No duplicates')
return
for index,numA in enumerate(num_list):
num_len = len(num_list)
for indexB in range(index+1, num_len):
if numA == num_list[indexB]:
print('Duplicate Number:'+str(numA))
return
duplicates([11,15,17,17,14])
duplicates([3,1,2,6,2,3])
duplicates([])
duplicates([5])
l=[]
n= int(input("the number of digit is :"))
l=[0 for k in range(n)]
for j in range(0,n):
l[j]=int(input("the component is"))
print(l)
b=0; c=0
for i in range(n):
if l[i]== l[n-1-i]:
b=1;c=i
if b==1:
print("duplicate found! it is",l[c])
elif b==0:
print("no duplicate")
The answer is unfinished. It tries to convert the array to a linked list. So far it found where the slow pointer and fast pointer met, but this is the halfway solution. To get the solution, we need to initialize another pointer from the beginning of the linked list and walk towards each other. When they meet, that point is the where cycle is detected, in our question it is where the single point is:
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow,fast=0,0
while True:
slow=nums[slow]
fast=nums[nums[fast]]
if slow==fast:
break
slow2=0
while True:
slow2=nums[slow2]
slow=nums[slow]
if slow==slow2:
return slow2