Sorting in ascending order with selection sort - python

I'm in need of big help, I cant seem to figure out how to do this code. So I am sorting an unsorted list of numbers in ascending order using selection sort and then returning the number of swaps it takes to sort the list.
Below is my code:
def swaps(numbers):
count = 0
for i in range(len(numbers)):
minIndex = i
for j in range(i + 1, len(numbers)):
if numbers[j] < numbers[minIndex]:
minIndex = j
if i != minIndex:
numbers[i], numbers[minIndex] = numbers[minIndex], numbers[i]
count += 1
return count
For these two test cases:
numbers = [0, 4, 2, 7, 5]
print(swaps(numbers))
numbers = [9, 8, 7, 6, 5, 4]
print(swaps(numbers))
it works perfect but for this test case it doesn't work:
import random
random.seed(30)
numbers = [random.randint(1, 50) for index in range(10)]
print(numbers)
print(swaps(numbers))
The numbers list for this test case is [35, 19, 40, 2, 40, 42, 14, 17, 4, 26]. Now working it out it swaps it 7 times but in my test program it is suppose to have swapped 8 times. Is this because of the repeat of 40 ?
How do I configure my code so that it takes into account a repeat of the same number?

If you are supposed to count an extra swap when you have a single pair of duplicate values, an easy way to match that expectation is to change the numbers[j] < numbers[minIndex] check to use <= instead of <.
That's making the code worse though, so I'd be sure to double check if that expectation is actually real or not. Managing to sort with fewer swaps should be a feature, not a bug!

Related

Creating a python loop/ list comprehension that contains all the multiples of 1 to 100 that are under 100

