├── README.md
├── W1_L1_gcd1.py
├── W1_L2_gcd2.py
├── W1_L2_gcd_euclid.png
├── W1_L2_gcd_euclid.py
├── W1_L3_gcd_best.png
├── W1_L3_gcd_best.py
├── W1_quiz.py
├── W2_L1_basics.py
├── W2_L2_strings.py
├── W2_L3_lists.py
├── W2_L4_controlflow.py
├── W2_L5_functions.py
├── W2_L6_examples.py
├── W2_programming_assignment.py
├── W2_quiz.py
├── W3_L1_range.py
├── W3_L2_manipulating_lists.py
├── W3_L3_break_out_of_loop.py
├── W3_L4_Array.png
├── W3_L4_Lists.png
├── W3_L4_Operations.png
├── W3_L4_arrays_lists_binarysearch.py
├── W3_L5_efficiency.py
├── W3_L6_selection_sort.py
├── W3_L7_insertion_bubble_sort.py
├── W3_L8_recursion.py
├── W3_programming_assignment.py
├── W4_L1_merge_sort.py
├── W4_L3_quick_sort.py
├── W4_L5_tuples_dictionaries.py
├── W4_L6_function_definitions.py
├── W4_L7_list_comprehension.py
├── W4_programming_assignment.py
├── W4_quiz.py
├── W5_L1_exception_handling.py
├── W5_L2_standard_input_output.py
├── W5_L3_file1.txt
├── W5_L3_handling_files.py
├── W5_L4_string_functions.py
├── W5_L5_formatting_printed_output.py
├── W5_L6_pass_del_None.py
├── W5_programming_assignment.py
├── W6_L1_PythonCode.py
├── W6_L2_globalscope_nestedfunctions.py
├── W6_L3_generating_permutations.py
├── W6_L4_sets_stacks_queues.py
├── W6_L5_priority_queues_heaps.py
├── W6_quiz.py
├── W7_L1_abstractDatatypes_classes_objects.py
├── W7_L2_classes_objects_in_Python.py
├── W7_L3_PythonCode.py
├── W7_L3_user_defined_lists.py
├── W7_L4_PythonCode.py
├── W7_L4_binary_search_trees.py
├── W7_quiz.py
├── W8_L1_memoization_dynamic_programming.py
├── W8_L4_matrix_multiplication.py
├── W8_L5_Wrap_up.py
└── W8_programming_assignment.py
/README.md:
--------------------------------------------------------------------------------
1 |
The learning path on DSA using Python in my NPTEL course
2 |
--------------------------------------------------------------------------------
/W1_L1_gcd1.py:
--------------------------------------------------------------------------------
1 | def gcd(m, n):
2 | m_lst = []
3 | for i in range(1, m+1):
4 | if m % i == 0:
5 | m_lst.append(i)
6 |
7 | n_lst = []
8 | for i in range(1, n+1):
9 | if n % i == 0:
10 | n_lst.append(i)
11 |
12 | common_lst = []
13 | for i in m_lst:
14 | if i in n_lst:
15 | common_lst.append(i)
16 |
17 | return common_lst[-1]
18 |
19 | print(gcd(15, 20))
--------------------------------------------------------------------------------
/W1_L2_gcd2.py:
--------------------------------------------------------------------------------
1 | def gcd(m, n):
2 | for i in range(min(m, n), 0, -1):
3 | if m % i == 0 and n % i == 0:
4 | return i
5 |
6 |
7 |
8 | print(gcd(150, 75))
9 |
--------------------------------------------------------------------------------
/W1_L2_gcd_euclid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joswinemmanuel/NPTEL-DSA-Python/69a467d94f32c49c1206c19f40d1842e7b5e7235/W1_L2_gcd_euclid.png
--------------------------------------------------------------------------------
/W1_L2_gcd_euclid.py:
--------------------------------------------------------------------------------
1 | def gcd(m, n):
2 | if m < n:
3 | m, n = n, m
4 |
5 | if m % n == 0:
6 | return n
7 | else:
8 | diff = m - n
9 | return gcd(max(n, diff), min(n, diff))
10 |
11 | print(gcd(75, 30))
--------------------------------------------------------------------------------
/W1_L3_gcd_best.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joswinemmanuel/NPTEL-DSA-Python/69a467d94f32c49c1206c19f40d1842e7b5e7235/W1_L3_gcd_best.png
--------------------------------------------------------------------------------
/W1_L3_gcd_best.py:
--------------------------------------------------------------------------------
1 | def gcd(m, n):
2 |
3 | if n == 0:
4 | return m
5 | return gcd(n, m % n)
6 |
7 | # if m < n:
8 | # m, n = n, m
9 |
10 | # if m % n == 0:
11 | # return n
12 | # else:
13 | # return gcd(n, m % n) # m % n < n always
14 |
15 | print(gcd(30, 75))
--------------------------------------------------------------------------------
/W1_quiz.py:
--------------------------------------------------------------------------------
1 | # def h(x):
2 | # (d,n) = (1,0)
3 | # while d <= x:
4 | # (d,n) = (d*3,n+1)
5 | # return(n)
6 |
7 | # print(h(27993))
8 |
9 |
10 | # def g(n):
11 | # s=0
12 | # for i in range(2,n):
13 | # if n%i == 0:
14 | # s = s+1
15 | # return(s)
16 |
17 | # print(g(60) - g(48))
18 |
19 |
20 | # def f(n):
21 | # s=0
22 | # for i in range(1,n+1):
23 | # if n//i == i and n%i == 0:
24 | # s = 1
25 | # return(s%2 == 1)
26 |
27 | # for i in range(1, 50):
28 | # print(i, f(i))
29 |
30 |
31 |
32 | # def foo(m):
33 | # if m == 0:
34 | # return(0)
35 | # else:
36 | # return(m+foo(m-1))
37 |
38 | # for i in range(0, 6):
39 | # print(i, foo(i), int(i*(i+1)/2))
--------------------------------------------------------------------------------
/W2_L1_basics.py:
--------------------------------------------------------------------------------
1 | """ float the sentence break up into MANTISSA and EXPONENT """
2 | # 1.2345 = 12345 x 10**-4
3 | # (mantissa) (exponent)
4 | # 0.602 X 10**24
5 | #(mantissa) (exponent)
6 |
7 | def divides(m, n):
8 | return True if m % n == 0 else False
9 |
10 | def even(m):
11 | return divides(m, 2)
12 |
13 | def odd(m):
14 | return not even(m)
15 |
16 | print(divides(10, 5))
17 | print(even(8))
18 | print(odd(8))
19 | print(odd(5))
20 |
--------------------------------------------------------------------------------
/W2_L2_strings.py:
--------------------------------------------------------------------------------
1 | city = 'Kerala\'s' # single quotes can be used
2 | title = "\"Joswin the great\"" # double quotes can be used
3 | paragraph = '''What's "going on"
4 | Why's "this" different''' # triple quotes can be used
5 | print(city)
6 | print(title)
7 | print(paragraph)
8 |
9 | s1 = "Joswin"
10 | s2 = " Emmanuel"
11 |
12 | print(s1[1:5]) # string slicing
13 |
14 | print(s1[::-1]) # string reversing
15 |
16 | print(s1 + s2) # concatenation
17 |
18 | print(len(s1)) # getting length of the string
--------------------------------------------------------------------------------
/W2_L3_lists.py:
--------------------------------------------------------------------------------
1 | names = ["joswin", "agath", "merin"]
2 | age = [19, 23, 53]
3 | mixed = ["joswin", 19, "agath", 23]
4 |
5 | lst = [1, 2, 3, 4, 5]
6 |
7 | print(lst[1:3]) # list slicing
8 |
9 | print(lst[::-1]) # returns the reverse of the list using slicing
10 |
11 | print(len(lst)) # returns the lenght of the list
12 |
13 | ''' lst[0] not equal to lst[0:1] '''
14 | ''' lst[0] gives 1 lst[0:1] gives [1] '''
15 |
16 | lst[0] = 10 # lists are mutable
17 | print(lst[0])
18 |
19 | a = 10
20 | b = a
21 | a = 99
22 | print("a = ", a, "b = ", b)
23 | """ Value of b will still be 10 -- this is the case for immutalble datatypes only
24 | like int, float, str etc -- a fresh copy is made while assigining"""
25 | a = [1, 2, 3]
26 | b = a # shallow copy
27 | a[1] = 100
28 | b[2] = 99
29 | print("a = ", a, "b = ", b)
30 | """ for mutable datatypes like list when value in list is changed it change for both"""
31 | """ so we make a copy in b using .copy() funciton"""
32 | a = [1, 2, 3]
33 | b = a.copy() # deep copy
34 | c = a[:] # or use [::] slicing to make a deep copy
35 | a[1] = 100
36 | b[2] = 99
37 | print("a = ", a, "b = ", b, "c = ", c)
38 |
39 | l1 = [1, 2, 3]
40 | l2 = [1, 2, 3]
41 | l3 = l2
42 | print(l1 == l2) # == checks if l1 and l2 have same value
43 | print(l2 == l3)
44 | print(l1 is l2) # is checks if l1 and l2 refers to same object
45 | print(l2 is l3)
46 |
47 | print(l1 + l2) # concatenation of lists using
--------------------------------------------------------------------------------
/W2_L4_controlflow.py:
--------------------------------------------------------------------------------
1 | ''' 0 (zero), "", '' (empty string), [], {}, () are treated as False '''
2 |
3 | """ conditional execution
4 | repeated execution
5 | function execution """
6 | # all basic knowledge on control flow
7 |
8 | # to print all the factors of an inputted number
9 |
10 | number = int(input("Enter the number : "))
11 | for i in range(1, number+1):
12 | if number % i == 0:
13 | print(i, end=" ")
--------------------------------------------------------------------------------
/W2_L5_functions.py:
--------------------------------------------------------------------------------
1 | """ A function calling itself is RECUSION """
2 |
3 | def factorial(n):
4 | if n <= 1:
5 | return 1
6 | return n * factorial(n-1)
7 |
8 | print(factorial(5))
9 |
10 | def fibonacci_n(n):
11 | if n<=1:
12 | return n
13 | return fibonacci_n(n-1) + fibonacci_n(n-2)
14 |
15 | for i in range(0, 10):
16 | print(fibonacci_n(i), end=" ")
--------------------------------------------------------------------------------
/W2_L6_examples.py:
--------------------------------------------------------------------------------
1 | def is_prime(n):
2 | if n <= 1:
3 | return False
4 | for i in range(2, int(n**(1/2))+1):
5 | if n % i == 0:
6 | return False
7 | return True
8 |
9 | def primes_upto(n):
10 | for i in range(0, n):
11 | if is_prime(i):
12 | print(i, end=" ")
13 | print()
14 |
15 | def n_primes(n):
16 | i = 1
17 | while n != 0:
18 | i += 1
19 | if is_prime(i):
20 | print(i, end=" ")
21 | n -= 1
22 |
23 | primes_upto(10)
24 |
25 | n_primes(9)
--------------------------------------------------------------------------------
/W2_programming_assignment.py:
--------------------------------------------------------------------------------
1 | """ 1) Write a function intreverse(n) that takes as input a positive integer n
2 | and returns the integer obtained by reversing the digits in n.
3 | Here are some examples of how your function should work. """
4 |
5 | def intreverse(n):
6 | return int(str(n)[::-1])
7 |
8 | """ 2) Write a function matched(s) that takes as input a string s and checks if the brackets
9 | "(" and ")" in s are matched: that is, every "(" has a matching ")" after it and every ")"
10 | has a matching "(" before it. Your function should ignore all other symbols that appear in s.
11 | Your function should return True if s has matched brackets and False if it does not.
12 | Here are some examples to show how your function should work """
13 |
14 | def matched(s):
15 | stack = []
16 | for i in s:
17 | if i == "(":
18 | stack.append(i)
19 | elif i == ")":
20 | if len(stack) > 0:
21 | stack.pop()
22 | else:
23 | return False
24 | if len(stack) == 0:
25 | return True
26 | else:
27 | return False
28 |
29 | """ 3) Write a function sumprimes(l) that takes as input a list of integers l
30 | and retuns the sum of all the prime numbers in l.
31 | Here are some examples to show how your function should work. """
32 |
33 | def sumprimes(l):
34 | def if_prime(n):
35 | if n <= 1:
36 | return False
37 | for i in range(2, int(n**(1/2))+1):
38 | if n % i == 0:
39 | return False
40 | return True
41 | sum = 0
42 | for i in l:
43 | if if_prime(i):
44 | sum += i
45 | return sum
46 |
--------------------------------------------------------------------------------
/W2_quiz.py:
--------------------------------------------------------------------------------
1 | # x = [[3,5],"mimsy",2,"borogove",1] # Statement 1
2 | # y = x[0:50] # Statement 2
3 | # z = y # Statement 3
4 | # w = x # Statement 4
5 | # x[1] = x[1][:5] + 'ery' # Statement 5
6 | # y[1] = 4 # Statement 6
7 | # w[1][:3] = 'fea' # Statement 7
8 | # z[4] = 42 # Statement 8
9 | # x[0][0] = 5555 # Statement 9
10 | # a = (x[3][1] == 1)
11 |
12 | # #Error statement 7
13 |
14 | # b = [43,99,65,105,4]
15 | # a = b[2:]
16 | # d = b[1:]
17 | # c = b
18 | # d[1] = 95
19 | # b[2] = 47
20 | # c[3] = 73
21 | # print(b)
22 | # print(a)
23 | # print(d)
24 | # print(c)
25 | # print(f"a[0] == {a[0]}, b[3] == {b[3]}, c[3] == {c[3]}, d[1] == {d[1]}")
26 |
27 | # startmsg = "anaconda"
28 | # endmsg = ""
29 | # for i in range(1,1+len(startmsg)):
30 | # endmsg = endmsg + startmsg[-i]
31 | # print(endmsg)
32 |
33 | # def mystery(l):
34 | # l = l[2:]
35 | # return(l)
36 |
37 | # mylist = [7,11,13,17,19,21]
38 | # mystery(mylist)
39 | # print(mylist)
--------------------------------------------------------------------------------
/W3_L1_range.py:
--------------------------------------------------------------------------------
1 | print(list(range(1, 11)))
2 | # gives [1 ... 10] ( till n-1 )
3 |
4 | print(list(range(1, 11, 2)))
5 | # the third argument is the jump value
6 |
7 | print(list(range(10, 0, -1)))
8 | # count down
9 |
10 | print(range(1, 4) == [1, 2, 3])
11 | # False because range(1, 4) gives a range object while [1, 2, 3] is a list object
12 | print(type(range(1, 4)))
13 | print(type([1, 2, 3]))
14 |
15 | # Type conversion
16 | print(int('10') + 1) # 11
17 | print(str(100) + '1') # 1001
--------------------------------------------------------------------------------
/W3_L2_manipulating_lists.py:
--------------------------------------------------------------------------------
1 | list1 = [1, 2, 3, 4, 5]
2 | list1[1] = 1000
3 | # [1, 1000, 3, 4, 5]
4 | print(list1)
5 |
6 | list2 = list1 # list2 will be list1, shallow copy, any change to list1 changes list2
7 |
8 | list1 = list1[:2] + [999] + list1[3:] # list1 is changed to a new list so list2 remains same as old list1
9 | # list1 = [1, 1000, 999, 4, 5]
10 | print(list1)
11 | # list2 = [1, 1000, 3, 4, 5]
12 | print(list2)
13 |
14 | list1 = [1, 2, 3]
15 | list1 = list2 # shallow copy
16 | list1.append(100) # list1 is manipulated, added a new value,
17 | # not changed into a new list, so list2 also changed
18 | print(list1)
19 | print(list2)
20 | # both will be [1, 2, 3, 100]
21 |
22 | " Shrink and Expand list using slices "
23 | list1 = [1, 2, 3, 4, 5]
24 | list1[2:] = [33, 44, 55, 66]
25 | print(list1) # [1, 2, 33, 44, 55, 66] Expanded using slices
26 | list1[0:2] = [1000]
27 | print(list1) # [1000, 33, 44, 55, 66] Shrinked using slices
28 |
29 | " 'in' is called membership operator "
30 | # used to check if an element is in a list or string
31 | print('IN') if 1 in [1, 2, 3] else print('NOT IN') # IN
32 | print('IN') if 100 in [1, 2, 3] else print('NOT IN') # NOT IN
33 |
34 | " removing all occurance of an element "
35 | lst = [1, 2, 3, 1, 4, 1, 5]
36 | while 1 in lst:
37 | lst.remove(1)
38 | print(lst) # [2, 3, 4, 5]
39 |
--------------------------------------------------------------------------------
/W3_L3_break_out_of_loop.py:
--------------------------------------------------------------------------------
1 | def find_pos(lst, item):
2 | for i in range(len(lst)):
3 | if lst[i] == item:
4 | return i
5 | return -1
6 | " gives the index of item in list, if item not in list gives -1 "
7 |
8 | # break can be used to break out of a loop
9 | for i in range(1, 10):
10 | if i == 6:
11 | break
12 | print(i, end=" ")
13 | # 1 2 3 4 5 when i == 6 it breaks out of the loop
14 | print()
15 |
16 | " In Python there is an 'else' case for the 'for', it executes after all the iteration in the loop "
17 | for i in range(1, 6):
18 | print(i, end=' ')
19 | else:
20 | print("all values printed")
21 | # 1 2 3 4 5 all values printed
22 |
23 | " but if the loop is breaked out using 'break' 'else' case won't be executed "
24 | for i in range(1, 6):
25 | if i == 3:
26 | break
27 | print(i, end=' ')
28 | else:
29 | print("all values printed")
30 | # 1 2 see else case didn't get exectued as loop was breaked
31 |
--------------------------------------------------------------------------------
/W3_L4_Array.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joswinemmanuel/NPTEL-DSA-Python/69a467d94f32c49c1206c19f40d1842e7b5e7235/W3_L4_Array.png
--------------------------------------------------------------------------------
/W3_L4_Lists.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joswinemmanuel/NPTEL-DSA-Python/69a467d94f32c49c1206c19f40d1842e7b5e7235/W3_L4_Lists.png
--------------------------------------------------------------------------------
/W3_L4_Operations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joswinemmanuel/NPTEL-DSA-Python/69a467d94f32c49c1206c19f40d1842e7b5e7235/W3_L4_Operations.png
--------------------------------------------------------------------------------
/W3_L4_arrays_lists_binarysearch.py:
--------------------------------------------------------------------------------
1 | " Linear search : find the index of the value if present in the list "
2 | def linear_search(lst, value):
3 | for i in range(len(lst)):
4 | if lst[i] == value:
5 | return f"Found at index {i}"
6 | return "Value not found"
7 | # it check all the elements in the list to find the index
8 | # worst cases : if element is at last of the list, element not in list
9 | # in these cases it is inefficient, so we need a better algorithm
10 |
11 | " Binary search : is a technique to find the index of an element in a sorted list "
12 | # Iterative Binary Search Function
13 | def binary_search_i(arr, x):
14 | low = 0
15 | high = len(arr) - 1
16 | mid = 0
17 | while low <= high:
18 | mid = (high + low) // 2
19 | # If x is greater, ignore left half
20 | if arr[mid] < x:
21 | low = mid + 1
22 | # If x is smaller, ignore right half
23 | elif arr[mid] > x:
24 | high = mid - 1
25 | # means x is present at mid
26 | else:
27 | return mid
28 | # If we reach here, then the element was not present
29 | return -1
30 |
31 |
32 | # Recursive binary search.
33 | def binary_search(arr, low, high, x):
34 | # Check base case
35 | if high >= low:
36 | mid = (high + low) // 2
37 | # If element is present at the middle itself
38 | if arr[mid] == x:
39 | return mid
40 | # If element is smaller than mid, then it can only
41 | # be present in left subarray
42 | elif arr[mid] > x:
43 | return binary_search(arr, low, mid - 1, x)
44 | # Else the element can only be present in right subarray
45 | else:
46 | return binary_search(arr, mid + 1, high, x)
47 | else:
48 | # Element is not present in the array
49 | return -1
50 |
51 | " Python's built in 'list' are not array "
--------------------------------------------------------------------------------
/W3_L5_efficiency.py:
--------------------------------------------------------------------------------
1 | """ Efficiency : Measure of time taken by an algorithm
2 | as a function T(n) with respect to input size n """
3 |
4 | """ Big O notation
5 | T(n) = O(n)
6 | less time order:
7 | log(n) < n < n*log(n) < n**2 < n**3 < 2**n < n! """
8 |
9 | # Linear search efficiency is : O(n) for any lists
10 | # Binary search efficiency is : O(log(n)) for sorted lists
11 |
12 | " Python can do about 10**7 steps in 1 second"
13 |
14 | " use command : 'time python3 W3_L3_efficiency.py' to get time taken in LINUX"
--------------------------------------------------------------------------------
/W3_L6_selection_sort.py:
--------------------------------------------------------------------------------
1 | """ Selection sort """
2 |
3 | def selection_sort(lst):
4 | n = len(lst)
5 | for i in range(n):
6 | min_index = i
7 |
8 | for j in range(i+1, n):
9 | if lst[j] < lst[min_index]:
10 | min_index = j
11 | lst[i], lst[min_index] = lst[min_index], lst[i]
12 | return lst
13 |
14 | # Time Complexity: O(n**2)
15 | # Auxiliary Space: O(1)
16 |
--------------------------------------------------------------------------------
/W3_L7_insertion_bubble_sort.py:
--------------------------------------------------------------------------------
1 | """ Bubble sort """
2 | def bubble_sort(arr):
3 | n = len(arr)
4 | for i in range(n-1):
5 | for j in range(n-i-1):
6 | if arr[j] > arr[j+1]:
7 | arr[j], arr[j+1] = arr[j+1], arr[j]
8 | return arr
9 | # Time Complexity: O(n**2)
10 | # Auxiliary Space: O(1)
11 |
12 | """ Insertion sort """
13 | def insertion_sort(arr):
14 | for i in range(1, len(arr)):
15 | key = arr[i]
16 | j = i-1
17 | while j >= 0 and key < arr[j]:
18 | arr[j+1] = arr[j]
19 | j -= 1
20 | arr[j+1] = key
21 | return arr
22 | # Time Complexity: O(n**2)
23 | # Auxiliary Space: O(1)
24 |
25 | """ to set recursion limit to 2000 """
26 | import sys
27 | sys.setrecursionlimit(2000)
28 |
29 |
30 | """ Insertion using recursion """
31 | def insertionSortRecursive(arr, n):
32 | # base case
33 | if n <= 1:
34 | return # None
35 |
36 | # Recursively sort first n-1 elements
37 | insertionSortRecursive(arr, n-1)
38 |
39 | # Insert last element at its correct position in sorted array
40 | key = arr[n-1]
41 | j = n-2
42 | while j >= 0 and arr[j] > key:
43 | arr[j+1] = arr[j]
44 | j = j-1
45 | arr[j+1] = key
46 |
47 | # Time Complexity: O(n**2)
48 | # Auxiliary Space: O(n)
49 |
50 | a = [100, 14, 23, 44, 2 ,1]
51 | insertionSortRecursive(a, len(a))
52 | print(a)
53 |
54 | """ Selection sort and Insertion sort are both O(n**2)
55 | O(n**2) sorting is infeasible for n over 5000
56 | Among insertion sort and selection sort, insertion sort is usually better """
--------------------------------------------------------------------------------
/W3_L8_recursion.py:
--------------------------------------------------------------------------------
1 | ''' Many arithmetic functions are naturally defined inductively '''
2 |
3 | # FACTORIAL : n! = n x (n-1) x (n-2)!
4 | # n! = n x (n-1)!
5 | def factorial(n):
6 | if n <= 1:
7 | return 1
8 | return n * factorial(n-1)
9 |
10 | # MULTIPLICATION (repeated addition):
11 | # 2 x 3 = 2 + 2 + 2 or 3 + 3
12 | # m x n = m + (m x (n-1))
13 | def multiplication(m, n):
14 | if n == 1:
15 | return m
16 | return m + multiplication(m, n-1)
17 |
18 | # FIBONACCI SERIES:
19 | # 1 1 2 3 5 8 13 21 34 ...
20 | # fib(1) = fib(2) = 1, fib(3) = fib(1) + fib(2),
21 | # fib(4) = fib(2) + fib(3)
22 | # fib(n) = fib(n-1) + fib(n-2)
23 | def fibonacci(n):
24 | if n <= 1:
25 | return n
26 | return fibonacci(n-1) + fibonacci(n-2)
27 |
28 | """ Inductive definitions naturally give rise to recursive programs """
29 | # like FACTORIAL, MULTIPLICATION, FIBONACCI etc
30 |
31 | # LENGTH OF LIST using recursion
32 | # length(l) = 1 + length(l[1:])
33 | def length_list(arr):
34 | if arr == []:
35 | return 0
36 | return 1 + length_list(arr[1:])
37 |
38 | # SUM OF ELEMENTS IN LIST using recursion
39 | # sum_of(l) = l[0] + sum_of(l[1:])
40 | def sum_of_list(arr):
41 | if arr == []:
42 | return 0
43 | return arr[0] + sum_of_list(arr[1:])
44 |
45 | """ 'RecursionError: maximum recursion depth exceeded in comparison'
46 | recursion limit is there in python so that the program won't
47 | run forever if the base case is incorrect ( like in case of infinite loop ) """
48 | # upto 997 something it's okay but from 998 the above will be alerted (Recursion Error)
49 | # therefore 998 is the default recursion limit in python
50 |
51 | """ We can get over it by setting the recursion Limit """
52 | import sys
53 | sys.setrecursionlimit(1000)
54 |
55 |
--------------------------------------------------------------------------------
/W3_programming_assignment.py:
--------------------------------------------------------------------------------
1 | """ 1) Write a function contracting(l) that takes as input a list of integer l and returns
2 | True if the absolute difference between each adjacent pair of elements strictly decreases.
3 |
4 | Here are some examples of how your function should work.
5 |
6 | >>> contracting([9,2,7,3,1])
7 | True
8 |
9 | >>> contracting([-2,3,7,2,-1])
10 | False
11 |
12 | >>> contracting([10,7,4,1])
13 | False"""
14 |
15 | def contracting(l):
16 | diff= abs(l[1] - l[0])
17 | for i in range(2, len(l)):
18 | if abs(l[i] - l[i-1]) < diff:
19 | diff = abs(l[i] - l[i-1])
20 | else:
21 | return False
22 | return True
23 |
24 | """ 2)In a list of integers l, the neighbours of l[i] are l[i-1] and l[i+1]. l[i] is a hill
25 | if it is strictly greater than its neighbours and a valley if it is strictly less than its neighbours.
26 | Write a function counthv(l) that takes as input a list of integers l and returns a list [hc,vc]
27 | where hc is the number of hills in l and vc is the number of valleys in l.
28 |
29 | Here are some examples to show how your function should work.
30 |
31 | >>> counthv([1,2,1,2,3,2,1])
32 | [2, 1]
33 |
34 | >>> counthv([1,2,3,1])
35 | [1, 0]
36 |
37 | >>> counthv([3,1,2,3])
38 | [0, 1]"""
39 |
40 | def counthv(l):
41 | hc, vc = 0, 0
42 | for i in range(1, len(l)-1):
43 | if l[i] > l[i-1] and l[i] > l[i+1]:
44 | hc += 1
45 | elif l[i] < l[i-1] and l[i] < l[i+1]:
46 | vc += 1
47 | return [hc, vc]
48 |
49 | """ 3) A square n×n matrix of integers can be written in Python as a list with n elements,
50 | where each element is in turn a list of n integers, representing a row of the matrix. For instance, the matrix
51 |
52 | 1 2 3
53 | 4 5 6
54 | 7 8 9
55 | would be represented as [[1,2,3], [4,5,6], [7,8,9]].
56 |
57 | Write a function leftrotate(m) that takes a list representation m of a square matrix as input, and returns the matrix obtained by rotating the original matrix counterclockwize by 90 degrees. For instance, if we rotate the matrix above, we get
58 |
59 | 3 6 9
60 | 2 5 8
61 | 1 4 7
62 | Your function should not modify the argument m provided to the function rotate().
63 |
64 | Here are some examples of how your function should work.
65 |
66 | >>> leftrotate([[1,2],[3,4]])
67 | [[2, 4], [1, 3]]
68 |
69 | >>> leftrotate([[1,2,3],[4,5,6],[7,8,9]])
70 | [[3, 6, 9], [2, 5, 8], [1, 4, 7]]
71 |
72 | >>> leftrotate([[1,1,1],[2,2,2],[3,3,3]])
73 | [[1, 2, 3], [1, 2, 3], [1, 2, 3]]"""
74 |
75 | def leftrotate(m):
76 | l = len(m)
77 | arr = [[0 for i in range(l)] for i in range(l)]
78 | for i in range(l):
79 | for j in range(l):
80 | arr[i][j] = m[j][(l-1)-i]
81 | return arr
82 |
83 | # def leftrotate(m):
84 | # l = len(m)
85 | # arr = []
86 | # for i in range(l):
87 | # sub_arr = []
88 | # for j in range(l):
89 | # sub_arr.append(m[j][(l-1)-i])
90 | # arr.append(sub_arr)
91 | # return arr
92 |
--------------------------------------------------------------------------------
/W4_L1_merge_sort.py:
--------------------------------------------------------------------------------
1 | # Python program for implementation of MergeSort
2 |
3 | # Merges two subarrays of arr[].
4 | # First subarray is arr[l..m]
5 | # Second subarray is arr[m+1..r]
6 |
7 |
8 | def merge(arr, l, m, r):
9 | n1 = m - l + 1
10 | n2 = r - m
11 |
12 | # create temp arrays
13 | L = [0] * (n1)
14 | R = [0] * (n2)
15 |
16 | # Copy data to temp arrays L[] and R[]
17 | for i in range(0, n1):
18 | L[i] = arr[l + i]
19 |
20 | for j in range(0, n2):
21 | R[j] = arr[m + 1 + j]
22 | # or do L = arr[l:m+1]
23 | # R = arr[m+1:r+1]
24 | # Merge the temp arrays back into arr[l..r]
25 | i = 0 # Initial index of first subarray
26 | j = 0 # Initial index of second subarray
27 | k = l # Initial index of merged subarray
28 |
29 | while i < n1 and j < n2:
30 | if L[i] <= R[j]:
31 | arr[k] = L[i]
32 | i += 1
33 | else:
34 | arr[k] = R[j]
35 | j += 1
36 | k += 1
37 |
38 | # Copy the remaining elements of L[], if there
39 | # are any
40 | while i < n1:
41 | arr[k] = L[i]
42 | i += 1
43 | k += 1
44 |
45 | # Copy the remaining elements of R[], if there
46 | # are any
47 | while j < n2:
48 | arr[k] = R[j]
49 | j += 1
50 | k += 1
51 |
52 | # l is for left index and r is right index of the
53 | # sub-array of arr to be sorted
54 |
55 |
56 | def mergeSort(arr, l, r):
57 | if l < r:
58 |
59 | # Same as (l+r)//2, but avoids overflow for
60 | # large l and h
61 | m = l+(r-l)//2
62 |
63 | # Sort first and second halves
64 | mergeSort(arr, l, m)
65 | mergeSort(arr, m+1, r)
66 | merge(arr, l, m, r)
67 |
68 |
69 | # Driver code to test above
70 | arr = [12, 11, 13, 5, 6, 7]
71 | n = len(arr)
72 | print("Given array is")
73 | print(arr)
74 |
75 | mergeSort(arr, 0, n-1)
76 | print("\n\nSorted array is")
77 | print(arr)
78 |
79 | # Time Complexity: O(n*log(n))
80 | # Auxiliary Space: O(n)
81 |
82 | """ Limitations """
83 | # It requires the use of an extra array
84 | # Extra storage can be costly
85 | # Recursive call and return are expensive
86 |
--------------------------------------------------------------------------------
/W4_L3_quick_sort.py:
--------------------------------------------------------------------------------
1 | # Python program for implementation of Quicksort Sort
2 |
3 | # This implementation utilizes pivot as the last element in the nums list
4 | # It has a pointer to keep track of the elements smaller than the pivot
5 | # At the very end of partition() function, the pointer is swapped with the pivot
6 | # to come up with a "sorted" nums relative to the pivot
7 |
8 |
9 | def partition(l, r, nums):
10 | # Last element will be the pivot and the first element the pointer
11 | pivot, ptr = nums[r], l
12 | for i in range(l, r):
13 | if nums[i] <= pivot:
14 | # Swapping values smaller than the pivot to the front
15 | nums[i], nums[ptr] = nums[ptr], nums[i]
16 | ptr += 1
17 | # Finally swapping the last element with the pointer indexed number
18 | nums[ptr], nums[r] = nums[r], nums[ptr]
19 | return ptr
20 |
21 | # With quicksort() function, we will be utilizing the above code to obtain the pointer
22 | # at which the left values are all smaller than the number at pointer index and vice versa
23 | # for the right values.
24 |
25 |
26 | def quicksort(l, r, nums):
27 | if len(nums) == 1: # Terminating Condition for recursion. VERY IMPORTANT!
28 | return nums
29 | if l < r:
30 | pi = partition(l, r, nums)
31 | quicksort(l, pi-1, nums) # Recursively sorting the left values
32 | quicksort(pi+1, r, nums) # Recursively sorting the right values
33 | return nums
34 |
35 |
36 | example = [4, 5, 1, 2, 3]
37 | result = [1, 2, 3, 4, 5]
38 | print(quicksort(0, len(example)-1, example))
39 |
40 | example = [2, 5, 6, 1, 4, 6, 2, 4, 7, 8]
41 | result = [1, 2, 2, 4, 4, 5, 6, 6, 7, 8]
42 | # As you can see, it works for duplicates too
43 | print(quicksort(0, len(example)-1, example))
44 |
45 | # Time Complexity: Worst case time complexity is O(n**2) and average case time complexity is O(n*log(n))
46 | # Auxiliary Space: O(1)
47 |
48 | # Worst case is when the array is already sorted
49 | """ Generally built-in sort function in programming languages are quick sort """
50 |
--------------------------------------------------------------------------------
/W4_L5_tuples_dictionaries.py:
--------------------------------------------------------------------------------
1 | """ Tuples """
2 | # simultaneous assignment
3 | a, b, c = 10, 11, 12
4 | # is actually (a, b, c) = (10, 11, 12)
5 | t = 1, 2, 3
6 | print(type(t))
7 |
8 | point = (10, 20) # tuple
9 | x_coordinate = point[0]
10 | y_coordinate = point[1]
11 | print(x_coordinate, y_coordinate)
12 |
13 | # But tuples are immutable, we can't do point[0] = 100
14 |
15 | " Dictionary "
16 | empty_dict = {}
17 | empty_dict["One"] = 1 # assigning key value pair
18 | empty_dict["Two"] = 2
19 | print(empty_dict)
20 | # Key should be immutable (int, float, bool, string, tuple)
21 | # Value can be mutable or immutable
22 |
23 | match = {"m1":{"p1":100, "p2":95}, "m2":{"p1":104, "p2":321}}
24 | print(match["m1"]["p2"])
25 | print(empty_dict.keys())
26 |
--------------------------------------------------------------------------------
/W4_L6_function_definitions.py:
--------------------------------------------------------------------------------
1 | def power(a, b):
2 | ans = 1
3 | for i in range(b):
4 | ans *= a
5 | return ans
6 |
7 | # passing values to function
8 | print(power(2, 5))
9 | # passing arguments by name
10 | print(power(b=5, a=2))
11 |
12 | def add(a, b=0): # default argument
13 | return a + b
14 |
15 | print(add(5))
16 |
17 | def square(x):
18 | return x * x
19 |
20 | def apply(f, x, n):
21 | res = x
22 | for i in range(n):
23 | res = f(res)
24 | return(res)
25 |
26 | print(apply(square, 5, 2))
27 | # same as square(square(5))
--------------------------------------------------------------------------------
/W4_L7_list_comprehension.py:
--------------------------------------------------------------------------------
1 | # map(f, l) applies f function to every element in l
2 | l = list(map(int, ['1', '2', '3']))
3 | print(l)
4 | # using list comprenhension
5 | ll = [int(i) for i in '123']
6 | print(ll)
7 |
8 | # filter(p, l) checks p for each element in l
9 |
10 | def is_even(n):
11 | if n % 2 == 0:
12 | return True
13 | return False
14 |
15 | even_l = list(filter(is_even, [0, 1, 2, 3, 5, 6]))
16 | print(even_l)
17 | # using list comprenhension
18 | even_ll = [i for i in [0, 1, 2, 3, 5, 6] if is_even(i)]
19 | print(even_ll)
20 |
21 | # map() and filter() together
22 |
23 | def square(n):
24 | return n * n
25 |
26 | even_square = list(map(square, filter(is_even, [1, 2, 3, 4, 5, 6])))
27 | print(even_square)
28 | # using list comprenhension
29 | even_square_l = [i*i for i in [1, 2, 3, 4, 5, 6] if is_even(i)]
30 | print(even_square_l)
31 | print()
32 |
33 | """ Find all (x, y, z) where x*x + y*y = z*z (pythagoras) """
34 | py = [(x, y, z) for x in range(1, 10) for y in range(1, 10) for z in range(1, 10) if (x*x + y*y)==z*z]
35 | for i in py:
36 | print(i)
37 | print()
38 | # Better code...remove duplicates in x and y
39 | py = [(x, y, z) for x in range(1, 10) for y in range(x, 10) for z in range(y, 10) if x*x + y*y == z*z]
40 | for i in py:
41 | print(i)
42 |
43 | """ 2 D lists """
44 | lst = [[0 for i in range(3)] for j in range(2)]
45 | print(lst)
--------------------------------------------------------------------------------
/W4_programming_assignment.py:
--------------------------------------------------------------------------------
1 | """ 1) Write a Python function frequency(l) that takes as input a list of integers and
2 | returns a pair of the form (minfreqlist,maxfreqlist) where,
3 | minfreqlist is a list of numbers with minimum frequency in l, sorted in ascending order
4 | maxfreqlist is a list of numbers with maximum frequency in l, sorted in ascending order
5 | Here are some examples of how your function should work.
6 |
7 | >>> frequency([13,12,11,13,14,13,7,11,13,14,12])
8 | ([7], [13])
9 |
10 | >>> frequency([13,12,11,13,14,13,7,11,13,14,12,14,14])
11 | ([7], [13, 14])
12 |
13 | >>> frequency([13,12,11,13,14,13,7,11,13,14,12,14,14,7])
14 | ([7, 11, 12], [13, 14])"""
15 |
16 | def frequency(l):
17 | l.sort()
18 | data = {}
19 | for i in l:
20 | data[i] = data.get(i, 0) + 1
21 | minimun, maximun = min(data.values()), max(data.values())
22 | l = ([], [])
23 | for i in data:
24 | if data[i] == minimun:
25 | l[0].append(i)
26 | if data[i] == maximun:
27 | l[1].append(i)
28 | return l
29 |
30 | """ 2)An airline has assigned each city that it serves a unique numeric code.
31 | It has collected information about all the direct flights it operates, represented
32 | as a list of pairs of the form (i,j), where i is the code of the starting city and
33 | j is the code of the destination.
34 |
35 | It now wants to compute all pairs of cities connected by one intermediate hope — city i
36 | is connected to city j by one intermediate hop if there are direct flights of the
37 | form (i,k) and (k,j) for some other city k. The airline is only interested in
38 | one hop flights between different cities — pairs of the form (i,i) are not useful.
39 |
40 | Write a Python function onehop(l) that takes as input a list of pairs representing
41 | direct flights, as described above, and returns a list of all pairs (i,j), where i != j,
42 | such that i and j are connected by one hop. Note that it may already be the case that
43 | there is a direct flight from i to j. So long as there is an intermediate k with a flight
44 | from i to k and from k to j, the list returned by the function should include (i,j).
45 | The input list may be in any order. The pairs in the output list should be in
46 | lexicographic (dictionary) order. Each pair should be listed exactly once.
47 |
48 | Here are some examples of how your function should work.
49 |
50 | >>> onehop([(2,3),(1,2)])
51 | [(1, 3)]
52 |
53 | >>> onehop([(2,3),(1,2),(3,1),(1,3),(3,2),(2,4),(4,1)])
54 | [(1, 2), (1, 3), (1, 4), (2, 1), (3, 2), (3, 4), (4, 2), (4, 3)]
55 |
56 | >>> onehop([(1,2),(3,4),(5,6)])
57 | [] """
58 |
59 | def onehop(l):
60 | result=[]
61 | n = len(l)
62 | for i in range(n):
63 | for j in range(n):
64 | if l[i][1] == l[j][0] and l[i][0] != l[j][1]:
65 | result.append((l[i][0], l[j][1]))
66 | return sorted(set(result))
67 |
--------------------------------------------------------------------------------
/W4_quiz.py:
--------------------------------------------------------------------------------
1 | # 1)
2 | def mystery(l):
3 | if l == []:
4 | return(l)
5 | else:
6 | return(mystery(l[1:])+l[:1])
7 |
8 | print(mystery([22,14,19,65,82,55]))
9 |
10 | # 2)
11 | pairs = [ (x,y) for x in range(4,1,-1) for y in range(5,1,-1) if (x+y)%3 == 0 ]
12 | print(pairs)
13 |
14 | # 3)
15 | wickets = {"Tests":{"Bumrah":[3,5,2,3],"Shami":[4,4,1,0],"Ashwin":[2,1,7,4]},"ODI":{"Bumrah":[2,0],"Shami":[1,2]}}
16 | # wickets["ODI"]["Ashwin"][0:] = [4,4] Error
17 | # wickets["ODI"]["Ashwin"].extend([4,4]) Error
18 | wickets["ODI"]["Ashwin"] = [4,4]
19 | # wickets["ODI"]["Ashwin"] = wickets["ODI"]["Ashwin"] + [4,4] Error
20 |
21 | # 4)
22 | hundreds = {}
23 | # hundreds["Tendulkar, international"] = 100
24 | # hundreds["Tendulkar"] = {"international":100}
25 | # hundreds[("Tendulkar","international")] = 100
26 | hundreds[["Tendulkar","international"]] = 100
--------------------------------------------------------------------------------
/W5_L1_exception_handling.py:
--------------------------------------------------------------------------------
1 | # Handling error is exception handling
2 |
3 | try:
4 | print(5/0)
5 | except Exception as e:
6 | print("Error")
7 | print(e)
8 |
9 | """
10 | try:
11 | # Some Code....
12 | except:
13 | # optional block
14 | # Handling of exception (if required)
15 | else:
16 | # execute if no exception
17 | finally:
18 | # Some code .....(always executed)
19 | """
--------------------------------------------------------------------------------
/W5_L2_standard_input_output.py:
--------------------------------------------------------------------------------
1 | """ Programs need to interact with user
2 | - receive input (Keyboard)
3 | - display output (Screen) """
4 |
5 | # Read a line of input and assign it to variable data
6 | data = input("Enter the data : ")
7 | # default datatype is string
8 | data = int(input("Enter the number : "))
9 | # the datatype is converted to integer
10 |
11 | while True:
12 | try:
13 | value = int(input("Enter the number : "))
14 | except:
15 | print("The entered data is not an interger. Try again...")
16 | else:
17 | break
18 |
19 | print()
20 | print("A line", end=" ")
21 | print("Same line", end="\nNext line\n")
22 | print(1, 2, 3, 4, 5, sep="-")
23 |
--------------------------------------------------------------------------------
/W5_L3_file1.txt:
--------------------------------------------------------------------------------
1 | Hey New World
2 | New line here
3 | Another new line hereline 1
4 | line 2
5 | line 3
6 |
--------------------------------------------------------------------------------
/W5_L3_handling_files.py:
--------------------------------------------------------------------------------
1 | with open("W5_L3_file1.txt", "w") as f:
2 | f.write("Hey New World\n")
3 | f.write("New line here\n")
4 | f.write("Another new line here")
5 | # f.write() - to write to a file, return number of characters written
6 | f.writelines(["line 1\n", "line 2\n", "line 3\n"])
7 | # f.writelines() - to write a list of lines
8 |
9 | # r - mode to read a file
10 | # w - mode to write to a file
11 | # a - mode to append a file
12 | # f.close() - flushes the buffer if opened used f.open()
13 | # with open() as f - if used don't need to close using f.close()
14 |
15 | with open("W5_L3_file1.txt") as f:
16 | print(f.read())
17 | print()
18 | # f.read() - read the entire data in a string format
19 | # f.read(n) - read the n characters of the file
20 |
21 | with open("W5_L3_file1.txt") as f:
22 | print(f.readline(), end="")
23 | print(f.readline())
24 | # f.readline() - read the next line in string format
25 | with open("W5_L3_file1.txt") as f:
26 | print(f.readlines())
27 | # f.readlines() - read and give a list of each line as string
28 | with open("W5_L3_file1.txt") as f:
29 | for i in f.readlines():
30 | print(i[:-1]) # will exclude '\n' in the end
31 |
32 | """ f.seek() can be used to move the file poiner to any position """
33 | # f.seek(0) - to move file pointer to begining of the file
--------------------------------------------------------------------------------
/W5_L4_string_functions.py:
--------------------------------------------------------------------------------
1 | """ lstrip() - strip the empty spaces in left """
2 | a = " joswin"
3 | print(a) # joswin
4 | print(a.lstrip()) # joswin
5 |
6 | """ rstrip() - strip the empty spaces in right """
7 |
8 | """ strip() - strip off the empty spaces in both sides """
9 | a = " the best "
10 | print(a) # the best
11 | print(a.strip()) # the best
12 |
13 | """ find(s) - return the first occurance of s in the string """
14 | a = "apple"
15 | print(a.find("p")) # 1
16 | print(a.find("pl")) # 2
17 |
18 | """ index(s) - as same as find(s) but raise ValueError if s not found """
19 | a = "apple"
20 | print(a.index("ppl")) # 1
21 |
22 | """ replace(fromstr, tostr) - replace the fromstr with tostr in the string """
23 | a = "apples is healthy is"
24 | print(a.replace("is", "are")) # apples are healthy are
25 | print(a.replace("is", "are", 1)) # apples are healthy is
26 |
27 | """ split(s) - split a string on s into list elements """
28 | a = "one,two,three,four"
29 | print(a.split(",")) # ['one', 'two', 'three', 'four']
30 | print(a.split(",", 2)) # ['one', 'two', 'three,four']
31 |
32 | """ join(l) - recombines a list of string using a separator """
33 | a = ["1", "2", "3", "4"]
34 | print(",".join(a)) # 1,2,3,4
35 |
36 | """ capitalize() - return new string with first letter uppercase rest lower """
37 | """ lower() - return new string with all letter lowercase """
38 | """ upper() - return new string with all letter uppercase """
39 | """ title() - return title format, first letter of each word in sentence capital """
40 | a = "this world is happy"
41 | print(a.capitalize()) # This world is happy
42 | print(a.title()) # This World Is Happy
43 |
44 | """ swapcase() - revert uppercase to lower and lower to upper """
45 |
46 | """ center(n) - return string of length n with s centred with blank """
47 | print("joswin".center(10, "*")) # **joswin**
48 | print("joswin".ljust(10, "*")) # joswin****
49 | print("joswin".rjust(10, "*")) # ****joswin
50 |
51 |
52 | """ isalpha() - checks if the string is alphabitical """
53 | """ isnumeric() - checks if the stirng is numerical """
--------------------------------------------------------------------------------
/W5_L5_formatting_printed_output.py:
--------------------------------------------------------------------------------
1 | print("Joswin", "is", "the", "best", sep="$", end="(^_^)\n")
2 |
3 | """ format() method """
4 | print("First : {0}, Second : {1}".format("Joswin", 100))
5 | # First : Joswin, Second : 100
6 | print("First : {1}, Second : {0}".format("Joswin", 100))
7 | # First : 100, Second : Joswin
8 | print("First : {a}, Second : {f}".format(a="Joswin", f=99))
9 | # First : Joswin, Second : 99
10 |
11 | print("Value : {0:3d}".format(10))
12 | # Value : 10
13 | print("Value : {0:7.3f}".format(55.223433))
14 | # Value : 55.223
--------------------------------------------------------------------------------
/W5_L6_pass_del_None.py:
--------------------------------------------------------------------------------
1 | """ pass - is used to do noting or leave an inteded block blank """
2 | if True:
3 | pass
4 | else:
5 | pass
6 |
7 | """ del """
8 | lst = [1, 2, 3, 4, 5]
9 | del(lst[2])
10 | print(lst) # [1, 2, 4, 5]
11 |
12 | dic = {1:"one", 2:"two"}
13 | del(dic[1])
14 | print(dic) # {2: 'two'}
15 |
16 | x = 10
17 | print(x) # 10
18 | del(x)
19 | #print(x) # Error , del(x) makes x undefined
20 |
21 | """ None - is a keyword used to denote 'nothing' """
--------------------------------------------------------------------------------
/W5_programming_assignment.py:
--------------------------------------------------------------------------------
1 | """ Q) Here are some basic facts about tennis scoring: A tennis match is made up of sets. A set is made up of games.
2 |
3 | To win a set, a player has to win 6 games with a difference of 2 games. At 6-6, there is often a special tie-breaker. In some cases, players go on playing till
4 | one of them wins the set with a difference of two games. Tennis matches can be either 3 sets or 5 sets. The player who wins a majority of sets wins the match
5 | (i.e., 2 out 3 sets or 3 out of 5 sets) The score of a match lists out the games in each set, with the overall winner's score reported first for each set.
6 | Thus, if the score is 6-3, 5-7, 7-6 it means that the first player won the first set by 6 games to 3, lost the second one 5 games to 7 and won the
7 | third one 7 games to 6 (and hence won the overall match as well by 2 sets to 1).
8 | You will read input from the keyboard (standard input) containing the results of several tennis matches. Each match's score is recorded on a separate line with the
9 | following format:
10 |
11 | Winner:Loser:Set-1-score,...,Set-k-score, where 2 ≤ k ≤ 5
12 |
13 | For example, an input line of the form
14 |
15 | Osaka:Barty:3-6,6-3,6-3
16 | indicates that Osaka beat Barty 3-6, 6-3, 6-3 in a best of 3 set match.
17 |
18 | The input is terminated by a blank line.
19 |
20 | You have to write a Python program that reads information about all the matches and compile the following statistics for each player:
21 |
22 | Number of best-of-5 set matches won
23 | Number of best-of-3 set matches won
24 | Number of sets won
25 | Number of games won
26 | Number of sets lost
27 | Number of games lost
28 | You should print out to the screen (standard output) a summary in decreasing order of ranking, where the ranking is according to the criteria 1-6 in that order
29 | (compare item 1, if equal compare item 2, if equal compare item 3 etc, noting that for items 5 and 6 the comparison is reversed).
30 |
31 | For instance, given the following data
32 |
33 | Zverev:Medvedev:2-6,6-7,7-6,6-3,6-1
34 | Barty:Osaka:6-4,6-4
35 | Medvedev:Zverev:6-3,6-3
36 | Osaka:Barty:1-6,7-5,6-2
37 | Zverev:Medvedev:6-0,7-6,6-3
38 | Osaka:Barty:2-6,6-2,6-0
39 | Medvedev:Zverev:6-3,4-6,6-3,6-4
40 | Barty:Osaka:6-1,3-6,7-5
41 | Zverev:Medvedev:7-6,4-6,7-6,2-6,6-2
42 | Osaka:Barty:6-4,1-6,6-3
43 | Medvedev:Zverev:7-5,7-5
44 | Osaka:Barty:3-6,6-3,6-3
45 | your program should print out the following
46 |
47 | Zverev 3 0 10 104 11 106
48 | Medvedev 1 2 11 106 10 104
49 | Osaka 0 4 9 76 8 74
50 | Barty 0 2 8 74 9 76
51 | You can assume that there are no spaces around the punctuation marks ":", "-" and ",". Each player's name will be spelled consistently and no two players
52 | have the same name."""
53 |
54 | """CODE"""
55 |
56 | data=input()
57 | result={}
58 | while data:
59 | winner, loser, sets = data.split(':')
60 | winner_sets, loser_sets = 0, 0
61 | winner_games, loser_games = 0, 0
62 | winner_BO5, winner_BO3 = 0, 0
63 |
64 | for i in sets.split(','):
65 | score = list(map(int, i.split('-')))
66 |
67 | if score[0] > score[1]:
68 | winner_sets += 1
69 | else:
70 | loser_sets += 1
71 |
72 | winner_games += score[0]
73 | loser_games += score[1]
74 |
75 | if winner_sets >= 3:
76 | winner_BO5 += 1
77 | else:
78 | winner_BO3 += 1
79 |
80 | if winner not in result:
81 | result[winner] = [0, 0, 0, 0, 0, 0]
82 | if loser not in result:
83 | result[loser] = [0, 0, 0, 0, 0, 0]
84 |
85 | result[winner][0] += winner_BO5
86 | result[winner][1] += winner_BO3
87 | result[winner][2] += winner_sets
88 | result[winner][3] += winner_games
89 | result[winner][4] += loser_sets
90 | result[winner][5] += loser_games
91 |
92 | result[loser][2] += loser_sets
93 | result[loser][3] += loser_games
94 | result[loser][4] += winner_sets
95 | result[loser][5] += winner_games
96 |
97 | data=input()
98 |
99 | result = sorted(result.items(), key=lambda t:t[1], reverse=True)
100 |
101 | for player in result:
102 | print(f"{player[0]} {player[1][0]} {player[1][1]} {player[1][2]} {player[1][3]} {player[1][4]} {player[1][5]}")
103 |
--------------------------------------------------------------------------------
/W6_L1_PythonCode.py:
--------------------------------------------------------------------------------
1 | def initialize(n):
2 | for key in ['queen','row','col','nwtose','swtone']:
3 | board[key] = {}
4 | for i in range(n):
5 | board['queen'][i] = -1
6 | board['row'][i] = 0
7 | board['col'][i] = 0
8 | for i in range(-(n-1),n):
9 | board['nwtose'][i] = 0
10 | for i in range(2*n-1):
11 | board['swtone'][i] = 0
12 |
13 | def printboard():
14 | for row in sorted(board['queen'].keys()):
15 | print((row,board['queen'][row]),end=" ")
16 | print("")
17 |
18 | def free(i,j):
19 | return(board['row'][i] == 0 and board['col'][j] == 0 and
20 | board['nwtose'][j-i] == 0 and board['swtone'][j+i] == 0)
21 |
22 | def addqueen(i,j):
23 | board['queen'][i] = j
24 | board['row'][i] = 1
25 | board['col'][j] = 1
26 | board['nwtose'][j-i] = 1
27 | board['swtone'][j+i] = 1
28 |
29 | def undoqueen(i,j):
30 | board['queen'][i] = -1
31 | board['row'][i] = 0
32 | board['col'][j] = 0
33 | board['nwtose'][j-i] = 0
34 | board['swtone'][j+i] = 0
35 |
36 | def placequeen(i):
37 | n = len(board['queen'].keys())
38 | for j in range(n):
39 | if free(i,j):
40 | addqueen(i,j)
41 | if i == n-1:
42 | printboard()
43 | else:
44 | extendsoln = placequeen(i+1)
45 | undoqueen(i,j)
46 |
47 | board = {}
48 | n = int(input("How many queens? "))
49 | initialize(n)
50 | if placequeen(0):
51 | printboard()
--------------------------------------------------------------------------------
/W6_L2_globalscope_nestedfunctions.py:
--------------------------------------------------------------------------------
1 | """ Scope is the portion of the code where the name or variable is
2 | available to read and update """
3 |
4 | # def f():
5 | # y = x # Value of x taken from global scope
6 | # # y is in local scope
7 | # print(y)
8 | # x = 7 # Global scope
9 | # f()
10 |
11 | # Output: 7
12 |
13 | # def f():
14 | # y = x
15 | # print(y)
16 | # x = 22 # we try to assign value to x, which is global, so error
17 | # x = 7
18 | # f()
19 |
20 | # Output: Error
21 |
22 | """ This applies only to immutable values, for mutable values,
23 | we can change the value in functions or local scope """
24 |
25 | # def f():
26 | # y = x[0]
27 | # print(y, end=" ")
28 | # x[0] = 22 # trying to change value of mutable datatype(list)
29 | # print(x)
30 | # x = [7]
31 | # f()
32 |
33 | # Output: 7 [22]
34 |
35 | # def f():
36 | # global x # calling the global x, making it available in local scope to change
37 | # y = x
38 | # print(y, end=" ")
39 | # x = 22
40 | # print(x)
41 | # x = 7
42 | # f()
43 |
44 | # Output: 7 22
45 |
46 | """ Nested Functions """
47 | # Functions inside another function are nested functions
48 | # These functions are available withing the local scope or the funtion only
49 |
50 | def f():
51 | a = 10
52 | def g():
53 | nonlocal a # here we call in the local a, a is available in f() or local scope not global
54 | a = 100 # since we are changing its value, we use nonlocal a, like we used global x, before
55 | return a
56 | def h():
57 | return 1
58 | print(g() + h()) # g() and h() are the nested funcitons and can be used inside f() only
59 | f()
60 |
61 | # Output: 3
--------------------------------------------------------------------------------
/W6_L3_generating_permutations.py:
--------------------------------------------------------------------------------
1 | # Often used when we need to try out all possibilities
2 |
3 | # For instance, what is the next sequence formed from
4 | # {a, b, c, d, e, f, g, h, i, j, k, l, m}, in dictionary after
5 | # d c h b a e g l k o n m j i
6 |
7 | # smallest permutation - all elements in ascending order
8 | # a b c d e f g h i j k l m
9 |
10 | # largest permutation - all elements in descending order
11 | # m l k j i h g f e d c b a
12 |
13 | # next permutation - find shortest suffix that can be incremented
14 | # or longest suffix that cannot be incremented
15 |
16 | # longest suffix that cannot be incremented -
17 | # - already in descending order
18 |
19 | # d c h b a e g l k o n m j i
20 |
21 | # o n m j i - these letters are in descending order
22 | # so we cannot make any larger permutations
23 | # we fix from d to k - o n m j i is the largest permutation of the suffix
24 | # to increment we also include k, suffix k o n m j i can be incremented
25 | # how do we increment this?
26 | # replace k by next largest letter to its right, m
27 | # d c h b a e g l m o n k j i
28 | # now arrange o n k j i in ascending order - i j k n o
29 |
30 | # d c h b a e g l m i j k n o - is the next permutation
31 |
32 | """ Implementation """
33 | #1) from the right, identify first decreasing position
34 | # k in - d c h b a e g l k o n m j i
35 |
36 | #2) swap that value with its next larger letter to its right
37 | # m is the next larger letter of k - in o n m j i
38 | # it becomes - d c h b a e g l m o n k j i
39 |
40 | #3) reverse the increasing suffix
41 | # reverse or arrange in ascending order - o n k j i
42 | # to i j k n o
43 |
44 | # d c h b a e g l m i j k n o - is the next permutation
--------------------------------------------------------------------------------
/W6_L4_sets_stacks_queues.py:
--------------------------------------------------------------------------------
1 | # Algorithms + Data Structures = Programs
2 |
3 | """ Data structures examples
4 | - arrays / lists
5 | - dictionaries
6 | - python builtin data types etc """
7 |
8 | """ -----------------------------------------------------------"""
9 |
10 | """ Sets """
11 | colors = {"Red", "Green", "Blue", "White"}
12 | print(colors)
13 | # {'Green', 'Blue', 'White', 'Red'}
14 | empty_set = {}
15 | print(empty_set)
16 | # {}
17 | print("Green" in colors)
18 | # True
19 | word = "Banana"
20 | print(set(word))
21 | # {'B', 'a', 'n'}
22 |
23 | """ Set operations """
24 | odd = {1, 3, 5, 7, 9, 11}
25 | prime = {2, 3, 5, 7, 11}
26 |
27 | """ Union """
28 | print(odd | prime) # or
29 | # {1, 2, 3, 5, 7, 9, 11}
30 |
31 | """ Intersection """
32 | print(odd & prime) # and
33 | # {11, 3, 5, 7}
34 |
35 | """ Set difference """
36 | print(odd - prime)
37 | # {1, 9}
38 |
39 | """ ------------------------------------------------------------- """
40 |
41 | """ Stacks """
42 | # LIFO - last in first out
43 | # operations that can be performed:
44 | # push(element) - push an element to the last of the stack
45 | # list.append(element) - can be used
46 | # pop() - pop and element from the last of the stack and return it
47 | # list.pop() - can be used
48 |
49 | """ ------------------------------------------------------------- """
50 |
51 | """ Queues """
52 | # FIFO - first in first out
53 | # LILO - last in last out
54 | # operations that can be performed:
55 | # addq(element) - add an element to the last of the queue
56 | # also called enqueue
57 | # list.append(element) - can be used
58 | # removeq() - remove the element from the head of the queue
59 | # also called dequeue
60 | # list.pop(0) - can be used
61 |
62 | """ ------------------------------------------------------------- """
63 |
64 |
--------------------------------------------------------------------------------
/W6_L5_priority_queues_heaps.py:
--------------------------------------------------------------------------------
1 | """ Priority queues """
2 | # delete_max() - identifies and remove the element with highest priority
3 | # need not be unique
4 | # insert() - add a new element to the list
5 |
6 | # If unsorted list - insert() takes O(1) time
7 | # - delete_max() takes O(n) time
8 |
9 | # If sorted list - delete_max() takes O(1) time
10 | # - insert() takes O(n) time
11 |
12 | # Thus processing a sequence of n cases requires O(n**2) time
13 |
14 | """ Binary tree """
15 | # a basic Two dimensional structure
16 | # at each node
17 | # - value
18 | # - link to parent, left child, right child
19 | # node with no children is called leaf
20 | # node with children is called parent, have a right child and left child
21 | # Ex 5 (root)
22 | # / \
23 | #(parent) 2 8
24 | # / \ \
25 | # 1 4 9 (leaf)
26 | # (left and right child)
27 |
28 | """ Heap """
29 | # Heaps are a tree based implementation of priority queues
30 | # Heaps are special kind of binary tree having a priority queue
31 | # This tree is a balanced tree
32 | # A balanced tree is the one in which at each point the left and right
33 | # side are almost the same size.
34 | # N node tree has height log(N)
35 | # Both insert and delete_max() take O(log(N))
36 | # Progessing N cases takes time O(N*log(N))
37 | # Truly flexible, need not fix upper bound for N in advance
38 |
39 | # Head a binary tree with two properties:
40 | # -Binary tree is filled level by level, left to right
41 | # -At each node, value stored is bigger than both children
42 | # -Max Heap property - evey value in node is bigger than the values of the two children
43 |
44 | # Ex 24
45 | # / \
46 | # 11 7
47 | # /
48 | # 10
49 | # correct example of a node, 11>10, 24>11 and 24>7
50 |
51 | # Ex 24
52 | # / \
53 | # 11 7
54 | # / \ / \
55 | # 10 5 6 5
56 | # correct example of a node, 11>10 and 11>5,
57 | # 7>6 and 7>5, 24>11 and 24>7
58 |
59 | # Ex 24
60 | # / \
61 | # 11 7
62 | # / \ /
63 | # 10 5 6
64 | # /
65 | # 8
66 | # not a heap, as right child of node with value 7
67 | # is not filled with 8. STRUCTURE of heap is violated
68 |
69 | # Ex 24
70 | # / \
71 | # 11 7
72 | # / \ / \
73 | # 10 5 8 5
74 | # not a heap, as 7<8
75 | # Max Heap property is violated, so not a heap
76 |
77 | # insert()
78 | # Ex 24
79 | # / \
80 | # 11 7
81 | # / \ / \
82 | # 10 5 6 5
83 | # insert(12) to this node - it will become
84 | # 24
85 | # / \
86 | # 12 7
87 | # / \ / \
88 | # 11 5 6 5
89 | # /
90 | # 10
91 | # insert(33)
92 | # 33
93 | # / \
94 | # 24 7
95 | # / \ / \
96 | # 12 5 6 5
97 | # / \
98 | # 10 11
99 |
100 | # Complexity of insert()
101 | # we have to walk up from the leaf to the root - height of tree
102 | # insert() takes time O(log(N))
103 |
104 | # delete_max()
105 | # maximum value is always the root
106 | # - first, we create a "hole" at the root
107 | # - reducing one value requires deleting last node
108 | # - move the "homeless" value to root
109 | # __
110 | # / \
111 | # 24 7
112 | # / \ / \
113 | # 12 5 6 5 # first step
114 | # / \
115 | # 10 11
116 | # 11
117 | # / \
118 | # 24 7
119 | # / \ / \ # next step
120 | # 12 5 6 5
121 | # /
122 | # 10
123 | # - now we have to restore the heap property
124 | # 24
125 | # / \
126 | # 12 7
127 | # / \ / \
128 | # 11 5 6 5
129 | # /
130 | # 10
131 |
132 | # will follow a single path from root to leaf
133 | # cost proportional to height of tree
134 | # delete_max() takes time O(log(N))
135 |
136 | # delete_max() again on the heap
137 | # __
138 | # / \
139 | # 12 7
140 | # / \ / \
141 | # 11 5 6 5
142 | # /
143 | # 10
144 | # 10
145 | # / \
146 | # 12 7
147 | # / \ / \
148 | # 11 5 6 5
149 | # 12
150 | # / \
151 | # 11 7
152 | # / \ / \
153 | # 10 5 6 5
154 |
155 | # Implementing using an array
156 | # 0
157 | # / \
158 | # 1 2
159 | # / \ / \ # 0,1,2... represent indexes
160 | # 3 4 5 6
161 | # / \
162 | # 7 8
163 |
164 | # - number the nodes left to right, level by level
165 | # - represent as an array H[0..N-1]
166 | # - Children of H[i] are at H[2*i + 1] , H[2*i + 2]
167 | # - Parent of H[j] is at H[floor((j-1)/2)] for j > 0
168 |
169 | """ Building a heap, heapify() """
170 | # give a list of values [x1,x2,x3,x4,...,xn], build a heap
171 | # Naive approach
172 | # - start with an empty heap
173 | # - insert each xj
174 | # - overall O(N*log(N))
175 |
176 | # Better heapify()
177 | # - Set up the array a [x1,x2,x3,x4,...,xn]
178 | # - Leaf nodes trivially satisy heap property
179 | # - second half of array is already a valid heap
180 | # - Assume leaf nodes are at level k
181 | # - for each node at level k-1, k-2, ... , 0, fix heap property
182 | # - as we go up, the number of steps per node goesup by 1,
183 | # but the number of nodes per level is halved
184 | # - cost turns out to be O(N) overall
185 |
186 | """ Heap sort """
187 | # - start with an unordered list
188 | # - build a heap - O(n)
189 | # - call delete_max() n times to extract elements in descending order - O(n*log(n))
190 | # - after each delete_max(), heap shrinks by 1,
191 | # - store maximum value at the end of the current heap
192 | # - in place O(n*log(n)) sort
193 |
194 | """ Heap min """
195 | # we can revert the heap condition
196 | # each node is smaller than the children
197 | # Min-heap, for insert(), delete_min()
--------------------------------------------------------------------------------
/W6_quiz.py:
--------------------------------------------------------------------------------
1 | """ 1) Suppose u and v both have values of type set and are disjoint.
2 | Which of the following expressions evaluates to True?
3 | u == v | (u^v)
4 | u == (v^u)
5 | u == v^(u | v)
6 | u == u^(v | u) """
7 |
8 | # Disjoin sets are sets that have no common value
9 | # or u intersection v = null set
10 |
11 | # u = {1, 2, 3}
12 | # v = {4, 5, 6}
13 |
14 | # print(u^v) # {1, 2, 3, 4, 5, 6}
15 | # The symmetric difference between two sets is the set of all the elements
16 | # that are either in the first set or the second set but not in both.
17 |
18 | # You have the choice of using either the symmetric_difference() method
19 | # or the ^ operator to do this in Python.
20 |
21 | # print(u == v | (u^v)) # False
22 | # print(u == (v^u)) # False
23 | # print(u == v^(u | v)) # True
24 | # print(u == u^(v | u)) # False
25 |
26 | # ANS) u == v^(u | v)
27 |
28 | """ 2) Suppose u and v both denote sets in Python. What is the most
29 | general condition that guarantees that u|v == u^v?
30 | The sets u and v should be disjoint.
31 | The set u should be a subset of the set v.
32 | The set v should be a subset of the set u.
33 | This is true for any u and v. """
34 |
35 | # u = {1, 2, 3} # u and v are disjoint sets
36 | # v = {4, 5, 6}
37 | # print(u | v) # {1, 2, 3, 4, 5, 6}
38 | # print(u ^ v) # {1, 2, 3, 4, 5, 6}
39 | # print(u|v == u^v) # True
40 |
41 | # u = {1, 2, 3} # u is a subset of set v
42 | # v = {1, 2, 3, 4, 5}
43 | # print(u | v) # {1, 2, 3, 4, 5}
44 | # print(u ^ v) # {4, 5}
45 | # print(u|v == u^v) # False
46 |
47 | # u = {1, 2, 3, 4, 5}
48 | # v = {1, 2, 3} # v is a subset of set u
49 | # print(u | v) # {1, 2, 3, 4, 5}
50 | # print(u ^ v) # {4, 5}
51 | # print(u|v == u^v) # False
52 |
53 | # Thus, u|v == u^v when u and v are disjoint sets
54 |
55 | # ANS) The sets u and v should be disjoint.
56 |
57 | """ 3) Consider the min-heap [15, 27, 33, 39, 66, 39, 47, 58, 51].
58 | built by repeatedly inserting values into an empty heap. Which of the
59 | following could not have been the last element inserted into this heap?
60 | 27
61 | 15
62 | 58
63 | 51 """
64 | # check this out for explanation
65 | # https://stackoverflow.com/questions/69024237/find-the-last-element-inserted-into-the-min-heap
66 |
67 | # ANS) 58
68 |
69 | """ 4) Suppose we execute delete-min twice on the min-heap [13,29,24,67,52,89,45,98,79,58].
70 | What is the resulting heap? """
71 | # just do to delete_min() operation on the heap and we will get the answer:
72 | # ANS) [29,52,45,67,79,89,58,98]
73 |
--------------------------------------------------------------------------------
/W7_L1_abstractDatatypes_classes_objects.py:
--------------------------------------------------------------------------------
1 | # We can go beyond the builtin datatypes and create ourown datatypes
2 | # A data structure is an organisation of information whose behaviour is
3 | # defined through an interface, interface is the allowed set of operations
4 | # Ex: stack is a data structure having operations pop() and push()
5 | # Ex: queue - having operations enqueue() and dequeue()
6 | # Ex: Heap - insert() and delete_max()
7 |
8 | # We are implementing all these using builtin list,
9 | # but the operations of list, like append should not be done in heap etc
10 |
11 | # In order to avoid this, we define abstract datatypes, where no other operations can be done
12 | # Ex: In stack, (stack.push(v)).pop() == v, as stack.pop() gives back the last value added
13 | # and last value added using stack.push() is v, so it should be equal to v
14 | # Ex: In queue, ((q.enqueue(u)).enqueue(v)).dequeue() == u
15 |
16 | # We should imagine each data structures like a black box
17 | # only specific operations can be done which is unique to each data structure
18 |
19 | # Abstract Data Types can be defined using object oriented programming (OOP)
20 | # Class and Objects are important concepts of OOP
21 |
22 | # Class: is like a template, how data is stored, what all operations can be performed
23 | # Object: is an instance of the template
24 |
25 | # DUMMY EXAMPLE
26 | """
27 | class Heap:
28 | def __init__(self, l):
29 | # create heap from list l
30 | def insert(self, x):
31 | # insert x into heap
32 | def delete_max(self):
33 | # return max element and delete it from heap
34 |
35 | # creating object
36 | h1 = Heap([15, 32, 10])
37 | # applying operations
38 | h1.insert(23)
39 | h1.insert(19)
40 | x = h1.delete_max()
41 | """
42 |
--------------------------------------------------------------------------------
/W7_L2_classes_objects_in_Python.py:
--------------------------------------------------------------------------------
1 | # 'self' is a name that is used inside a class to refer to the object
2 | # that we are currently working on
3 |
4 | # __init__() is called the constructor,
5 | # called when object is created
6 | # __str__() return the string representation,
7 | # of the object when called
8 | # str(o) == o.__str__(), implicitly invoked by print()
9 | # __add__() : invoked implicitly by +
10 | # p1 + p2 = p1.__add__(p2)
11 | # __mul__() : called implicitly by *
12 | # p1 * p2 = p1.__mul__(p2)
13 | #__lt__(), __gt__(), __le__()
14 | # called implicityly by <, >, <=
15 |
16 |
17 | """ Class on points on a plane """
18 | class Point:
19 |
20 | def __init__(self, a, b):
21 | self.x = a
22 | self.y = b
23 |
24 | def __str__(self):
25 | return f"a point where co-ordinates ({self.x}, {self.y})"
26 |
27 | def __add__(self, p2):
28 | return Point(self.x + p2.x, self.y + p2.y)
29 |
30 | def translate(self, deltax, deltay):
31 | # shifting (x, y) to (x+deltax, y+deltay)
32 | self.x += deltax
33 | self.y += deltay
34 |
35 | def o_distance(self):
36 | # return the distance from origin
37 | return (self.x**2 + self.y**2)**(1/2)
38 |
39 | class Point2:
40 |
41 | def __init__(self, a=0, b=0): # a=0, b=0 are default arguments
42 | import math
43 | self.r = math.sqrt(a*a + b*b)
44 | if a == 0:
45 | self.theta = 0
46 | else:
47 | self.theta = math.atan(b/a)
48 |
49 | def o_distance(self):
50 | return self.r
51 |
52 | def translate(self, deltax, deltay):
53 | import math
54 | x = self.r * math.cos(self.theta)
55 | y = self.r * math.sin(self.theta)
56 | x += deltax
57 | y += deltay
58 | self.r = math.sqrt(x*x + y*y)
59 | if x == 0:
60 | self.theta = 0
61 | else:
62 | self.theta = math.atan(y/x)
63 |
64 | p1 = Point(5, 15)
65 | print(p1)
66 | # a point where co-ordinates (5, 15)
67 | print(p1.x, p1.y)
68 | # Output: 5 15
69 | p1.translate(10, 5)
70 | print(p1)
71 | # a point where co-ordinates (15, 20)
72 | print(p1.x, p1.y)
73 | # Output: 15 20
74 | print(p1.o_distance())
75 | # Output: 25.0
76 |
77 | p = Point(100, 100)
78 | p4 = p + p1
79 | print(p4)
80 | # a point where co-ordinates (115, 120)
81 |
82 | p2 = Point2(15, 20)
83 | print(p2.o_distance())
84 | # Output: 25.0
85 | p2.translate(5, 5)
86 | # Now point (15, 20) becomes (20, 25)
87 | # also r and theta value also changes
88 | print(p2.o_distance())
89 | # Output: 32.01562118716424 , which is sqrt(20**2 + 25**2)
90 |
--------------------------------------------------------------------------------
/W7_L3_PythonCode.py:
--------------------------------------------------------------------------------
1 | class Node:
2 | def __init__(self, v = None):
3 | self.value = v
4 | self.next = None
5 | return
6 |
7 | def isempty(self):
8 | if self.value == None:
9 | return(True)
10 | else:
11 | return(False)
12 |
13 | def append(self,v): # append, recursive
14 | if self.isempty():
15 | self.value = v
16 | elif self.next == None:
17 | newnode = Node(v)
18 | self.next = newnode
19 | else:
20 | self.next.append(v)
21 | return
22 |
23 | def insert(self,v):
24 | if self.isempty():
25 | self.value = v
26 | return
27 |
28 | newnode = Node(v)
29 |
30 | # Evchange values in self and newnode
31 | (self.value, newnode.value) = (newnode.value, self.value)
32 | (self.next, newnode.next) = (newnode, self.next)
33 |
34 | return
35 |
36 | def delete(self,v): # delete, recursive
37 | if self.isempty():
38 | return
39 |
40 | if self.value == v:
41 | self.value = None
42 | if self.next != None:
43 | self.value = self.next.value
44 | self.next = self.next.next
45 | return
46 | else:
47 | if self.next != None:
48 | self.next.delete(v)
49 | if self.next.value == None:
50 | self.next = None
51 | return
52 |
53 | def __str__(self):
54 | selflist = []
55 | if self.value == None:
56 | return(str(selflist))
57 |
58 | temp = self
59 | selflist.append(temp.value)
60 |
61 | while temp.next != None:
62 | temp = temp.next
63 | selflist.append(temp.value)
64 |
65 | return(str(selflist))
--------------------------------------------------------------------------------
/W7_L3_user_defined_lists.py:
--------------------------------------------------------------------------------
1 | # Designing our own list
2 | # a list is a sequence of nodes
3 | # Each node store value, points to next node
4 | # final node have value but points to nothing (None)
5 | # empty list have value None and points to None
6 | # singleton list have one value and it points to None
7 |
8 | class Node:
9 |
10 | def __init__(self, initial=None):
11 | self.value = initial
12 | self.next = None
13 |
14 | def isempty(self):
15 | return self.value == None
16 |
17 | def append_recursively(self, v): # append using recursion
18 | if self.isempty():
19 | self.value = v
20 | elif self.next == None:
21 | newnode = Node(v)
22 | self.next = newnode
23 | else:
24 | self.next.append_recursively(v)
25 | return
26 |
27 | def append_iteratively(self, v): # append using iteration
28 | if self.isempty():
29 | self.value = v
30 | return
31 | temp = self
32 | while temp.next != None:
33 | temp = temp.next
34 | newnode = Node(v)
35 | temp.next = newnode
36 | return
37 |
38 | def insert(self, v):
39 | if self.isempty():
40 | self.value = v
41 | return
42 | newnode = Node(v)
43 | self.value, newnode.value = newnode.value, self.value
44 | self.next, newnode.next = newnode, self.next
45 | return
46 |
47 | def delete(self,v): # delete, recursive
48 | if self.isempty():
49 | return
50 | if self.value == v:
51 | self.value = None
52 | if self.next != None:
53 | self.value = self.next.value
54 | self.next = self.next.next
55 | return
56 | else:
57 | if self.next != None:
58 | self.next.delete(v)
59 | if self.next.value == None:
60 | self.next = None
61 | return
62 |
63 | def __str__(self): # To print out the list
64 | selflist = []
65 | if self.value == None:
66 | return(str(selflist))
67 |
68 | temp = self
69 | selflist.append(temp.value)
70 |
71 | while temp.next != None:
72 | temp = temp.next
73 | selflist.append(temp.value)
74 |
75 | return(str(selflist))
76 |
77 |
78 | l1 = Node() # Empty list
79 | print(l1.isempty())
80 | # Output: True
81 |
82 | l2 = Node(5) # Singleton
83 | print(l2.isempty())
84 | # Output: False
85 |
86 | l = Node(0)
87 | print(l)
88 | # [0]
89 | l.append_recursively(20)
90 | print(l)
91 | # [0, 20]
92 | l.append_iteratively(33)
93 | print(l)
94 | # [0, 20, 33]
95 | l.insert(100)
96 | print(l)
97 | # [100, 0, 20, 33]
98 | l.delete(20)
99 | print(l)
100 | # [100, 0, 33]
--------------------------------------------------------------------------------
/W7_L4_PythonCode.py:
--------------------------------------------------------------------------------
1 | class Tree:
2 |
3 | # Empty node has self.value, self.left, self.right = None
4 | # Leaf has self.value != None, and self.left, self.right point to empty node
5 |
6 | # Constructor: create an empty node or a leaf node, depending on initval
7 | def __init__(self,initval=None):
8 | self.value = initval
9 | if self.value:
10 | self.left = Tree()
11 | self.right = Tree()
12 | else:
13 | self.left = None
14 | self.right = None
15 | return
16 |
17 | # Only empty node has value None
18 | def isempty(self):
19 | return (self.value == None)
20 |
21 | # Leaf nodes have both children empty
22 | def isleaf(self):
23 | return (self.left.isempty() and self.right.isempty())
24 |
25 | # Convert a leaf node to an empty node
26 | def makeempty(self):
27 | self.value = None
28 | self.left = None
29 | self.right = None
30 | return
31 |
32 | # Copy right child values to current node
33 | def copyright(self):
34 | self.value = self.right.value
35 | self.left = self.right.left
36 | self.right = self.right.right
37 | return
38 |
39 | # Check if value v occurs in tree
40 | def find(self,v):
41 | if self.isempty():
42 | return(False)
43 |
44 | if self.value == v:
45 | return(True)
46 |
47 | if v < self.value:
48 | return(self.left.find(v))
49 |
50 | if v > self.value:
51 | return(self.right.find(v))
52 |
53 | # Insert value v in tree
54 | def insert(self,v):
55 | if self.isempty():
56 | self.value = v
57 | self.left = Tree()
58 | self.right = Tree()
59 |
60 | if self.value == v:
61 | return
62 |
63 | if v < self.value:
64 | self.left.insert(v)
65 | return
66 |
67 | if v > self.value:
68 | self.right.insert(v)
69 | return
70 |
71 | # Find maximum value in a nonempty tree
72 | def maxval(self):
73 | if self.right.isempty():
74 | return(self.value)
75 | else:
76 | return(self.right.maxval())
77 |
78 | # Delete value v from tree
79 | def delete(self,v):
80 | if self.isempty():
81 | return
82 |
83 | if v < self.value:
84 | self.left.delete(v)
85 | return
86 |
87 | if v > self.value:
88 | self.right.delete(v)
89 | return
90 |
91 | if v == self.value:
92 | if self.isleaf():
93 | self.makeempty()
94 | elif self.left.isempty():
95 | self.copyright()
96 | else:
97 | self.value = self.left.maxval()
98 | self.left.delete(self.left.maxval())
99 | return
100 |
101 | # Inorder traversal
102 | def inorder(self):
103 | if self.isempty():
104 | return([])
105 | else:
106 | return(self.left.inorder()+[self.value]+self.right.inorder())
107 |
108 | # Display Tree as a string
109 | def __str__(self):
110 | return(str(self.inorder()))
--------------------------------------------------------------------------------
/W7_L4_binary_search_trees.py:
--------------------------------------------------------------------------------
1 | # Dynamin sorted data
2 | # sorting is useful for efficient searching
3 | # if the data is changing dynamically:
4 | # - items are periodically inserted and deleted
5 | # - insert/delete in sorted list take time O(n)
6 | # it is inefficient to sort the data again and again, for like binary search
7 | # but in heap with priority queue we can do both efficiently
8 | # thus we can move into a tree like structure
9 |
10 | """ Binary search tree """
11 | # for each node with value v
12 | # - value in left subtree < v
13 | # - value in right subtree > v
14 | # No duplicate values
15 | #Ex: 5
16 | # / \
17 | # 2 8
18 | # / \ \
19 | # 1 4 9
20 | # 2<5, 8>5,, 1<2, 4>2,, 9>8
21 |
22 | # inorder traversal : [1, 2, 4, 5, 8, 9]
23 |
24 | # Left most node in the tree have the minimum value
25 |
26 | # Right most node in the tree have the maximum value
27 |
28 | # Each node have: value, left, right
29 | # Node with 5 is like : 5, node with 2, node with 8
30 | # Node with 8 is like : 8, None, node with 9
31 | # Node with 2 is like : 2, node with 1, node with 4
32 | # Node with 1 is like : 1, None, None
33 |
34 | # leaf node have a value, have left and right, both of which point to empty node
35 | # Empty node : None, None, None
36 | # Empty tree is a single empty node
37 | # This concept makes it easier to write recursive functions to traverse the tree
38 |
39 | class Tree:
40 |
41 | # Empty node has self.value, self.left, self.right = None
42 | # Leaf has self.value != None, and self.left, self.right point to empty node
43 |
44 | # Constructor: create an empty node or a leaf node, depending on initval
45 | def __init__(self,initval=None):
46 | self.value = initval
47 | if self.value:
48 | self.left = Tree()
49 | self.right = Tree()
50 | else:
51 | self.left = None
52 | self.right = None
53 | return
54 |
55 | # Only empty node has value None
56 | def isempty(self):
57 | return (self.value == None)
58 |
59 | # Inorder traversal
60 | def inorder(self):
61 | if self.isempty():
62 | return([])
63 | else:
64 | return(self.left.inorder()+[self.value]+self.right.inorder())
65 |
66 | # Display Tree as a string
67 | def __str__(self):
68 | return(str(self.inorder()))
69 |
70 | # Check if value v occurs in tree
71 | def find(self,v):
72 | if self.isempty():
73 | return(False)
74 |
75 | if self.value == v:
76 | return(True)
77 |
78 | if v < self.value:
79 | return(self.left.find(v))
80 |
81 | if v > self.value:
82 | return(self.right.find(v))
83 |
84 | # Find maximum value in a nonempty tree
85 | def maxval(self):
86 | if self.right.isempty():
87 | return(self.value)
88 | else:
89 | return(self.right.maxval())
90 |
91 | # Find minimum value in a nonempty tree
92 | def minval(self):
93 | if self.left == None:
94 | return self.value
95 | else:
96 | return self.left.minval()
97 |
98 | # Insert value v in tree
99 | def insert(self,v):
100 | if self.isempty():
101 | self.value = v
102 | self.left = Tree()
103 | self.right = Tree()
104 |
105 | if self.value == v:
106 | return
107 |
108 | if v < self.value:
109 | self.left.insert(v)
110 | return
111 |
112 | if v > self.value:
113 | self.right.insert(v)
114 | return
115 |
116 | # Leaf nodes have both children empty
117 | def isleaf(self):
118 | return (self.left.isempty() and self.right.isempty())
119 |
120 | # Convert a leaf node to an empty node
121 | def makeempty(self):
122 | self.value = None
123 | self.left = None
124 | self.right = None
125 | return
126 |
127 | # Copy right child values to current node
128 | def copyright(self):
129 | self.value = self.right.value
130 | self.left = self.right.left
131 | self.right = self.right.right
132 | return
133 |
134 | # Delete value v from tree
135 | def delete(self,v):
136 | if self.isempty():
137 | return
138 |
139 | if v < self.value:
140 | self.left.delete(v)
141 | return
142 |
143 | if v > self.value:
144 | self.right.delete(v)
145 | return
146 |
147 | if v == self.value:
148 | if self.isleaf():
149 | self.makeempty()
150 | elif self.left.isempty():
151 | self.copyright()
152 | else:
153 | self.value = self.left.maxval()
154 | self.left.delete(self.left.maxval())
155 | return
156 |
157 | t = Tree()
158 | print(t)
159 | # []
160 | t.insert(1)
161 | for i in [3, 2, 18, 7, 5, 4, 22, 14]:
162 | t.insert(i)
163 | print(t)
164 | # [1, 2, 3, 4, 5, 7, 14, 18, 22]
165 | t.insert(17)
166 | print(t)
167 | # [1, 2, 3, 4, 5, 7, 14, 17, 18, 22]
168 | t.delete(3)
169 | print(t)
170 | # [1, 2, 4, 5, 7, 14, 17, 18, 22]
171 |
172 | """ Complexity """
173 | # all operations on search trees walk down a single path
174 | # Worst-case : height of tree
175 | # Balanced trees : height is O(log(n)) for n nodes
176 | # Trees can be balanced using rotations - look up AVL trees
177 |
--------------------------------------------------------------------------------
/W7_quiz.py:
--------------------------------------------------------------------------------
1 | """ 1) Given the following permutation of a,b,c,d,e,f,g,h,i,j,
2 | what is the next permutation in lexicographic (dictionary) order?
3 | Write your answer without any blank spaces between letters.
4 | fjadbihgec """
5 |
6 | # Ans) fjadcbeghi # using the finding next permutation
7 |
8 | """ 2) We want to add a function length() to the class Node that implements user
9 | defined lists which will compute the length of a list. An incomplete implementation
10 | of length() given below. You have to provide expressions to put in place of XXX, YYY. and ZZZ.
11 |
12 | def length(self):
13 | if self.value == None:
14 | return(XXX)
15 | elif self.next == None:
16 | return(YYY)
17 | else:
18 | return(ZZZ)
19 |
20 | XXX: 0, YYY: 0, ZZZ: self.next.length()
21 | XXX: 0, YYY: 0, ZZZ: 1 + self.next.length()
22 | XXX: 0, YYY: 1, ZZZ: self.next.length()
23 | XXX: 0, YYY: 1, ZZZ: 1 + self.next.length() """
24 |
25 | # Ans) 4) XXX: 0, YYY: 1, ZZZ: 1 + self.next.length()
26 |
27 | """ 3) Suppose we add this function foo() to the class Tree that implements search trees.
28 | For a name mytree with a value of type Tree, what would mytree.foo() compute?
29 |
30 | def foo(self):
31 | if self.isempty():
32 | return(0)
33 | elif self.isleaf():
34 | return(1)
35 | else:
36 | return(1 + max(self.left.foo(),self.right.foo()))
37 |
38 | The number of nodes in mytree
39 | The largest value in mytree.
40 | The length of the longest path from root to leaf in mytree.
41 | The number of paths in mytree. """
42 |
43 | # Ans) 3) The length of the longest path from root to leaf in mytree.
44 |
45 | """ 4) Inorder traversal of a binary tree has been defined in the lectures.
46 | A preorder traversal lists the vertices of a binary tree (not necessarily a search tree) as follows:
47 | Print the root.
48 | Print the left subtree in preorder.
49 | Print the right subtree in preorder.
50 | Suppose we have a binary tree with 10 nodes labelled a, b, c, d, e, f, g, h, i, j, with
51 | preorder traversal gbhecidajf and inorder traversal ehbicgjafd. What is the right child of the root node? """
52 |
53 | # Ans) 'd'
--------------------------------------------------------------------------------
/W8_L1_memoization_dynamic_programming.py:
--------------------------------------------------------------------------------
1 | # Inductive definitions directly gives recursive programs
2 | # fact(n-1) is a subproblem of fact(n)
3 | # so are fact(n-2), fact(n-3) etc fact(0)
4 | # isort([x2,...,xn]) is a subproblem of isort([x1,x2,...,xn])
5 |
6 | def fib(n):
7 | if n==0 or n==1:
8 | value = n
9 | else:
10 | value = fib(n-1) + fib(n-2)
11 | return value
12 |
13 | print(fib(4))
14 |
15 | # Here we can see that in fib(n-1) and fib(n-2) some calls
16 | # are getting repeated but done again....like, fib(2) , fib(3) etc
17 |
18 | # Thus there is an overlapping subproblems
19 | # - wasterful recomputation
20 | # - computation tree grows exponentially
21 |
22 | # we should avoid this...never re-evaluate a subproblem
23 | # build a table of values already computed
24 | # - memonry table
25 | # - memoizatioin
26 | # store each newly computed value in a table
27 |
28 | def memoized_fib(n):
29 | fibtable = {}
30 | if n in fibtable:
31 | return fibtable[n]
32 | if n==0 or n==1:
33 | value = n
34 | else:
35 | value = fib(n-1) + fib(n-2)
36 | fibtable[n] = value
37 | return value
38 |
39 | """ Dynamic programming """
40 | # Dynamic Programming is a technique in computer programming that helps to efficiently solve
41 | # a class of problems that have overlapping subproblems and optimal substructure property.
42 |
43 | def dynamic_fib(n):
44 | fibtable = {}
45 | fibtable[0] = 0
46 | fibtable[1] = 1
47 | for i in range(2, n+1):
48 | fibtable[i] = fibtable[i-1] + fibtable[i-2]
49 | return fibtable[n]
50 |
--------------------------------------------------------------------------------
/W8_L4_matrix_multiplication.py:
--------------------------------------------------------------------------------
1 | # Matrix multiplication is associative
2 | # ABC = (AB)C = A(BC)
3 | # Bracketing doesn't change answer...
4 | # but changes the complexity of computing
5 | # How?
6 | # Assume A[1,100], B[100,1], C[1,100]
7 | # computing A(BC)
8 | # - BC is [100,100], 100 x 1 x 100 = 10000 steps
9 | # - A(BC) is [1,100], 1 x 100 x 100 = 10000 steps
10 | # computing (AB)C
11 | # - AB is [1,1], 1 x 100 x 1 = 100 steps
12 | # - (AB)C is [1,100], 1 x 1 x 100 = 100 steps
13 | # A(BC) takes 20000 steps
14 | # (AB)C takes 200 steps
--------------------------------------------------------------------------------
/W8_L5_Wrap_up.py:
--------------------------------------------------------------------------------
1 | # Only some difference in python compared to other
2 | # programming language
--------------------------------------------------------------------------------
/W8_programming_assignment.py:
--------------------------------------------------------------------------------
1 | def solve(l1, l2):
2 | n = len(l1)
3 |
4 | if n == 0:
5 | return (0)
6 |
7 | ans = [0 for i in range(n + 1)]
8 |
9 | ans[n - 1] = max(l1[n - 1], l2[n - 1]) - min(l1[n - 1], l2[n - 1])
10 |
11 | for i in range(n - 2, -1, -1):
12 | vert = max(l1[i], l2[i]) - min(l1[i], l2[i]) + ans[i + 1]
13 | horz = max(l1[i], l1[i + 1]) - min(l1[i], l1[i + 1]) + max(l2[i], l2[i + 1]) - min(l2[i], l2[i + 1]) + ans[
14 | i + 2]
15 | ans[i] = max(vert, horz)
16 |
17 | return (ans[0])
18 |
19 |
20 | nstr = input()
21 | line1str = input().strip()
22 | line1strlist = line1str.split()
23 | line1 = []
24 | for s in line1strlist:
25 | line1.append(int(s))
26 |
27 | line2str = input().strip()
28 | line2strlist = line2str.split()
29 | line2 = []
30 | for s in line2strlist:
31 | line2.append(int(s))
32 |
33 | print(solve(line1, line2))
34 |
--------------------------------------------------------------------------------