Files
PyClasses/Algorithms.py

253 lines
8.9 KiB
Python

#Python/myClasses/Algorithms.py
#Matthew Ellison
# Created: 01-27-19
#Modified: 03-22-19
#This is a file that contains a few algorithms that I have used several times
"""
Copyright (C) 2019 Matthew Ellison
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import math
#This function returns a list with all the prime numbers <= goalNumber
def getPrimes(goalNumber: int) -> list:
primes = []
foundFactor = False
#If the number is 0 or negative return an empty list
if(goalNumber <= 1):
return primes
#Otherwise the number is at least 2, therefore 2 should be added to the list
else:
primes.append(2)
#We can now start at 3 and skip all even numbers, because they cannot be prime
for possiblePrime in range(3, goalNumber + 1, 2): #Need goalNumber + 1 to account for goalNumber being prime
#Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor
primesCnt = 0
#We can safely assume that there will at lease be 1 element in the primes list because of 2 being added before the loop
topPossibleFactor = math.ceil(math.sqrt(possiblePrime))
while(primes[primesCnt] <= topPossibleFactor):
if((possiblePrime % primes[primesCnt]) == 0):
foundFactor = True
break
else:
primesCnt += 1
#Check if the index has gone out of range
if(primesCnt >= len(primes)):
break
#If you didn't find a factor then the current number must be prime
if(not foundFactor):
primes.append(possiblePrime)
else:
foundFactor = False
primes.sort()
return primes
#This function gets a certain number of primes
def getNumPrimes(numberOfPrimes: int) -> list:
primes = []
foundFactor = False
#If the number is 0 or negative return an empty list
if(numberOfPrimes < 1):
return primes
#Otherwise there is at lease 1, meaning 2 will be the first entry
else:
primes.append(2)
#Loop through every odd number starting at 3 until you reach the correct number of entries looking for a prime number
possiblePrime = 3 #Holds the next possible prime number
while((len(primes) < numberOfPrimes) and (possiblePrime > 0)):
#Loop through all primes we have already found, up to sqrt(possiblePrime), checking for a factor
primesCnt = 0
#We can safely assume that there will at lease be 1 element in the primes list because of 2 being added before the loop
topPossibleFactor = math.ceil(math.sqrt(possiblePrime))
while(primes[primesCnt] <= topPossibleFactor):
#If you find a factor the number is not a prime so raise the flag and break the loop
if((possiblePrime % primes[primesCnt]) == 0):
foundFactor = True
break
else:
primesCnt += 1
#Check if the index has gone out of bounds and break the loop if it has
if(primesCnt >= len(primes)):
break
#If you don't find a factor then this number is prime so add it to the list
if(not foundFactor):
primes.append(possiblePrime)
#If it wasn't prime simply reset the flag
else:
foundFactor = False
#Increment to the next possible prime number
possiblePrime += 2
#Everything should already be in order, but sort it just in case
primes.sort()
#Return the list with all the prime numbers
return primes
#This is a function that returns all the factors of goalNumber
def getFactors(goalNumber: int) -> list:
#You need to get all the primes up to this number
primes = getPrimes(math.ceil(math.sqrt(goalNumber))) #If there is a prime it must be <= sqrt(num)
factors = []
#You need to step through each prime and see if it is a factor in the number
cnt = 0
while((cnt < len(primes)) and (goalNumber > 1)):
#If the prime is a factor you need to add it to the factor list
if((goalNumber % primes[cnt]) == 0):
factors.append(primes[cnt])
goalNumber /= primes[cnt]
#Otherwise advance the location in primes you are looking at
#By not advancing if the prime is a factor you allow for multiple of the same prime number as a factor
else:
cnt += 1
#If you didn't get any factors the number itself must be a prime
if(len(factors) == 0):
factors.append(goalNumber)
goalNumber /= goalNumber
#If for some reason the goalNumber is not 0 print an error message
if(goalNumber > 1):
print("There was an error in getFactors(). A leftover of " + str(goalNumber))
#Return the list of factors
return factors
#This function returns all the divisors of goalNumber
def getDivisors(goalNumber: int) -> list:
divisors = []
#Start by checking that the number is positive
if(goalNumber <= 0):
return divisors
#If the number is 1 return just itself
elif(goalNumber == 1):
divisors.append(1)
return divisors
#Start at 3 and loop through all numbers < (goalNumber / 2 ) looking for a number that divides it evenly
topPossibleDivisor = math.ceil(math.sqrt(goalNumber))
possibleDivisor = 1
while(possibleDivisor <= topPossibleDivisor):
#If you find one add it and the number it creates to the list
if((goalNumber % possibleDivisor) == 0):
divisors.append(possibleDivisor)
#Account for the possibility sqrt(goalNumber) being a divisor
if(possibleDivisor != topPossibleDivisor):
divisors.append(goalNumber / possibleDivisor)
#Take care of a few occations where a number was added twice
if(divisors[len(divisors) - 1] == (possibleDivisor + 1)):
possibleDivisor += 1
possibleDivisor += 1
#Sort the list before returning for neatness
divisors.sort()
#Return the list
return divisors
#This function returns the numth Fibonacci number
def getFib(goalSubscript: int) -> int:
#Setup the variables
fibNums = [1, 1, 0] #A list to keep track of the Fibonacci numbers. It need only be 3 long because we only need the one we are working on and the last 2
#If the number is <= 0 return 0
if(goalSubscript <= 0):
return 0
#Loop through the list, generating Fibonacci numbers until it finds the correct subscript
fibLoc = 2
while(fibLoc < goalSubscript):
fibNums[fibLoc % 3] = fibNums[(fibLoc - 1) % 3] + fibNums[(fibLoc - 2) % 3]
fibLoc += 1
#Return the propper number. The location counter is 1 off of the subscript
return fibNums[(fibLoc - 1) % 3]
#This function returns a list of all Fibonacci numbers <= num
def getAllFib(goalNumber: int) -> list:
#Setup the variables
fibNums = [] #A list to save the Fibonacci numbers
#If the number is <= 0 return an empty list
if(goalNumber <= 0):
return fibNums
#This means that at least 2 1's are elements
fibNums.append(1)
fibNums.append(1)
#Loop to generate the rest of the Fibonacci numbers
while(fibNums[len(fibNums) - 1] <= goalNumber):
fibNums.append(fibNums[len(fibNums) - 1] + fibNums[len(fibNums) - 2])
#At this point the most recent number is > goalNumber, so remove it
fibNums.pop()
return fibNums
#This function returns the product of all elements in the list
def prod(nums: list) -> int:
#If a blank list was sent to the function return 0 as the product
if(len(nums) == 0):
return 0
#Setup the variables
product = 1 #Start at 1 because of working with multiplication
#Loop through every element in a list and multiply them together
for num in nums:
product *= num
#Return the product of all elements
return product
#This is a function that creates all permutations of a string and returns a vector of those permutations.
def getPermutations(master: str, num: int = 0) -> list:
perms = []
#Check if the number is out of bounds
if((num >= len(master)) or (num < 0)):
#Do nothing and return and empty list
perms
#If this is the last possible recurse just return the current string
elif(num == (len(master) - 1)):
perms.append(master)
#If there are more possible recurses, recurse with the current permutations
else:
temp = getPermutations(master, num + 1)
perms += temp
#You need to swap the current letter with every possible letter after it
#The ones needed to swap before will happen automatically when the function recurses
for cnt in range(1, len(master) - num):
#Swap two elements
master = master[0:num] + master[num + cnt] + master[num + 1 : num + cnt] + master[num] + master[num + cnt + 1:]
#Get the permutations after swapping two elements
temp = getPermutations(master, num + 1)
perms += temp
#Swap the elements back
master = master[0:num] + master[num + cnt] + master[num + 1 : num + cnt] + master[num] + master[num + cnt + 1:]
#The array is not necessarily in alpha-numeric order. So if this is the full array sort it before returning
if(num == 0):
perms.sort()
#Return the list
return perms