I want to create a python list comprehension statement that contains all the multiples of 2 to 100 that are under 100 and puts them inside a list. I understand this statement is probably very confusing so here how it would work in my mind:
Start from 2, add all the multiples of 2 to a list. IE. 2, 4, 6, 8... 100..
Move onto the next number, 3, add all the multiple of 3 to the same list(keeping it under 100) IE. 3, 6, 9, …99
Repeat this for all number from 2 to 99, placing all the values inside one singular list
In the end, my list should pretty much contain every number from 1 to 100 that is not prime.
I want to achieve this using list comprehension if possible. I've attached my work in the bottom which is not working. Right now, my loop just prints the multiple of 2 100 times and I am having trouble figuring out how to change the number being multiplied and storing it in one entire list.
Note: The point of my list is to filter out the prime numbers later, in the fashion of the Sieve of Eratosthenes but I don't need help with that part. See my code below:
print([i for i in range(100) if [x+x for x in range(100) if i + i <= 100]])
In my early days with Python I often found it helpful to write the operation as a regular loop first, and then converting it to a list comprehension
I'm going to use a set comprehension in my answer because sets get rid of the duplicates, so you don't have to worry about checking if a number is already in the list.
For example:
multiples = set()
for i in range(2, 101): # Loop over numbers
for j in range(2, 100//i + 1): # Loop over multiplications
multiples.add(i * j)
The inner loop goes from 2 (because you don't want to add every number to the set) to 100//ii + 1 (because 100//i is the highest multiple of i that is <= 100, and + 1 because range() excludes the end).
Writing this as a listset comprehension now is easy:
multiples = {i * j for i in range(2, 101) for j in range(2, 100//i + 1)}
To quickly pick out the numbers that aren't in this set, you can create a set containing all numbers from 2 (because 1 isn't prime) to 100 and get the set difference.
primes = set(range(2, 101)) - multiples
which gives:
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
This is not an answer, just an observation about how list comprehension could be slower than a multiline program.
This program is an implementation of the Sieve of Eratosthenes. One line added to #Pranav's solution could eliminate running through the table with unnecessary divisors. e.g.
multiples = set()
for i in range(2, 101): # Loop over numbers
if not i in multiples:
for j in range(2, 100//i + 1): # Loop over multiplications
multiples.add(i * j)
I don't believe that could be done with any kind of list comprehension.

Could you help me with this Dynamic Programming Problem?

I tried to solve the problem below using dynamic programming, but there is something wrong with my code and I could not figure it out. Could you help me with it? Thank you!
Problem:
Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum number of length k <= m + n from digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the k digits.
Note: You should try to optimize your time and space complexity.
Example 1:
Input:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
Output:
[9, 8, 6, 5, 3]
Example 2:
Input:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
Output:
[6, 7, 6, 0, 4]
Example 3:
Input:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
Output:
[9, 8, 9]
My idea is as following:
dp[i][j][t] is the the maximum number of length i which is picked out of first j digits of array 1 and first t digits of array 2, where i goes from 0 to k, j goes from 0 to len(nums1), t goes from 0 to len(nums2). the state transition equation goes like this:
when nums1[j-1] > nums2[t-1]:
if we already have k-2 digits, then we have to take both nums1[j-1] and nums2[t-1], and we must take nums1[j-1] first in order to maximize the result
if we already have k-1 digits, then we only have to take one more digit, and it must be nums1[j-1], because it is bigger
if we already have k digits, then we do not need to take more digits, so we keep the last result dp[i][j-1][t-1]
Given that we are looking for maximum, our current result should be the biggest among these 3 situations, so we have:
dp[i][j][t] = max(
(dp[i-2][j-1][t-1]*10+nums1[j-1])*10+nums2[t-1],
dp[i-1][j-1][t-1]*10+nums1[j-1],
dp[i][j-1][t-1]
)
when nums1[j-1] < nums2[t-1]:
if we already have k-2 digits, then we have to take both nums1[j-1] and nums2[t-1], and this time we must take nums2[t-1] first because it is bigger
if we already have k-1 digits, then we only have to take one more digit, and it must be nums2[t-1], because it is bigger
if we already have k digits, then we do not need to take more digits, so we keep the last result dp[i][j-1][t-1]
Likewise, we take the biggest result from these possible ones:
dp[i][j][t] = max(
(dp[i-2][j-1][t-1]*10+nums2[t-1])*10+nums1[j-1],
dp[i-1][j-1][t-1]*10+nums2[t-1],
dp[i][j-1][t-1]
)
Here is my code:
import numpy as np
def maxNumber(nums1, nums2, k):
m = len(nums1)
n = len(nums2)
dp = [[[0 for _ in range(n + 1)] for _ in range(m + 1)] for _ in range(k + 1)]
for i in range(2, k + 1):
for j in range(i + 1):
if j > m or (i - j) > n:
continue
tmp = 0
tmp_nums1 = nums1[:j]
tmp_nums2 = nums2[:(i-j)]
while tmp_nums1 or tmp_nums2:
if tmp_nums1 > tmp_nums2:
tmp = tmp * 10 + tmp_nums1.pop(0)
else:
tmp = tmp * 10 + tmp_nums2.pop(0)
dp[i][j][i - j] = tmp
for i in range(m + 1):
for j in range(n + 1):
if not i and not j:
continue
dp[1][i][j] = max(nums1[:i] + nums2[:j])
for i in range(2, k+1):
for j in range(m+1):
for t in range(i+1-j, n + 1):
if nums1[j - 1] > nums2[t - 1]:
dp[i][j][t] = max((dp[i-2][j-1][t-1]*10+nums1[j-1])*10+nums2[t-1], dp[i][j-1][t-1], dp[i-1][j-1][t-1]*10+nums1[j-1])
else:
dp[i][j][t] = max((dp[i-2][j-1][t-1]*10+nums2[t-1])*10+nums1[j-1], dp[i][j-1][t-1], dp[i-1][j-1][t-1]*10+nums2[t-1])
# print(np.array(dp))
res = []
tmp_res = dp[-1][-1][-1]
while tmp_res:
res.append(tmp_res % 10)
tmp_res //= 10
return res[::-1]
But it outputs [8, 9, 9] on Example 3, and I cannot figure out the reason. Could you help me with it?
Thank you in advance!
Dynamic programming usually implies short-circuiting some of the computation based on results from computations made to date. Often this takes the form of a recursive function. You seem to be taking more of a brute force approach (which usually corresponds to the worse case scenario for dp)
Here is an example of a recursive approach that will lend itself better to optimization:
def largestFrom(M,N,K):
if K == 1: return [max(M+N)] # simple case
if not M and len(N)==K : return N # simple case
if not N and len(M)==K : return M # simple case
result = []
for A,B in [(N,M),(M,N)]:
for i,a in enumerate(A): # trial on numbers from A
if len(A)-i+len(B)<K: break # can't take more from A
if result and a < result[0]: continue # short-circuit
R = [a] + largestFrom(A[i+1:],B,K-1) # recurse with remaining numbers
if R > result: result = R # track best so far
return result
After eliminating the obvious solutions that require no special processing, it goes into a recursive trial/error process that short-circuits the traversal for candidate numbers that won't improve the best result found so far.
The traversal goes through the two lists and attempts to use the number at each position as the first one in the result. It then recurses with the remaining numbers and a size of K-1. So, upon returning from the recursion, a list R is formed of the selected number followed by the largest K-1 sized suffix that can be made with the remaining numbers.
One part of the short circuiting is stopping the loop when the index of the selected number would not leave enough remaining numbers to reach a size of K-1 (i.e. combining the remainder of the current list plus all numbers of the other one).
Another part of short circuiting is comparing the number we are about to try with the first one in the best result. If the candidate number is smaller than the first one in the result, then it would be pointless to go deeper as there is no possibility to form an R list greater than the result we already have.
For example:
combining [3,9] [8,9] with K=3
result starts empty
Going through first list [3,9]
select 3 at position 0
recurse with M=[9] N=[8,9] K=2
will produce R = [3] + [9,8]
R > result, result is now [3,9,8]
select 9 at position 1
recurse with M=[] N=[8,9] K=2
will produce R = [9] + [8,9]
R > result, result is now [9,8,9]
Going through second list [8,9]
select 8 at position 0
8 is smaller than R[0] (9)
short-circuit
select 9 at position 1
recurse with M=[3,9] N=[] K=2
will produce R = [9] + [3,9]
result unchanged (R is < result)
return result [9,8,9]
The for A,B in [(N,M),(M,N)]: loop is merely a shorthand way to avoid duplicating the code for the trial loops on numbers in M and numbers N.
testSet = [ ([3,4,6,5],[9,1,2,5,8,3],5),
([6, 7], [6, 0, 4],5),
([3, 9], [8, 9],3)
]
for M,N,K in testSet:
print(M,N,K,":",largestFrom(M,N,K))
[3, 4, 6, 5] [9, 1, 2, 5, 8, 3] 5 : [9, 8, 6, 5, 3]
[6, 7] [6, 0, 4] 5 : [6, 7, 6, 0, 4]
[3, 9] [8, 9] 3 : [9, 8, 9]
There is alternative way than DP to solve it. Here I've just crafted another solution:
def maxNumber(nums1, nums2, k):
def pick(nums, k):
stack = []
drop = len(nums) - k
for num in nums:
while drop and stack and stack[-1] < num:
stack.pop()
drop -= 1
stack.append(num)
return stack[:k]
def merge(A, B):
ans = []
while A or B:
bigger = A if A > B else B
ans.append(bigger.pop(0))
return ans
return max(merge(pick(nums1, i), pick(nums2, k-i))
for i in range(k+1) if i <= len(nums1) and k-i <= len(nums2))
if __name__ == '__main__':
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
print(maxNumber(nums1, nums2, 5))
print(maxNumber([3,9],[8,9], 3))
Are those answers to your examples provided by the professor? Because they don't make sense to me. Surely the largest number is one that uses all of the digits available? i.e. the largest value will always mean k=m+n. You can't possibly have a larger answer with k=m+(n-1) for instance. What am I missing?
Example 3:
Input: nums1 = [3, 9]
nums2 = [8, 9]
k = 3
Output: [9, 8, 9]
or - in my world k = 4 / Output: [8, 9, 3, 9]
(Hmm... I guess they were provided. Seems a weird question to me. Sorry - I'm unable to help, but I'll post this anyway in case someone else wonders the same thing I did. To me the hard part would be to actually work out what the largest number would be, using all digits. But even then that's not that hard: Compare positions 1 - use the value from the larger array. Compare position 1 of the non-chosen array with position 2... and so on.)

How to make a script that prints the multiples of a number using a for loop and range() function in python

The multiples of number is when you add that number to it self multiple times.
range() generates a sequence of integer numbers. It can take one, two, or three parameters:
range(n): 0, 1, 2, ... n-1
range(x,y): x, x+1, x+2, ... y-1
range(p,q,r): p, p+r, p+2r, p+3r, ... q-1 (if it's a valid increment).
This code with print all the multiples a given number x, n times
x = 2
n = 5
multiples = [x * i for i in range(1, n+1)]
print(multiples)
output:
[2, 4, 6, 8, 10]
This can be accomplished range itself - by setting third argument same as first, assuming that you want to get 10 multiplies of 3 you can do:
n = 3
k = 10
mult = list(range(n, (n*k)+1, n))
print(mult) # [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
Note that due to first argument being inclusive and second being exclusive I need to add 1 to n*k, otherwise I would get 9 instead of 10 numbers. Keep in mind that range is designed for integer numbers.
def the_multiples_of_number(start_number,end_number,the_number_you_want_to_the_multiples):
for x in range(start_number,end_number,the_number_you_want_to_the_multiples):
print(x)
the_multiples_of_number(0,100,7) #it should prints out the multiples of 7 between 0 & 100
What you want is already implemented by the range function in python.
You can read its documentation here.

Determine if an array is decreasing-increasing O(log(n)) and find the "switch" value

I'm trying to determine whether an array is decreasing first then increasing.
Also I need to find out the value when the pattern changes from ascending to descending which would be the min value in the arrays
Let's say for example I have the following array:
[10, 10, 10, 10, 10, 10, 8, 8, 8, 6, 6, 6, 6, 6, 4, 3, 12, 13, 22, 31, 40, 59, 78]
and this one
[-1, 1, 2, 4, 8, 16, 32, 64]
Edit: for simplicity you can assume the values won't be repeated like the first example I showed you
I mainly want to write a program that takes O(logn) time.
I'm trying to use binary search and this is what I have come up with. The input to the function is a sorted list or an descending-ascending list. That can have repeated values as shown in the above examples
def find_middle(ls):
start = 0
end = len(ls) - 1
idx = -1
while start < end:
mid = start + (end - start) // 2
middle = ls[mid]
if ls[mid-1] <= middle and middle > ls[mid+1]):
return middle
elif ls[mid-1] < middle:
start = mid
else:
end = mid
return idx
Sorry for the messy code, I have tinkered with it alot and at this point I've just given up on finding a solution.
If the array is JUST decreasing or increasing, I want the function to return -1.
Any help will be appreciated!
In your example there is repetition. Without repetition this is easy. Check the values at three different indices. Calling these x, y, and z, we can see that the boundary can only be in of of the three intervals (x,y), (y,z), (z,x). So if we look at the ordering of these pairs, either 2 will be ascending and 1 descending or the reverse. The majority matches the array. Then, you can use binary search to find the boundary. This is O(log n)
With repetition this requires (in the worst case) linear time. A bad example is where you have an array where all but 2 elements are identical. In this case it is O(n) just to find the different elements. In general, with repetition the same algorithm applies but you have the added work of finding different elements.

Appending function values to a list while iterating

I am a total Python newbie
so pardon me for this stupid question
The composition() function returns a certain value
However I only want the value to be <=10, and I want 100 of them
The code below calculates the times it took to simulate 100 composition() values to be of <=10
def find():
i=1
aaa=composition()
while(aaa>10):
aaa=composition()
i=i+1
return i
Customers_num=[find() for i in range(100)]
Customers_num=np.array(Customers_num)
print(np.sum(Customers_num))
However, Suppose that the code above returns 150.
And I also want to know all the values that were being simulated in 150 times of composition()
What kind of code should I start with?
I am thinking about combining it with the if else method statement and appending the values to an empty list, but so far my code has been a total disaster
def find():
i=1
aaa=composition()
bbb=[]
if aaa<=10:
bbb.appendd([aaa])
else:
bbb.append([aaa])
aaa=composition()
bbb.appendd([aaa])
while(aaa>10):
i=i+1
if aaa>10:
bbb.append([aaa])
else:
bbb.append([aaa])
return i,bbb
find()
Thanks in advance!
You could make a generator that will generate n of list of values from composition() and stop when n of them are <= 10. This list will include all the numbers, so you have all the intermediate values, and the length of this list will be how "long" it took to generate it. For example (with a fake random composition() function:
from random import randint
def composition():
return randint(0, 20)
def getN(n):
while n > 0:
c = composition()
if c < 10:
n -= 1
yield c
values = list(getN(10)) # get 10 values less than 10
# [2, 0, 11, 15, 12, 8, 16, 16, 2, 8, 10, 3, 14, 2, 9, 18, 6, 11, 1]
time = len(values)
# 19

Categories

Resources