├── JulianDayCalculator.py ├── ML_tools.py ├── MultiProcessing.py ├── PMT_count.py ├── Plot3dGraphic.py ├── README.md ├── Request.py ├── SinFunction.py ├── Socket.py ├── WGET.sh ├── avg_num_lst.py ├── create_file.py ├── ds_algos ├── 1d_dynamic │ ├── climbingStairs.py │ └── fibonacci.py ├── 2d_dynamic │ └── knapsack.py ├── arrays_hashTables │ ├── containsDup.py │ ├── groupAnagrams.py │ ├── twoSum.py │ └── validAnagram.py ├── backTracking copy │ ├── nQueens.py │ └── wordSearch.py ├── backTracking │ ├── nQueens.py │ └── wordSearch.py ├── fastAndSlow.py ├── graphs │ ├── graphGraphs │ │ └── graphIntro.py │ └── tree │ │ └── trie.py ├── prefixSum │ └── prefixSum.py ├── savingaFile.js ├── stacks │ ├── kFrequentEl.py │ └── validParens.py └── twoPointer │ ├── kadanes_algo.py │ ├── slidingWindow.py │ ├── targetSum.py │ ├── validPalindrome.py │ └── varyingSlidingWindow.py ├── fft.py ├── fft_data.txt ├── py_dict_demo.py ├── randomPolygonGenerator.py ├── relaxation_method.py ├── socket_2.py ├── statistics_admission_rates.py ├── string_manipulation.py └── vector_graphics.py /JulianDayCalculator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This program does... 5 | # 6 | # a. Prompts the user for a date in the form DDMmmYYYY. For example, 26Apr2016. 7 | # 8 | # b. Computes and prints the Julian day number corresponding to 0 h universal time 9 | # on the selected date 10 | # 11 | # c. Computes and prints the day of the week on which the selected date falls. 12 | # 13 | # ---Also, there are functions that are defined for each of the following tasks. 14 | # 15 | # a. Prompt the user and return his/her input string 16 | # 17 | # b. Parses the input string and returns a list containing the year, 18 | # month (1-12), and the day of the month. 19 | # 20 | # c. Compute the Julian day number using the list returned by the function from 21 | # the previous functions output 22 | # 23 | # d. Computes the day of the week given the julian day number 24 | # 25 | # 26 | 27 | #These are refrence lists and dictionaries for various parts of the code. 28 | 29 | month_abb = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 30 | days_of_week_dict = {0:'Sunday', 1:'Monday', 2:'Tuesday', 3:'Wednesday',4:'Thursday',5:'Friday',6:'Saturday'} 31 | month_code_dict = {'Jan':0,'Feb':3,'Mar':3,'Apr':6,'May':1,'Jun':4,'Jul':6,'Aug':2,'Sep':5,'Oct':0,'Nov':3,'Dec':5} 32 | cent_code_dict = {'17':4,'18':2,'19':0,'20':6,'21':4,'22':2,'23':0} 33 | leap_years = [i for i in range(0,2404,4)] 34 | 35 | #This function prompts the user, until the correct format is acheived. 36 | #I used a while loop and a conditional to break the while loop 37 | #The example provided provides clarity for any ambiguity for how to treate 38 | #single digit days and the month of September (Sep vs Sept) 39 | 40 | def prompt_user(): 41 | while True: 42 | print('Please enter a date of the form, DDMmmYYYY') 43 | print('An example is: 02Sep2022') 44 | print('\n') 45 | prompt = input('Enter your date here: ') 46 | print('\n') 47 | date_str = list(prompt) 48 | month_str = ''.join(date_str[2:5]) 49 | if month_str in month_abb and len(prompt) == 9: 50 | print(prompt) 51 | break 52 | return prompt 53 | 54 | #This function parses the strings with join() and string indexing. 55 | #This is why the above function keeps asking for a date given in the 56 | #correct format, since any other format would break this function. 57 | #I output string versions of the year and month for another function that 58 | #computes the days of the week in a different manner, not dependent on the julian day 59 | 60 | def string_parser(prompt): 61 | date_str = list(prompt) 62 | day = int(''.join(date_str[:2])) 63 | month_str = ''.join(date_str[2:5]) 64 | month_num = month_abb.index(month_str) + 1 65 | year_str = ''.join(date_str[5:]) 66 | year = int(year_str) 67 | date_lst = [year, month_num, day] 68 | print(date_lst) 69 | return month_str, year_str, date_lst 70 | 71 | #This is a function that computes the julian day with a formula. 72 | #It takes the prompt to simply print it out next to the output 73 | #of the computation so it is easier to read. 74 | 75 | def JD_calc(date_lst, prompt): 76 | D = date_lst[2] 77 | if date_lst[1] > 2: 78 | M = date_lst[1] 79 | Y = date_lst[0] 80 | JD = int(365.25*(Y + 4716)) + int(30.6001*(M + 1)) + D -1524.5 81 | elif date_lst[1] <=2: 82 | M = date_lst[1] + 12 83 | Y = year-1 84 | JD = int(365.25*(Y + 4716)) + int(30.6001*(M + 1)) + D -1524.5 85 | print('The Julian Day of '+ prompt +' is: '+ str(JD)) 86 | return JD 87 | 88 | #This is a function that computes what day of the week it is, 89 | #when given the julian day. 90 | 91 | #-note, it is much easier to calculate the day of the week given the julian day 92 | #than directly from the gregorian date 93 | 94 | def what_day_jd(JD): 95 | day_code = (JD +1.5)%7 96 | week_day = days_of_week_dict.get(day_code) 97 | print('This is a '+str(week_day)+ '!') 98 | return 99 | 100 | #This function calculates the day of a week given a specific gregorian date. 101 | #I made reference dictionaries that are commented out at the top of this program. 102 | #A nice thing about this function is that it does not depend on where you are in the 103 | #in the world. If you know what the gregorian date of you are interested, it gives 104 | #that date. It works too! The julian date calculator is a day early since it's 105 | #relative to the time in England. 106 | 107 | def what_day(day, month_str, year_str): 108 | YY = int(year_str[-2:]) 109 | y_code = (YY+(YY//4))%7 110 | m_code = int(month_code_dict.get(month_str)) 111 | yy = year_str[:2] 112 | yy_int = int(yy) 113 | if yy_int >= 17 or yy_int <=23: 114 | cent_code = int(cent_code_dict.get(yy)) 115 | else: 116 | cent_code = 0 117 | print('Cannot Compute the day of this date. Sorry : (') 118 | if int(year_str) in leap_years and month_str in ['Jan', 'Feb']: 119 | ly_code = -1 120 | else: 121 | ly_code = 0 122 | day_code = (y_code + m_code + cent_code + ly_code + day)%7 123 | week_day = days_of_week_dict.get(day_code) 124 | return(print('This is a '+str(week_day)+ '!')) 125 | 126 | 127 | #This is all the functions being called. 128 | 129 | prompt = prompt_user() 130 | 131 | month_str, year_str, date_lst = string_parser(prompt) 132 | 133 | JD = JD_calc(date_lst, prompt) 134 | 135 | #what_day(date_lst[2], month_str, year_str) 136 | 137 | what_day_jd(JD) 138 | -------------------------------------------------------------------------------- /ML_tools.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This is a list of machine learning tools to be used on various datasets. 5 | # There are function that utilize iterative loops as well as vectorized 6 | # functions for increase performance. 7 | 8 | import numpy as np 9 | 10 | # Loop version of multi-variable compute_cost 11 | def compute_cost(X, y, w, b): 12 | """ 13 | compute cost 14 | Args: 15 | X (ndarray (m,n)): Data, m examples with n features 16 | y (ndarray (m,)) : target values 17 | w (ndarray (n,)) : model parameters 18 | b (scalar) : model parameter 19 | Returns 20 | cost (scalar) : cost 21 | """ 22 | m = X.shape[0] 23 | cost = 0.0 24 | for i in range(m): 25 | f_wb_i = np.dot(X[i],w) + b #(n,)(n,)=scalar 26 | cost = cost + (f_wb_i - y[i])**2 27 | cost = cost/(2*m) 28 | return cost 29 | 30 | #Function to calculate the cost 31 | 32 | def compute_lin_cost_matrix(X, y, w, b, verbose=False): 33 | """ 34 | Computes the gradient for linear regression 35 | Args: 36 | X (ndarray (m,n)): Data, m examples with n features 37 | y (ndarray (m,)) : target values 38 | w (ndarray (n,)) : model parameters 39 | b (scalar) : model parameter 40 | verbose : (Boolean) If true, print out intermediate value f_wb 41 | Returns 42 | cost: (scalar) 43 | """ 44 | m = X.shape[0] 45 | 46 | # calculate f_wb for all examples. 47 | f_wb = X @ w + b 48 | # calculate cost 49 | total_cost = (1/(2*m)) * np.sum((f_wb-y)**2) 50 | 51 | if verbose: print("f_wb:") 52 | if verbose: print(f_wb) 53 | 54 | return total_cost 55 | 56 | def compute_logistic_cost_matrix(X, y, w, b, logistic=False, lambda_=0, safe=True): 57 | """ 58 | Computes the cost using using matrices 59 | Args: 60 | X : (ndarray, Shape (m,n)) matrix of examples 61 | y : (ndarray Shape (m,) or (m,1)) target value of each example 62 | w : (ndarray Shape (n,) or (n,1)) Values of parameter(s) of the model 63 | b : (scalar ) Values of parameter of the model 64 | verbose : (Boolean) If true, print out intermediate value f_wb 65 | Returns: 66 | total_cost: (scalar) cost 67 | """ 68 | m = X.shape[0] 69 | y = y.reshape(-1,1) # ensure 2D 70 | w = w.reshape(-1,1) # ensure 2D 71 | if logistic: 72 | if safe: #safe from overflow 73 | z = X @ w + b #(m,n)(n,1)=(m,1) 74 | cost = -(y * z) + log_1pexp(z) 75 | cost = np.sum(cost)/m # (scalar) 76 | else: 77 | f = sigmoid(X @ w + b) # (m,n)(n,1) = (m,1) 78 | cost = (1/m)*(np.dot(-y.T, np.log(f)) - np.dot((1-y).T, np.log(1-f))) # (1,m)(m,1) = (1,1) 79 | cost = cost[0,0] # scalar 80 | else: 81 | f = X @ w + b # (m,n)(n,1) = (m,1) 82 | cost = (1/(2*m)) * np.sum((f - y)**2) # scalar 83 | 84 | reg_cost = (lambda_/(2*m)) * np.sum(w**2) # scalar 85 | 86 | total_cost = cost + reg_cost # scalar 87 | 88 | return total_cost # scalar 89 | 90 | 91 | 92 | def compute_cost_logistic(X, y, w, b, lambda_=0, safe=False): 93 | """ 94 | Computes cost using logistic loss, non-matrix version 95 | 96 | Args: 97 | X (ndarray): Shape (m,n) matrix of examples with n features 98 | y (ndarray): Shape (m,) target values 99 | w (ndarray): Shape (n,) parameters for prediction 100 | b (scalar): parameter for prediction 101 | lambda_ : (scalar, float) Controls amount of regularization, 0 = no regularization 102 | safe : (boolean) True-selects under/overflow safe algorithm 103 | Returns: 104 | cost (scalar): cost 105 | """ 106 | 107 | m,n = X.shape 108 | cost = 0.0 109 | for i in range(m): 110 | z_i = np.dot(X[i],w) + b #(n,)(n,) or (n,) () 111 | if safe: #avoids overflows 112 | cost += -(y[i] * z_i ) + log_1pexp(z_i) 113 | else: 114 | f_wb_i = sigmoid(z_i) #(n,) 115 | cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i) # scalar 116 | cost = cost/m 117 | 118 | reg_cost = 0 119 | if lambda_ != 0: 120 | for j in range(n): 121 | reg_cost += (w[j]**2) # scalar 122 | reg_cost = (lambda_/(2*m))*reg_cost 123 | 124 | return cost + reg_cost # scalar 125 | 126 | 127 | 128 | def compute_gradient(X, y, w, b): 129 | """ 130 | Computes the gradient for linear regression 131 | Args: 132 | X (ndarray (m,n)): Data, m examples with n features 133 | y (ndarray (m,)) : target values 134 | w (ndarray (n,)) : model parameters 135 | b (scalar) : model parameter 136 | Returns 137 | dj_dw (ndarray Shape (n,)): The gradient of the cost w.r.t. the parameters w. 138 | dj_db (scalar): The gradient of the cost w.r.t. the parameter b. 139 | """ 140 | m,n = X.shape #(number of examples, number of features) 141 | dj_dw = np.zeros((n,)) 142 | dj_db = 0. 143 | 144 | for i in range(m): 145 | err = (np.dot(X[i], w) + b) - y[i] 146 | for j in range(n): 147 | dj_dw[j] = dj_dw[j] + err * X[i,j] 148 | dj_db = dj_db + err 149 | dj_dw = dj_dw/m 150 | dj_db = dj_db/m 151 | 152 | return dj_db, 153 | 154 | def compute_gradient_logistic(X, y, w, b): 155 | """ 156 | Computes the gradient for linear regression 157 | 158 | Args: 159 | X (ndarray (m,n): Data, m examples with n features 160 | y (ndarray (m,)): target values 161 | w (ndarray (n,)): model parameters 162 | b (scalar) : model parameter 163 | Returns 164 | dj_dw (ndarray (n,)): The gradient of the cost w.r.t. the parameters w. 165 | dj_db (scalar) : The gradient of the cost w.r.t. the parameter b. 166 | """ 167 | m,n = X.shape 168 | dj_dw = np.zeros((n,)) #(n,) 169 | dj_db = 0. 170 | 171 | for i in range(m): 172 | x_i = np.dot(X[i],w) + b 173 | f_wb_i = sigmoid(x_i) #(n,)(n,)=scalar 174 | err_i = f_wb_i - y[i] #scalar 175 | for j in range(n): 176 | dj_dw[j] = dj_dw[j] + err_i * X[i,j] #scalar 177 | dj_db = dj_db + err_i 178 | dj_dw = dj_dw/m #(n,) 179 | dj_db = dj_db/m #scalar 180 | 181 | return dj_db, dj_dw 182 | 183 | def compute_gradient_matrix(X, y, w, b): 184 | """ 185 | Computes the gradient for linear regression 186 | 187 | Args: 188 | X (ndarray (m,n)): Data, m examples with n features 189 | y (ndarray (m,)) : target values 190 | w (ndarray (n,)) : model parameters 191 | b (scalar) : model parameter 192 | Returns 193 | dj_dw (ndarray (n,1)): The gradient of the cost w.r.t. the parameters w. 194 | dj_db (scalar): The gradient of the cost w.r.t. the parameter b. 195 | 196 | """ 197 | m,n = X.shape 198 | f_wb = X @ w + b 199 | e = f_wb - y 200 | dj_dw = (1/m) * (X.T @ e) 201 | dj_db = (1/m) * np.sum(e) 202 | 203 | return dj_db,dj_dw 204 | 205 | def gradient_descent(X, y, w_in, b_in, cost_function, gradient_function, alpha, num_iters): 206 | ''' 207 | Performs batch gradient descent to learn theta. Updates theta by taking 208 | num_iters gradient steps with learning rate alpha 209 | 210 | Args: 211 | X : (array_like Shape (m,n) matrix of examples 212 | y : (array_like Shape (m,)) target value of each example 213 | w_in : (array_like Shape (n,)) Initial values of parameters of the model 214 | b_in : (scalar) Initial value of parameter of the model 215 | cost_function: function to compute cost 216 | gradient_function: function to compute the gradient 217 | alpha : (float) Learning rate 218 | num_iters : (int) number of iterations to run gradient descent 219 | Returns 220 | w : (array_like Shape (n,)) Updated values of parameters of the model after 221 | running gradient descent 222 | b : (scalar) Updated value of parameter of the model after 223 | running gradient descent 224 | ''' 225 | 226 | # number of training examples 227 | m = len(X) 228 | 229 | # An array to store values at each iteration primarily for graphing later 230 | hist={} 231 | hist["cost"] = []; hist["params"] = []; hist["grads"]=[]; hist["iter"]=[]; 232 | 233 | w = copy.deepcopy(w_in) #avoid modifying global w within function 234 | b = b_in 235 | save_interval = np.ceil(num_iters/10000) # prevent resource exhaustion for long runs 236 | 237 | for i in range(num_iters): 238 | 239 | # Calculate the gradient and update the parameters 240 | dj_db,dj_dw = gradient_function(X, y, w, b) 241 | 242 | # Update Parameters using w, b, alpha and gradient 243 | w = w - alpha * dj_dw 244 | b = b - alpha * dj_db 245 | 246 | # Save cost J,w,b at each save interval for graphing 247 | if i == 0 or i % save_interval == 0: 248 | hist["cost"].append(cost_function(X, y, w, b)) 249 | hist["params"].append([w,b]) 250 | hist["grads"].append([dj_dw,dj_db]) 251 | hist["iter"].append(i) 252 | 253 | # Print cost every at intervals 10 times or as many iterations if < 10 254 | if i% math.ceil(num_iters/10) == 0: 255 | #print(f"Iteration {i:4d}: Cost {cost_function(X, y, w, b):8.2f} ") 256 | cst = cost_function(X, y, w, b) 257 | print(f"Iteration {i:9d}, Cost: {cst:0.5e}") 258 | return w, b, hist #return w,b and history for graphing 259 | 260 | def gradient_descent(X, y, w_in, b_in, alpha, num_iters): 261 | ''' 262 | Performs batch gradient descent 263 | 264 | Args: 265 | X (ndarray (m,n) : Data, m examples with n features 266 | y (ndarray (m,)) : target values 267 | w_in (ndarray (n,)): Initial values of model parameters 268 | b_in (scalar) : Initial values of model parameter 269 | alpha (float) : Learning rate 270 | num_iters (scalar) : number of iterations to run gradient descent 271 | 272 | Returns: 273 | w (ndarray (n,)) : Updated values of parameters 274 | b (scalar) : Updated value of parameter 275 | ''' 276 | # An array to store cost J and w's at each iteration primarily for graphing later 277 | J_history = [] 278 | w = copy.deepcopy(w_in) #avoid modifying global w within function 279 | b = b_in 280 | 281 | for i in range(num_iters): 282 | # Calculate the gradient and update the parameters 283 | dj_db, dj_dw = compute_gradient_logistic(X, y, w, b) 284 | 285 | # Update Parameters using w, b, alpha and gradient 286 | w = w - alpha * dj_dw 287 | b = b - alpha * dj_db 288 | 289 | # Save cost J at each iteration 290 | if i<100000: # prevent resource exhaustion 291 | J_history.append(compute_cost_logistic(X, y, w, b) ) 292 | 293 | # Print cost every at intervals 10 times or as many iterations if < 10 294 | if i% math.ceil(num_iters / 10) == 0: 295 | print(f"Iteration {i:4d}: Cost {J_history[-1]} ") 296 | 297 | return w, b, J_history #return final w,b and J history for graphing 298 | 299 | 300 | 301 | 302 | def zscore_normalize_features(X,rtn_ms=False): 303 | ''' 304 | returns z-score normalized X by column 305 | Args: 306 | X : (numpy array (m,n)) 307 | Returns 308 | X_norm: (numpy array (m,n)) input normalized by column 309 | ''' 310 | mu = np.mean(X,axis=0) 311 | sigma = np.std(X,axis=0) 312 | X_norm = (X - mu)/sigma 313 | 314 | if rtn_ms: 315 | return(X_norm, mu, sigma) 316 | else: 317 | return(X_norm) 318 | 319 | def log_1pexp(x, maximum=20): 320 | ''' approximate log(1+exp^x) 321 | https://stats.stackexchange.com/questions/475589/numerical-computation-of-cross-entropy-in-practice 322 | Args: 323 | x : (ndarray Shape (n,1) or (n,) input 324 | out : (ndarray Shape matches x output ~= np.log(1+exp(x)) 325 | ''' 326 | 327 | out = np.zeros_like(x,dtype=float) 328 | i = x <= maximum 329 | ni = np.logical_not(i) 330 | 331 | out[i] = np.log(1 + np.exp(x[i])) 332 | out[ni] = x[ni] 333 | return out 334 | 335 | def sigmoid(x): 336 | return 1/(1 + np.exp(-x)) 337 | -------------------------------------------------------------------------------- /MultiProcessing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # William Murphy 4 | # 22May22 5 | 6 | # This program compares optimizxation techniques 7 | # on computing the mandelbrot set, and computes a 8 | # super hi-resolution plot with the most optimized 9 | # method 10 | 11 | import time 12 | import numpy as np 13 | import numexpr as ne 14 | import multiprocessing as mp 15 | import matplotlib.pyplot as plt 16 | from matplotlib import cm 17 | 18 | # Parameters of all the funcitons run 19 | 20 | x_min = -00.73 21 | x_max = -0.805 22 | y_min = 0.01 23 | y_max = 0.17 24 | 25 | x_mid = (x_max - x_min)/2 26 | y_mid = (y_max - y_min)/2 27 | 28 | width = 512 29 | height = 384 30 | max_iter = 1000 31 | 32 | width_a = 1024 33 | height_a = 768 34 | 35 | width_b = 4096*2 36 | height_b = 3072*2 37 | 38 | h_width = width//2 39 | h_height = height//2 40 | 41 | # List for storing data to be plotted 42 | processes_lst = [] 43 | 44 | iter_lst = range(100,2001,100) 45 | 46 | timeit_lst_serial = [] 47 | timeit_lst_vect = [] 48 | timeit_lst_static = [] 49 | timeit_lst_ne = [] 50 | 51 | timeit_lst_seriala = [] 52 | timeit_lst_vecta = [] 53 | timeit_lst_statica = [] 54 | timeit_lst_nea = [] 55 | 56 | #This line makes sure that the the data is sectioned in the middle 57 | num_cpu = 4 58 | 59 | # Computes the mandelbrot/ parts of the set 60 | # This is the same program that was turned for p5_hw5 61 | 62 | def mandel_serial(x_min, x_max, y_min, y_max, width, height, max_iter): 63 | 64 | mandel_arr = np.ones((width, height, 3), dtype='uint8') 65 | 66 | # Need to comput half the array since it's broken up 67 | re = np.linspace(x_min, x_max, width) 68 | im = np.linspace(y_min, y_max, height) 69 | 70 | color_arr = np.array(([1,1,1,1])) 71 | color_sch = cm.get_cmap('magma') 72 | 73 | for i in range(width): 74 | for k in range(height): 75 | c = complex(re[i],im[k]) 76 | m, z = 0, 0 77 | while abs(z) <= 2 and m <= max_iter: 78 | z = z*z + c 79 | m += 1 80 | color = round(float(1-(m/max_iter)), 2) 81 | pix_color = color_arr * color_sch(color)*255 82 | mandel_arr[i,k,:] = pix_color[0:3].astype(int) 83 | 84 | return mandel_arr 85 | 86 | # Everything below is for Multiprocessing/Optimization 87 | 88 | ############################################################################# 89 | 90 | # Vectorized version of the mandel_serial 91 | 92 | def mandel_vect(x_min, x_max, y_min, y_max, width, height, max_iter): 93 | 94 | re = np.linspace(x_min, x_max, width).reshape((1, width)) 95 | im = np.linspace(y_min, y_max, height).reshape((height, -1)) 96 | c = re + 1j * im 97 | z = np.zeros(c.shape, dtype='complex128') 98 | 99 | # Keeping track of how many iterations it to diverge 100 | div_num = np.zeros(c.shape, dtype=int) 101 | 102 | # Keeping this for loop as small as possible and using arrays 103 | # and array indexing to do all computation in parallel and 104 | # in C 105 | 106 | for i in range(max_iter): 107 | in_set = np.less(z.real*z.real+z.imag*z.imag, 3) 108 | div_num[in_set] = i 109 | z[in_set] = z[in_set]**2 + c[in_set] 110 | 111 | return div_num 112 | 113 | ############################################################################## 114 | 115 | # This is a helper function to place the data in a dictionary and process it at the same time 116 | # This is known as inter process communication 117 | 118 | def data_queue( x_min, x_max, y_min, y_max, width, height, max_iter, Queue, key): 119 | mandel_arr = mandel_vect(x_min, x_max, y_min, y_max, width, height, max_iter) 120 | return Queue.put({key : mandel_arr}) 121 | 122 | # The function that parallelizes the processing 123 | 124 | def mandel_static_mp(x_max, x_min, y_min, y_max, width, height, max_iter): 125 | # Using a queue to organize data 126 | mandel_data = mp.Queue() 127 | processes_lst = [] 128 | 129 | # This dictionary organizes the data according to which core it was computed on 130 | data_dict = {} 131 | 132 | #min_iter = max_iter // 4 133 | #Divides the compute power among the 4 cores of the ras-pi 134 | 135 | p0 = mp.Process(target=data_queue, args=(x_min, x_min + x_mid, y_min, y_min + y_mid, width, height, max_iter, mandel_data, 0)) 136 | p0.start() 137 | processes_lst.append(p0) 138 | 139 | p1 = mp.Process(target=data_queue, args=(x_min + x_mid, x_max, y_min, y_min + y_mid, width, height, max_iter, mandel_data, 1)) 140 | p1.start() 141 | processes_lst.append(p1) 142 | 143 | p2 = mp.Process(target=data_queue, args=(x_min, x_min + x_mid, y_min + y_mid, y_max, width, height, max_iter, mandel_data, 2)) 144 | p2.start() 145 | processes_lst.append(p2) 146 | 147 | p3 = mp.Process(target=data_queue, args=(x_min + x_mid, x_max, y_min + y_mid, y_max, width, height, max_iter, mandel_data, 3)) 148 | p3.start() 149 | processes_lst.append(p3) 150 | 151 | # Getting the data from the dictionary ready to be joined 152 | for i in processes_lst: 153 | data_dict.update(mandel_data.get()) 154 | 155 | bot_arr = np.concatenate((data_dict[0], data_dict[2]), axis=0) 156 | top_arr = np.concatenate((data_dict[1], data_dict[3]), axis=0) 157 | 158 | mandel_arr = np.concatenate((bot_arr,top_arr), axis=1) 159 | 160 | for p in processes_lst: 161 | p.join() 162 | 163 | return mandel_arr 164 | 165 | ################################################################################ 166 | 167 | # This algorithm is very similar to my mandel_vect(), only now 168 | # it uses numexpr to evaluate inside the for loop 169 | 170 | # using numexpr instead of numpy means that temporary arrays are 171 | # not created and arrays are processed on multiple cores. 172 | 173 | def mandel_ne(x_min, x_max, y_min, y_max, width, height, max_iter): 174 | 175 | #Mapping the complex plane onto the area to be graphed 176 | re = np.linspace(x_min, x_max, width).reshape((1, width)) 177 | im = np.linspace(y_min, y_max, height).reshape((height, -1)) 178 | c = re + 1j * im 179 | 180 | # Initialize z to all zeros 181 | z = np.zeros(c.shape, dtype='complex128') 182 | 183 | # To keep track when the iteration diverged 184 | div_num = np.zeros(c.shape, dtype=int) 185 | 186 | # Keeping this for loop as small as possible, using numexpr 187 | # instead of numpy so temporary arrays are not created and 188 | # arrays are processed on multiple cores. 189 | for i in range(max_iter): 190 | in_set = ne.evaluate('z.real**2 + z.imag**2 < 2') 191 | div_num[in_set] = i 192 | z = ne.evaluate('where(in_set,z**2+c,z)') 193 | 194 | return div_num 195 | 196 | 197 | # Program to compare functions 198 | 199 | if __name__ == '__main__': 200 | 201 | # Makes the mandelbort set 202 | mandel_arr = mandel_ne(x_min, x_max, y_min, y_max, width_b, height_b, max_iter) 203 | 204 | 205 | string_for_data_output = ''' 206 | for i in iter_lst: 207 | 208 | 209 | # Lower Resolution function calls 210 | 211 | t0 = time.perf_counter() 212 | mandel_serial(x_min, x_max, y_min, y_max, width, height, i) 213 | t1 = time.perf_counter() 214 | t_1 = t1 - t0 215 | timeit_lst_serial.append(t_1) 216 | 217 | ta = time.perf_counter() 218 | mandel_vect(x_min, x_max, y_min, y_max, width, height, i) 219 | tb = time.perf_counter() 220 | t_a = tb - ta 221 | timeit_lst_vect.append(t_a) 222 | 223 | t2 = time.perf_counter() 224 | mandel_static_mp(x_min, x_max, y_min, y_max, width, height, i) 225 | t3 = time.perf_counter() 226 | t_2 = t3 - t2 227 | timeit_lst_static.append(t_2) 228 | 229 | t4 = time.perf_counter() 230 | mandel_ne(x_min, x_max, y_min, y_max, width, height, i) 231 | t5 = time.perf_counter() 232 | t_3 = t5 - t4 233 | timeit_lst_ne.append(t_3) 234 | 235 | # Higher Resolution function calls 236 | 237 | t0a = time.perf_counter() 238 | mandel_serial(x_min, x_max, y_min, y_max, width_a, height_a, i) 239 | t1a = time.perf_counter() 240 | t_1a = t1a - t0a 241 | timeit_lst_seriala.append(t_1a) 242 | 243 | tc = time.perf_counter() 244 | mandel_vect(x_min, x_max, y_min, y_max, width_a, height_a, i) 245 | td = time.perf_counter() 246 | t_b = td - tc 247 | timeit_lst_vecta.append(t_b) 248 | 249 | t2a = time.perf_counter() 250 | mandel_static_mp(x_min, x_max, y_min, y_max, width_a, height_a, i) 251 | t3a = time.perf_counter() 252 | t_2a = t3a - t2a 253 | timeit_lst_statica.append(t_2a) 254 | 255 | t4a = time.perf_counter() 256 | mandel_ne(x_min, x_max, y_min, y_max, width_a, height_a, i) 257 | t5a = time.perf_counter() 258 | t_3a = t5a - t4a 259 | timeit_lst_nea.append(t_3a) 260 | 261 | ''' 262 | 263 | fig, ax = plt.subplots()#(1,2) 264 | 265 | string_plotting_figures = ''' 266 | fig.suptitle('Compute times for various methods of computing the mandelbrot set') 267 | 268 | #Lower resolutions data plot 269 | 270 | p1, =ax[0].plot(iter_lst, timeit_lst_serial,label="Serial") 271 | pa, =ax[0].plot(iter_lst, timeit_lst_vect,label="Vectorized Serial") 272 | p2, =ax[0].plot(iter_lst, timeit_lst_static,label="Static Multiprocessing") 273 | p3, =ax[0].plot(iter_lst, timeit_lst_ne,label="NumExpr") 274 | ax[0].set_title('Low Resolution') 275 | ax[0].set_xlabel('Interations') 276 | ax[0].set_ylabel('Time Elapsed (s)') 277 | ax[0].legend(loc='best') 278 | 279 | 280 | # Higher resolution data plot 281 | 282 | p1a, =ax[1].plot(iter_lst, timeit_lst_seriala,label="Serial") 283 | pb, =ax[1].plot(iter_lst, timeit_lst_vecta,label="Vectorized Serial") 284 | p2a, =ax[1].plot(iter_lst, timeit_lst_statica,label="Static Multiprocessing") 285 | p3a, =ax[1].plot(iter_lst, timeit_lst_nea,label="NumExpr") 286 | 287 | ax[1].set_title('High Resolution') 288 | ax[1].set_xlabel('Interations') 289 | ax[1].set_ylabel('Time Elapsed (s)') 290 | ax[1].legend(loc='best') 291 | ''' 292 | sup_hi_res = mandel_ne(x_min, x_max, y_min, y_max, width_a, height_a, 1000) 293 | ax.axis('off') 294 | ax.imshow(sup_hi_res, cmap='magma') 295 | 296 | plt.show() 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /PMT_count.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This program does 4 | 5 | # a) Has a function which simulates photon counting for 1000 one-millisecond 6 | # intervals, with the probability of a detection in each interval being 0.002. 7 | # The function should return the total number of detections. 8 | 9 | # b) Plots a histogram displaying the result of calling the function 1000 times 10 | 11 | # c) overlays on the plot, in a different color, a graph of the Poisson distribution 12 | # with mean, standard deviation, and maximum value corresponding to this simulation. 13 | 14 | 15 | import numpy as np 16 | import random 17 | import matplotlib.pyplot as plt 18 | import scipy.stats as stats 19 | 20 | 21 | # This function counts two numbers out of 1000 possible 22 | # numbers to choose from. If one of the two is chosen, 23 | # 1 is added to the counting variable. 24 | 25 | #NOTE- The two numbers choose for this program have no 26 | # special purpose. 27 | 28 | def counting_photons(N): 29 | photon_num = 0 30 | for i in range(N+1): 31 | x = random.randint(0, 1000) 32 | if x in [271, 277]: 33 | photon_num += 1 34 | else: 35 | pass 36 | return photon_num 37 | 38 | #num_photons = counting_photons(1000) 39 | #print(num_photons) 40 | 41 | # This functions calls the previous function 42 | # 1000 times. After each call, it stores the output 43 | # into a list, so it can later be plotted. 44 | 45 | def counting_counted_photons(trials): 46 | outcome = [] 47 | for i in range(trials): 48 | outcome.append(counting_photons(1000)) 49 | return outcome 50 | 51 | 52 | #Creating a Poisson Fit 53 | outcome_lst = counting_counted_photons(1000) 54 | mean = np.mean(outcome_lst) 55 | data_max = np.max(outcome_lst) 56 | sd = round(np.std(outcome_lst), 3) 57 | print(data_max) 58 | 59 | x = np.arange(0,5, 0.01) 60 | pmf = stats.poisson.pmf(x, mean) 61 | 62 | # Plotting 63 | fig, ax = plt.subplots() 64 | 65 | ax.plot(x,pmf, color='red') 66 | 67 | ax.hist(outcome_lst, density=True, facecolor='g', alpha=0.75) 68 | 69 | ax.set_title('Histogram of 1000 trials of \n counting photons for 1000 miliseconds') 70 | 71 | ax.text(5,0.25,'Max Value: '+str(data_max)+'\n \u03BC = '+str(mean)+'\n \u03C3 = '+str(sd)) 72 | ax.set_xlabel('Number of Photons Counted') 73 | ax.set_ylabel('Probability') 74 | ax.grid(True) 75 | plt.show() 76 | -------------------------------------------------------------------------------- /Plot3dGraphic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Author -- William Murphy 4 | # Date -- 04May2022 5 | 6 | 7 | # Plotting the function z(x,y) = sin(x)cos(y) 8 | 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | from mpl_toolkits import mplot3d 12 | 13 | 14 | # Compute z_func to make the surface. 15 | def func_z(x,y): 16 | return np.sin(x)*np.cos(y) 17 | 18 | #Define the space we are solving for z 19 | x = np.linspace(0, 5*np.pi, 900) 20 | y = np.linspace(0, 5*np.pi, 900) 21 | 22 | #Creating amesh grid for the points in the set z 23 | X, Y = np.meshgrid(x, y) 24 | Z = func_z(X, Y) 25 | 26 | 27 | #Making the 3D space 28 | fig = plt.figure() 29 | ax = plt.axes(projection="3d") 30 | 31 | #Setting labels and title 32 | ax.set_xlabel('x') 33 | ax.set_ylabel('y') 34 | ax.set_zlabel('z') 35 | ax.set_title('z(x,y)=sin(x)cos(y)') 36 | 37 | #The requested method - plot_surface() 38 | ax.plot_surface(X,Y,Z, cmap='cividis') 39 | 40 | plt.show() 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python_projects 2 | 3 | This is an assortment of fun projects that goes over different methods of scientific computing in python. The projects range from programs that solve any static differential equations, to fourier transformations, and more advanced ideas of scientific computing like multiprocessing and vercotization of algorithms. It is not only calculations though, some files also include component hardware like solar cells, and thermometers. 4 | 5 | In addtion to the scientific computing programs, the repo also includes a file that calculates regressions and imple neural networks from scratch. 6 | 7 | Thanks for taking a look, and if you have any questions, feel free to reach out. 8 | -------------------------------------------------------------------------------- /Request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import requests 5 | 6 | r = requests.get('https://web.physics.ucsb.edu/~phys129/lipman/', auth=('user', 'pass'), headers={'Connection':'close'}) 7 | 8 | #Makng the html text a string 9 | html_txt = str(r.text) 10 | 11 | #Finding parsing the string for the desired line 12 | begin_where = html_txt.find('Latest update') 13 | end_where = html_txt.find('
')-7 14 | update_str = html_txt[begin_where:end_where] 15 | 16 | #Deleting the undesired text form the desired line 17 | last_update = update_str.replace('','').replace(' ',' ') 18 | 19 | print('') 20 | print('Physics 129L '+last_update) 21 | print('') 22 | -------------------------------------------------------------------------------- /SinFunction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | 5 | # This is program that does a few different things 6 | 7 | 8 | 9 | # a. Prompts the user for a non-zero angle in degrees 10 | 11 | # b. Continues to reprompt the user unless the input is acceptable 12 | 13 | # c. Prompts the user for a number, ≤ 25, of terms to sum in a series 14 | 15 | # d. Continues to reprompt the user unless the input is acceptable 16 | 17 | # e. Calculates, using a function you have defined called sind(), the sine of the angle 18 | 19 | # provided by the user. This function must sum a series to the number of terms 20 | 21 | # requested, and may not use any predefined Python math functions. 22 | 23 | # f. Calculates the sine of the angle using math.sin() 24 | 25 | # g. Prints out a quantitative comparison between the two answers including the ratio 26 | 27 | # and the absolute difference. 28 | 29 | 30 | import math as m 31 | 32 | #This is a function that can tell if a string is a float or not. 33 | 34 | def isfloat(num): 35 | try: 36 | float(num) 37 | return True 38 | except ValueError: 39 | return False 40 | 41 | #A while loop that continues the prompt the users, unless they put in a 42 | #data type that can be turned into a float. 43 | #I called the above function here to make the code easier to read. 44 | #Further, within this while loop, I calculated the degrees into radians as 45 | #soon as I could since I would be needed to work in them for the rest of the 46 | #the program. 47 | 48 | while True: 49 | prompt_1 = input('Please enter an angle in degrees you are interested in: ') 50 | q = isfloat(prompt_1) 51 | if q == True: 52 | radians = float(prompt_1)/180 * m.pi 53 | break 54 | 55 | #I used the same structure of a while loop plus a conditional here as well, 56 | #to get the user to input an integer for the length of the series. 57 | 58 | while True: 59 | prompt_2 = input('Please enter a non-zero integer less than or equal to 25: ') 60 | if prompt_2.isdigit() == True: 61 | if int(prompt_2) <= 25: 62 | series_len = abs(int(prompt_2)) 63 | break 64 | 65 | #Since we are not using any pre built functions from python, I built my own 66 | #factorial function. Strictly speaking, if I was building a more general purpose 67 | #factorial function I would disqualify negative number, but I already did this 68 | #in this while loop above. Ii did however define 0! = 1 though, to avoid a zero 69 | #division error 70 | 71 | def factorial(num): 72 | f = 1 73 | if num == 0: 74 | f == 1 75 | else: 76 | for i in range(1, num + 1): 77 | f = f * i 78 | return f 79 | 80 | #This is the requested sind() function. It takes the users inputs and computes 81 | #the first 'prompt_2' terms of the sin(prompt_1) taylor series. It calls the 82 | #factorial function that was created above to keep the code cleaner 83 | 84 | def sind(rad, series_len): 85 | sin = 0 86 | for i in range(0, series_len, 1): 87 | n = 2*i+1 88 | sin = sin + (((-1)**(i))*(rad**(n))/(factorial(n))) 89 | print(sin) 90 | return sin 91 | 92 | 93 | #Outputs 94 | 95 | 96 | sin_me = sind(radians, series_len) 97 | sin_math = m.sin(radians) 98 | 99 | print("My sine function's output is "+str(sin_me)) 100 | print('\n') 101 | 102 | print("Python's math module output is "+str(sin_math)) 103 | print('\n') 104 | 105 | print("The ratio of my function's output over python's math module's is "+str(sin_me/sin_math)) 106 | print('\n') 107 | 108 | abs_dif = abs(sin_me - sin_math) 109 | 110 | print('The absolute difference between the two is '+str(abs_dif)) 111 | print('\n') 112 | 113 | -------------------------------------------------------------------------------- /Socket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | #Sockets and Requests 4 | 5 | import socket 6 | 7 | host = "web.physics.ucsb.edu" 8 | port = 80 9 | 10 | # creating a socket 11 | thesocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | 13 | # connecting to the client 14 | thesocket.connect((host,port)) 15 | 16 | # Making a request for HTTP data 17 | request = "GET /~phys129/lipman/ HTTP/1.1\r\nHost:%s\r\n\r\n" % host 18 | thesocket.send(request.encode()) 19 | 20 | # Receiving the HTTP data and closing the socket 21 | response = thesocket.recv(4096) 22 | http_response = str(repr(response)) 23 | thesocket.shutdown(socket.SHUT_RDWR) 24 | thesocket.close() 25 | 26 | #Parsing the HTTP data for the desired text 27 | begining = http_response.find('Latest update') 28 | ending = http_response.find('') 29 | Latest_update = http_response[begining:ending].replace('','').replace(' ',' ') 30 | 31 | #The output 32 | print('') 33 | print('Physics 129L '+Latest_update) 34 | print('') 35 | -------------------------------------------------------------------------------- /WGET.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | 5 | # Author : WIlliam Murphy 6 | # Date : 03May22 7 | 8 | # This shell script makes a request to physics 129L course web pages and 9 | # returns when the latest update occured on the anoucemnets page. 10 | 11 | # This shell script implements the commands - 'wget', 'grep', 'sed' 12 | 13 | 14 | wget -O- web.physics.ucsb.edu/~phys129/lipman/ | grep -h "Latest update" | sed -e 's///' -e 's/ / /' -e 's/<\/span><\/p>//' 15 | 16 | 17 | -------------------------------------------------------------------------------- /avg_num_lst.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # A program that reads numbers from a user-specified 4 | # file and prints out their average 5 | # note - input file requires one number per line 6 | 7 | # Author - Billy Murphy 8 | # 12 April 2022 9 | 10 | 11 | import numpy as np 12 | 13 | 14 | #Prompting the user for the name of file to operate on. 15 | 16 | fname = input('What is the file you would like to read: ') 17 | 18 | #Reading the text file and returning the contents as a list. 19 | #Each item of the list represents a line of the file. 20 | 21 | infile = open(str(fname), 'r') 22 | lines = infile.readlines() 23 | 24 | #Because the output of lines is has the new line character 25 | #a for loop is used to remove it from each item of of lines and 26 | #and appends the cleaned string to str_lst. This allows for numbers with 27 | #more than one digit. 28 | 29 | str_lst = [] 30 | for line in lines: 31 | i = line.rstrip("\n") 32 | str_lst.append(i) 33 | 34 | #Because there is no string.isdigit() method, I am using a 35 | #a function that can tell if a sting is float or not. 36 | #It has a simply True or False output and is used later. 37 | def isfloat(num): 38 | try: 39 | float(num) 40 | return True 41 | except ValueError: 42 | return False 43 | 44 | #This for loop populates a list that can be operatored on by numpy. Within this for loop 45 | #are some conditionals statements that handle the different types of characters that are 46 | #possible. Namely letters, numbers, and special characters. I included this extra bit to make 47 | #program robust to errors within the data it is analyzing. I don't want to rely on 48 | #the input data to be in a perfect format for the practical reason that often times real world 49 | #data is quite messy. 50 | 51 | num_lst = [] 52 | for i in str_lst : 53 | if i.isdigit() == True: 54 | num_lst.append(float(i)) 55 | elif isfloat(str(i)) == True: 56 | num_lst.append(float(i)) 57 | elif isfloat(str(i)) == False: 58 | print('ERROR: '+str(i)+' was skipped because it is not a number.') 59 | 60 | #The program prints the average of the given file. 61 | print('The average is: '+str(np.average(num_lst))) 62 | 63 | #As an add feature to the program I made it so that if there is a mistake 64 | #in the original file, the code with skip over that entry and alert the user 65 | #that there is an entry that was skipped. 66 | 67 | #Closing the file. This may seem like a trivial comment, though for the sake of explination I am including this time. I the program did not close the file, there is all kinds of mysterious and troublesome problems that could arise from the leaving a file open. Most likely the file would become currupted. This would obviously be a terrible thing. To write a program that corrupts files is pretty much a fail. Especially since you might not notice it right away! 68 | infile.close() 69 | 70 | -------------------------------------------------------------------------------- /create_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is a program that creates a file containing two 4 | # user-provided strings,one per line. 5 | # 6 | # Author -> Billy Murphy 12 April 2022 7 | 8 | 9 | #This is the first prompt asking for the name of the text file 10 | file_name = input('What would you like to name your text file: ') 11 | 12 | #This line creates a file using the given file name and allows the program to write to it. 13 | fname = open(str(file_name), "w") 14 | 15 | #These next four lines of code prompt the user for the two strings 16 | print('What is the first string?') 17 | str_1 = input() 18 | 19 | print('What is the second string?') 20 | str_2 = input() 21 | 22 | #The two strings are then saved into a list with 2 entries 23 | #string one plus a new line character, 24 | #and string two, with another new line character 25 | L = [str(str_1)+'\n', str(str_2)+'\n'] 26 | 27 | #This line writes the list of string, list L, to the text file 28 | fname.writelines(L) 29 | 30 | #In order to let the user confirm that the program ran properly. 31 | #A print statement is given confirming 32 | print('The text file '+str(file_name)+' is now in your current working directory') 33 | 34 | #This line closes the file 35 | fname.close() 36 | 37 | -------------------------------------------------------------------------------- /ds_algos/1d_dynamic/climbingStairs.py: -------------------------------------------------------------------------------- 1 | # memoization and caching or true dynamic solution -> NOPE 2 | # bottom up dynamic programming solution -> Oh Ya!! 3 | 4 | 5 | def climbStairs(n): 6 | one, two = 1, 1 7 | 8 | for i in range(n - 1): 9 | temp = one 10 | one = one + two 11 | two = temp 12 | 13 | return one 14 | 15 | 16 | print(climbStairs(5)) 17 | -------------------------------------------------------------------------------- /ds_algos/1d_dynamic/fibonacci.py: -------------------------------------------------------------------------------- 1 | # compute the fibonacci number 2 | 3 | # The input will be the index n of the fibonacci series 4 | # and the output should be F(n) 5 | 6 | 7 | # This is a dynamic programming solution that utilizes the 8 | # the bottom up approach for a linear problem 9 | # The space compexity is O(1) and time complexity is O(n) 10 | def F(n): 11 | # This is the "cache" that will hold 12 | # previously computed values 13 | results = [0, 1] 14 | # These two conditionals handle the 15 | # edge cases 16 | if n <= 0: 17 | return 0 18 | if n == 1: 19 | return 1 20 | # Inititalizing a counter variable to 21 | i = 1 22 | while i < n: 23 | # iteratively find the sum of our 24 | # results arr 25 | sum = results[0] + results[1] 26 | # and update the results array 27 | # to hold the prvious el at arr[1] and 28 | # the newly computed sum 29 | results = [results[1], sum] 30 | # then incrementing i 31 | i += 1 32 | # return the last sum => F(n) 33 | return sum 34 | 35 | 36 | print(F(5)) # 0, 1, 1, 2 , 3 37 | -------------------------------------------------------------------------------- /ds_algos/2d_dynamic/knapsack.py: -------------------------------------------------------------------------------- 1 | # 0/1 Knapsack 2 | # 2-d dynamic programming problem (take it or leave it!!!) 3 | 4 | # can the target be reached with the given arr 5 | 6 | # input: [1,2,3] target = 5 7 | 8 | 9 | def knapSack(arr, target): 10 | return True 11 | -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/containsDup.py: -------------------------------------------------------------------------------- 1 | # Given an integer array nums, 2 | # return true if any value appears at least twice in the array, 3 | # and return false if every element is distinct. 4 | 5 | def containsDuplicate(nums): 6 | """ 7 | :type nums: List[int] 8 | :rtype: bool 9 | """ 10 | dict = {} 11 | for el in nums: 12 | if el not in dict: 13 | dict[el] = el 14 | else: 15 | return True 16 | return False 17 | 18 | 19 | # PASSES 20 | 21 | # nums = [1,2,3,4,5] 22 | 23 | # print(containsDuplicate(nums)) -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/groupAnagrams.py: -------------------------------------------------------------------------------- 1 | # Input: strs = ["eat","tea","tan","ate","nat","bat"] 2 | # Output: [["bat"],["nat","tan"],["ate","eat","tea"]] 3 | 4 | 5 | from typing import List 6 | import collections 7 | 8 | 9 | class Solution: 10 | def groupAnagrams(self, strs: List[str]) -> List[List[str]]: 11 | ans = collections.defaultdict(list) 12 | 13 | for s in strs: 14 | count = [0] * 26 15 | for c in s: 16 | count[ord(c) - ord("a")] += 1 17 | ans[tuple(count)].append(s) 18 | return ans.values() 19 | 20 | 21 | def groupAnagrams(strs: List[str]) -> List[List[str]]: 22 | ans = collections.defaultdict(list) 23 | 24 | for s in strs: 25 | # creating a list of 26 zeros 26 | count = [0] * 26 27 | for c in s: 28 | # counting the number of occurrences of each letter in a string, 29 | # using the ASCII value of the letters to determine their index in the count list 30 | count[ord(c) - ord("a")] += 1 31 | # this line is grouping the strings by their character counts. 32 | # All the anagrams have the same counts and hence end up in the 33 | # same list in the dictionary 34 | ans[tuple(count)].append(s) 35 | return list(ans.values()) 36 | 37 | 38 | print( 39 | groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]) 40 | ) # -> dict_values([['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]) 41 | 42 | 43 | # NOTE more detail: 44 | # ord(c): This is a built-in function in Python that returns an 45 | # integer representing the Unicode character. 46 | # 47 | # For example, ord('a') will return 97 48 | -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/twoSum.py: -------------------------------------------------------------------------------- 1 | # Given an array of integers nums and an integer target, 2 | # return indices of the two numbers such that they add up to target. 3 | 4 | # You may assume that each input would have exactly one solution, 5 | # and you may not use the same element twice. 6 | 7 | # You can return the answer in any order. 8 | 9 | class Solution(object): 10 | def twoSum(self, nums, target): 11 | """ 12 | :type nums: List[int] 13 | :type target: int 14 | :rtype: List[int] 15 | """ 16 | dict = {} 17 | for i in range(len(nums)): 18 | el = nums[i] 19 | comp = target - el 20 | if comp in dict: 21 | return dict[comp], i 22 | else: 23 | dict[el] = i 24 | return 25 | 26 | nums = [-3,4,3,90] 27 | solution = Solution() 28 | print(solution.twoSum(nums, 0)) -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/validAnagram.py: -------------------------------------------------------------------------------- 1 | # Given two strings s and t, return true if t is an anagram of s, and false otherwise. 2 | 3 | 4 | def isAnagram(s: str, t: str) -> bool: 5 | if len(s) != len(t): 6 | return False 7 | 8 | countS, countT = {}, {} 9 | 10 | for i in range(len(s)): 11 | countS[s[i]] = 1 + countS.get(s[i], 0) 12 | countT[t[i]] = 1 + countT.get(t[i], 0) 13 | return countS == countT 14 | 15 | class Solution2(object): 16 | def isAnagram(self, s, t): 17 | """ 18 | :type s: str 19 | :type t: str 20 | :rtype: bool 21 | """ 22 | if len(s) != len(t): 23 | return False 24 | return sorted(s) == sorted(t) 25 | 26 | s = "accc" 27 | t = "aacc" 28 | 29 | print(isAnagram(s,t)) -------------------------------------------------------------------------------- /ds_algos/backTracking copy/nQueens.py: -------------------------------------------------------------------------------- 1 | # N-queens 2 | 3 | # we are given n queens and n differnet queens, such that no two queens never attack each other 4 | 5 | # example 6 | # [[0,1,0,0], 7 | # [0,0,0,1], 8 | # [1,0,0,0], 9 | # [0,0,1,0]] 10 | 11 | # every queen has to be in a different row and column 12 | # (the hard part is diagonals) Each queen can only be in 13 | # different diagonals 14 | 15 | def nQueens(n): 16 | col = set() 17 | posDiag = set() # (r + c) 18 | negDiag = set() # (r - c) 19 | 20 | # list of solutions 21 | res = [] 22 | # Board that we are traversing 23 | board = [["."] * n for i in range(n)] 24 | 25 | # backtracking function 26 | def backTrack(r): 27 | # we've found a solution 28 | if r == n: 29 | copy = ["".join(row) for row in board] 30 | res.append(copy) 31 | return 32 | 33 | # Backtrack baby! 34 | for c in range(n): 35 | # check for error conditions 36 | if c in col or (r + c) in posDiag or (r - c) in negDiag: 37 | continue 38 | # if passed error conditions 39 | # add the next set of error conditions for next back track 40 | col.add(c) 41 | posDiag.add(r + c) 42 | negDiag.add(r - c) 43 | board[r][c] = "Q" 44 | 45 | # recursive case 46 | backTrack(r + 1) 47 | 48 | # remove the last error conditions (and queen) 49 | col.remove(c) 50 | posDiag.remove(r + c) 51 | negDiag.remove(r - c) 52 | board[r][c] = "." 53 | 54 | # start backtracking 55 | backTrack(0) 56 | return res 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking copy/wordSearch.py: -------------------------------------------------------------------------------- 1 | # Given an NxN board of letters and a string 2 | # return true or false if the word can be 3 | # constructed by only moving horizontally or 4 | # vertically within the board 5 | 6 | board = [ 7 | ["a", "b", "c", "d"], 8 | ["e", "f", "h", "i"], 9 | ["j", "k", "l", "m"], 10 | ["n", "o", "p", "q"], 11 | ["r", "s", "t", "u"], 12 | ] 13 | 14 | 15 | def wordSearch(board, word): 16 | rows, cols = len(board), len(board[0]) 17 | # this will hold onto the previously visited node 18 | path = set() 19 | 20 | # // backtracking for depth first search 21 | def dfs(r, c, i): 22 | # base case 23 | if i == len(word): 24 | return True 25 | # boundry of false conditions 26 | if ( 27 | r < 0 28 | or r >= rows 29 | or c < 0 30 | or c >= cols 31 | or board[r][c] != word[i] 32 | or (r, c) in path 33 | ): 34 | return False 35 | 36 | path.add((r, c)) 37 | res = ( 38 | dfs(r + 1, c, i + 1) 39 | or dfs(r - 1, c, i + 1) 40 | or dfs(r, c + 1, i + 1) 41 | or dfs(r, c - 1, i + 1) 42 | ) 43 | 44 | path.remove((r, c)) 45 | return res 46 | 47 | for i in range(rows): 48 | for j in range(cols): 49 | if dfs(i, j, 0): 50 | return True 51 | 52 | return False 53 | 54 | # O(n * m * 4^n) 55 | 56 | print(wordSearch(board, "abc")) 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking/nQueens.py: -------------------------------------------------------------------------------- 1 | # N-queens 2 | 3 | # we are given n queens and n differnet queens, such that no two queens never attack each other 4 | 5 | # example 6 | # [[0,1,0,0], 7 | # [0,0,0,1], 8 | # [1,0,0,0], 9 | # [0,0,1,0]] 10 | 11 | # every queen has to be in a different row and column 12 | # (the hard part is diagonals) Each queen can only be in 13 | # different diagonals 14 | 15 | def nQueens(n): 16 | col = set() 17 | posDiag = set() # (r + c) 18 | negDiag = set() # (r - c) 19 | 20 | # list of solutions 21 | res = [] 22 | # Board that we are traversing 23 | board = [["."] * n for i in range(n)] 24 | 25 | # backtracking function 26 | def backTrack(r): 27 | # we've found a solution 28 | if r == n: 29 | copy = ["".join(row) for row in board] 30 | res.append(copy) 31 | return 32 | 33 | # Backtrack baby! 34 | for c in range(n): 35 | # check for error conditions 36 | if c in col or (r + c) in posDiag or (r - c) in negDiag: 37 | continue 38 | # if passed error conditions 39 | # add the next set of error conditions for next back track 40 | col.add(c) 41 | posDiag.add(r + c) 42 | negDiag.add(r - c) 43 | board[r][c] = "Q" 44 | 45 | # recursive case 46 | backTrack(r + 1) 47 | 48 | # remove the last error conditions (and queen) 49 | col.remove(c) 50 | posDiag.remove(r + c) 51 | negDiag.remove(r - c) 52 | board[r][c] = "." 53 | 54 | # start backtracking 55 | backTrack(0) 56 | return res 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking/wordSearch.py: -------------------------------------------------------------------------------- 1 | # Given an NxN board of letters and a string 2 | # return true or false if the word can be 3 | # constructed by only moving horizontally or 4 | # vertically within the board 5 | 6 | board = [ 7 | ["a", "b", "c", "d"], 8 | ["e", "f", "h", "i"], 9 | ["j", "k", "l", "m"], 10 | ["n", "o", "p", "q"], 11 | ["r", "s", "t", "u"], 12 | ] 13 | 14 | 15 | def wordSearch(board, word): 16 | rows, cols = len(board), len(board[0]) 17 | # this will hold onto the previously visited node 18 | path = set() 19 | 20 | # // backtracking for depth first search 21 | def dfs(r, c, i): 22 | # base case 23 | if i == len(word): 24 | return True 25 | # boundry of false conditions 26 | if ( 27 | r < 0 28 | or r >= rows 29 | or c < 0 30 | or c >= cols 31 | or board[r][c] != word[i] 32 | or (r, c) in path 33 | ): 34 | return False 35 | 36 | path.add((r, c)) 37 | res = ( 38 | dfs(r + 1, c, i + 1) 39 | or dfs(r - 1, c, i + 1) 40 | or dfs(r, c + 1, i + 1) 41 | or dfs(r, c - 1, i + 1) 42 | ) 43 | 44 | path.remove((r, c)) 45 | return res 46 | 47 | for i in range(rows): 48 | for j in range(cols): 49 | if dfs(i, j, 0): 50 | return True 51 | 52 | return False 53 | 54 | # O(n * m * 4^n) 55 | 56 | print(wordSearch(board, "abc")) 57 | -------------------------------------------------------------------------------- /ds_algos/fastAndSlow.py: -------------------------------------------------------------------------------- 1 | # Q: find the middle of a linkedList 2 | 3 | # fast point is shifted by 2 (always?) 4 | # slow point is incremented by 1 (always?) 5 | 6 | def middleOfList(head): 7 | slow, fast = head, head 8 | while fast and fast.next: 9 | slow = slow.next 10 | fast = fast.next.next 11 | return slow 12 | 13 | # O(n) space complexity 14 | # fn hasCycle(head): 15 | # visited = set() 16 | # while head is not null: 17 | # if head in visited: 18 | # return true 19 | # head = head.next 20 | # return false 21 | 22 | # O(1) space complexity 23 | # what if the LL has a cycle in it? 24 | def cycleDetection(head): 25 | slow, fast = head, head 26 | while fast and fast.next: 27 | slow = slow.next 28 | fast = fast.next.next 29 | if slow == fast: 30 | return True 31 | return False 32 | 33 | 34 | # Where does the cycle start? 35 | def cycleStart(head): 36 | slow, fast = head, head 37 | while fast and fast.next: 38 | slow = slow.next 39 | fast = fast.next.next 40 | 41 | if slow == fast: 42 | break 43 | 44 | if not fast or not fast.next: 45 | return None 46 | 47 | slow2 = head 48 | while slow != slow2: 49 | slow = slow.next 50 | slow2 = slow2.next 51 | 52 | return slow 53 | 54 | # Mathematical Proof of Floyd's Tortoise and Hare 55 | 56 | # 1. Let the distance between the head node and the node at which the cycle starts be denoted by P 57 | 58 | # 2. Let the length of the cycle be denoted by C 59 | 60 | # 3. Let the distance from the node at which slow and fast 61 | # intersect to the node at which the cycle begins, be denoted by X 62 | 63 | # Using this information, we can derive that the distance between the head node and the node at which fast and slow intersect is C − X 64 | 65 | # We know that 2∗slow = fast. Using the information above, let's rewrite this equation in terms of the 66 | # C,X,P, we get the following. -------------------------------------------------------------------------------- /ds_algos/graphs/graphGraphs/graphIntro.py: -------------------------------------------------------------------------------- 1 | # 1 Matrix 2 | # 2 Adjacency Matrix 3 | # 3 Adjacent List 4 | # 5 | # NOTE: 6 | # Vertices are the same as nodes 7 | # Pointers are Edges 8 | 9 | # Graphs can, and often do, have cycles! 10 | # Edges <= (Vertices)^2 11 | 12 | # Directed Graph -> Each pointer has a direction (BST and singlely-LL are directed graphs) 13 | 14 | # Undirected Graphs are essentially doubly-LL 15 | 16 | # Matrix (undirected graph) 17 | 18 | treasureMap = [[0, 0, 0, 0], 19 | [1, 1, 'X', 0], 20 | [1, 0, 0, 1], 21 | [0, 0, 1, 0]] 22 | 23 | teasure = treasureMap[1][2] # row 1 and column 2 24 | 25 | # Adjecency matrix 26 | grid = [[0, 0, 0, 0], 27 | [1, 1, 0, 0], 28 | [1, 0, 0, 1], 29 | [0, 0, 1, 0]] 30 | 31 | 32 | def dfs(grid, r, c, visit = set()): 33 | ROWS, COLS = len(grid), len(grid[0]) 34 | if (min(r,c) < 0 or 35 | r == ROWS or c == COLS or 36 | (r, c) in visit or grid[r][c] == 1): 37 | return 0 38 | if r == ROWS - 1 or c == COLS - 1: 39 | return 1 40 | 41 | count = 0 42 | visit.add((r, c)) 43 | count += dfs(grid, r + 1, c, visit) 44 | count += dfs(grid, r - 1, c, visit) 45 | count += dfs(grid, r, c + 1, visit) 46 | count += dfs(grid, r, c - 1, visit) 47 | 48 | visit.remove((r, c)) 49 | return count 50 | 51 | print(dfs(grid, 0, 0, set())) -------------------------------------------------------------------------------- /ds_algos/graphs/tree/trie.py: -------------------------------------------------------------------------------- 1 | # This is for finding prefix tree. This helps with auto complete 2 | 3 | # It is a node of characters ( a - z ) and every node 4 | 5 | class TrieNode: 6 | def __init__(self): 7 | self.children = {} 8 | self.word = False # Mark the end of a work (this indicate it's not the end) 9 | 10 | class Trie: 11 | def __init__(self): 12 | self.root = TrieNode() 13 | 14 | 15 | def insert(self, word): 16 | curr = self.root 17 | # Go through every character in 'word' 18 | for c in word: 19 | # If the letter is not a child of the current character 20 | if c not in curr.children: 21 | # Insert a new node 22 | curr.children[c] = TrieNode() 23 | curr = curr.children[c] 24 | curr.word = True # Mark the end of a work (this indicate it is the end) 25 | 26 | def search(self, word): 27 | curr = self.root 28 | for c in word: 29 | if c not in curr.children: 30 | return False 31 | curr = curr.children[c] 32 | return curr.word 33 | 34 | # Main use case of this data structure 35 | def startsWith(self, prefix): 36 | curr = self.root 37 | for c in prefix: 38 | if c not in curr.children: 39 | return False 40 | curr = curr.children[c] 41 | return True -------------------------------------------------------------------------------- /ds_algos/prefixSum/prefixSum.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Prefix Sum -> Starting at the beginning.... ? 5 | 6 | # nums = [2, -1, 3, -3, 4] ( any prefex is [2], [2, -1], [2, -1, 3],...) 7 | # a post fix if the same but from the end 8 | 9 | def prefixSum(nums): 10 | preSum = 0 11 | 12 | for el in nums: 13 | preSum += el 14 | return preSum 15 | 16 | def postFix(nums): 17 | postSum = 0 18 | 19 | for el in reversed(nums): 20 | postSum += el 21 | return postSum 22 | 23 | # Q Given an array of values, design a data structure that can query the sum 24 | # of a subarray of the values 25 | 26 | class PrefixSum: 27 | 28 | def __init__(self, nums): 29 | self.prefix = [] #an array of totals prefixes 30 | total = 0 31 | for n in nums: 32 | total += n 33 | self.prefix.append(total) 34 | 35 | def rangeSum(self, left, right): #Assuming range sum is called much more frequently 36 | preRight = self.prefix[right] 37 | preLeft = self.prefix[left - 1] if left > 0 else 0 # Edge case for L = 0 38 | return (preRight - preLeft) 39 | 40 | # This allows you to add to the PrefixSum class in O(1) time complexity 41 | def addElement(self, element): 42 | newLastElement = element + self.prefix[-1] 43 | self.prefix.append(newLastElement) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ds_algos/savingaFile.js: -------------------------------------------------------------------------------- 1 | const twoSumClosest = (nums, target) => { 2 | // O(nlogn) 3 | const sorted = nums.sort((a, b) => a - b) 4 | // initialize the two pointers 5 | 6 | let l = 0; 7 | let r = sorted.length - 1; 8 | let min = Infinity; 9 | 10 | // while left pointer is less than right pointer (l and r meet in the middle) 11 | while (l <= r) { 12 | // initialize a sum to left and right elements 13 | const sum = sorted[l] + sorted[r]; 14 | // initialize a measure of the distance between our sum and target 15 | // NOTE - the sign is super important for how we move our pointers 16 | const distance = target - sum 17 | // the return condition 18 | if (Math.abs(distance) < min && Math.abs(distance) >= 0) { // <-- Is distance between 0 and min? 19 | // If it is, reassign min and closestSum 20 | min = Math.abs(distance) 21 | closestSum = sum 22 | // Additionally, if the min is 0, return closestSum immediately 23 | if (min === 0) return closestSum; 24 | } 25 | // If sum is less that target, increase left 26 | if (distance > 0) { 27 | l++; 28 | // else decrease right! 29 | } else { 30 | r--; 31 | } 32 | } 33 | return closestSum 34 | }; 35 | 36 | // console.log(twoSumClosest([2,-2,1], 4)) 37 | // console.log(twoSumClosest([2, -3, -6, 7, 4], 3)) 38 | console.log(twoSumClosest([3, 1, 4, 3], 6)) 39 | 40 | module.exports = {twoSumClosest}; -------------------------------------------------------------------------------- /ds_algos/stacks/kFrequentEl.py: -------------------------------------------------------------------------------- 1 | # Given an integer array nums and an integer k, return the k most frequent elements. 2 | # You may return the answer in any order. 3 | 4 | # Input: nums = [1,1,1,2,2,3], k = 2 5 | # Output: [1,2] 6 | 7 | def topKFrequent(nums, k): 8 | """ 9 | :type nums: List[int] 10 | :type k: int 11 | :rtype: List[int] 12 | """ 13 | dict = {} 14 | for el in nums: 15 | if el in dict: 16 | dict[el] += 1 17 | if el not in dict: 18 | dict[el] = 1 19 | 20 | resultArr = sorted(dict, key=dict.get, reverse=True) 21 | return resultArr[0:k] 22 | 23 | print(topKFrequent([1,1,1,2,2,3,3,3,3,3], 2)) 24 | 25 | 26 | # Almost done, but just having trouble with syntax -------------------------------------------------------------------------------- /ds_algos/stacks/validParens.py: -------------------------------------------------------------------------------- 1 | # Write a function that takes in a string and returns a 'True' 2 | # if the parentheses are balances or 'False' if they are not 3 | 4 | # Input: s = "()[]{}" 5 | # Output: True 6 | 7 | 8 | def validParens(str): 9 | dict = {"[": "]", "{": "}", "(": ")"} 10 | stack = [] 11 | 12 | for char in str: 13 | if char in dict: 14 | stack.append(char) 15 | elif stack and char == dict[stack[-1]]: 16 | stack.pop() 17 | else: 18 | return False 19 | 20 | return len(stack) == 0 21 | 22 | 23 | print(validParens("[{[()]}]()")) 24 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/kadanes_algo.py: -------------------------------------------------------------------------------- 1 | #Find a non-empty subarray with the largest sum 2 | 3 | #Kadane's Algorith is O(n) 4 | 5 | #There is a sliding window that is non obvious 6 | 7 | 8 | # def kadanes(nums): 9 | # maxSum = nums[0] 10 | # curSum = 0 11 | 12 | # for n in nums: 13 | # # Ensuring that our current sum is never negative 14 | # curSum = max(curSum, 0) 15 | # curSum += n 16 | # maxSum = max(maxSum, curSum) 17 | # return maxSum 18 | 19 | def kadanes(nums): 20 | maxSum = nums[0] 21 | curSum = 0 22 | 23 | for n in nums: 24 | curSum = max(curSum, 0) + n 25 | maxSum = max(maxSum, curSum) 26 | 27 | return maxSum 28 | 29 | #How do you return the actual subarray? 30 | # You need to keep track of the indexes of the subarray 31 | 32 | 33 | def slidingWindow(nums): 34 | maxSum = nums[0] 35 | curSum = 0 36 | 37 | # Set the indexes 38 | maxL, maxR = 0, 0 39 | L = 0 40 | 41 | # R will change and L will be reassigned 42 | for R in range(len(nums)): 43 | # The first line of the kadanes for loop 44 | # We've found a window that sums to a negative number 45 | if curSum < 0: 46 | curSum = 0 47 | L = R 48 | 49 | # The second line of kadanes for loops 50 | curSum += nums[R] 51 | if curSum > maxSum: 52 | maxSum = curSum 53 | maxL, maxR = L , R 54 | 55 | # Return the subArray defined by maxL and maxR 56 | return nums[maxL:maxR] 57 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/slidingWindow.py: -------------------------------------------------------------------------------- 1 | # Given an array, return true if there 2 | # are two elements within a window of size k that are equal 3 | 4 | def closeDuplicates(nums, k): 5 | # Initialize a HastSet and L pointer 6 | window = set() 7 | L = 0 8 | 9 | # Iterate through the array 10 | for R in range(len(nums)): 11 | # If the two points extend past the window 12 | if R - L + 1 > k: 13 | # Remove the left element and resize the window 14 | window.remove(nums[L]) 15 | L += 1 16 | # If there is an element inside the HashSet 17 | if nums[R] in window: 18 | return True 19 | # Else add the element to the hashSet 20 | window.add(nums[R]) 21 | 22 | # Once we get the end of the array, w/o returning True... 23 | return False -------------------------------------------------------------------------------- /ds_algos/twoPointer/targetSum.py: -------------------------------------------------------------------------------- 1 | # Q: Given a sorted input array, return the two indices of two elements which 2 | # sums up to the target value. Assume there's exactly one solution. 3 | 4 | def targetSum(nums, target): 5 | L, curSum = 0, 0 6 | R = len(nums) - 1 7 | 8 | while R > L: 9 | curSum = nums[R] + nums[L] 10 | if curSum > target: 11 | R -= 1 12 | elif curSum < target: 13 | L += 1 14 | elif curSum == target: 15 | return [L, R] 16 | return -1 # Not needed since there is always a solution, but generalizes the code 17 | 18 | nums = [-1,2,4,6,9,10,12] 19 | target = 1 20 | 21 | print(targetSum(nums, target)) -------------------------------------------------------------------------------- /ds_algos/twoPointer/validPalindrome.py: -------------------------------------------------------------------------------- 1 | # Write a function that takes in 2 | # a string and returns a boolean; 3 | # 'True" if the string is a valid palindrome 4 | # and 'False' if it is not 5 | 6 | 7 | def validPalindrom(str): 8 | l, r = 0, len(str) - 1 9 | 10 | while l <= r: 11 | if str[l] != str[r]: 12 | return False 13 | else: 14 | l += 1 15 | r -= 1 16 | 17 | return True 18 | 19 | 20 | print(validPalindrom("racecar")) # -> True 21 | print(validPalindrom("notTrue")) # -> False 22 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/varyingSlidingWindow.py: -------------------------------------------------------------------------------- 1 | # Q: Find the length of the longest subarray, 2 | # with the same value in each position 3 | 4 | def longestSubarray(nums): 5 | length = 0 6 | L = 0 7 | 8 | for R in range(len(nums)): 9 | if nums[L] != nums[R]: 10 | L = R 11 | length = max(length, R - L + 1) 12 | return length 13 | 14 | # How do you write the array above without L and R pointers 15 | 16 | # Q: Find the length subarray, where the sum is greater that or equal to the target. 17 | # Assume all the values are positive (Important note/ hint!!) 18 | 19 | # O(n) time complexity and O(1) space complexity 20 | 21 | def shortestSubarry(nums, target): 22 | L, total = 0, 0 23 | length = float('inf') 24 | 25 | # Move R pointer right 26 | for R in range(len(nums)): # EXPAND THE WINDOW 27 | # wioth every step, add the elemenet to the total 28 | total += nums[R] 29 | # IF the total is greater than OR equal to the target 30 | while total >= target: # SHRINK THE WINDOW 31 | # possibly re-assign the length 32 | length = min(R - L + 1, length) 33 | # decrement the total by L pointer elements 34 | # until the total < target 35 | total -+ nums[L] 36 | L += 1 37 | # return o if length i infinite else return length 38 | return 0 if length == float('inf') else length 39 | -------------------------------------------------------------------------------- /fft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # fft.py - Demonstrate power spectrum from discrete fft 5 | # 6 | # 25Jul22 William Murphy 7 | # 8 | 9 | FTIME = 1 # function range in seconds 10 | FS = 920 # samples per second 11 | npts = FTIME*FS # number of sample points 12 | 13 | import numpy as np 14 | import matplotlib.pyplot as plt 15 | 16 | #solar cell data into numpy array 17 | sc_data = np.loadtxt('fft_data.txt') 18 | 19 | #print(sc_data) 20 | 21 | #plots the raw data 22 | t = np.linspace(0, FTIME, npts) 23 | y_raw = sc_data 24 | y_fft = sc_data - np.mean(sc_data) 25 | f1, ax1 = plt.subplots() 26 | ax1.plot(t,y_raw) 27 | ax1.set_title('Data Acquisition of Solar Cell') 28 | ax1.set_xlabel('Sec') 29 | ax1.set_ylabel('Voltage') 30 | f1.show() 31 | 32 | #Computng the FFT 33 | ft = np.fft.fft(y_fft, n=16*npts) 34 | ftnorm = abs(ft) 35 | fs = ftnorm**2 36 | ps = np.fft.fftshift(fs) 37 | x_vals = np.fft.fftfreq(len(ps), 1.0/FS) 38 | xvals = np.fft.fftshift(x_vals) 39 | 40 | f2, ax2 = plt.subplots() 41 | ax2.plot(xvals,ps) 42 | ax2.set_xlim(0,200) 43 | ax2.title.set_text('FFT of Raw Data') 44 | ax2.set_xlabel('Frequency') 45 | ax2.set_ylabel('Amplitude') 46 | f2.show() 47 | 48 | input('\nPress