added some algorithms, especially for sorting, trees and linked lists

This commit is contained in:
Ane 2022-05-19 09:49:10 +02:00
parent f3f2c3dea4
commit 4c34cd26a7
9 changed files with 347 additions and 2 deletions

View File

@ -0,0 +1,15 @@
# https://leetcode.com/problems/palindrome-linked-list/discuss/64500/11-lines-12-with-restore-O(n)-time-O(1)-space
def isPalindrome(head) -> bool:
rev = None
slow = fast = head
while fast and fast.next:
fast = fast.next.next
rev, rev.next, slow = slow, rev, slow.next
if fast:
slow = slow.next
while rev and rev.val == slow.val:
rev = rev.next
slow = slow.next
return not rev

View File

@ -0,0 +1,14 @@
# https://leetcode.com/problems/remove-nth-node-from-end-of-list/discuss/8802/3-short-Python-solutions
class Solution:
def removeNthFromEnd(self, head, n):
slow = fast = head
for _ in range(n):
fast = fast.next
if not fast:
return head.next
while fast.next:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return head

View File

@ -0,0 +1,72 @@
# Find Maximum depth of binary tree
[LeetCode problem](https://leetcode.com/problems/maximum-depth-of-binary-tree/)
Given the root of a binary tree, return its maximum depth. A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
![ ](https://assets.leetcode.com/uploads/2020/11/26/tmp-tree.jpg)
Example: input: [3,9,20,null,null,15,7], output: 3.
## LeetCode initial code
```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
```
## Recursive approach
Depth first
```python
def maxDepth(self, root: Optional[TreeNode]) -> int:
def max_depth(root, depth):
if not root: return depth
return max(max_depth(root.left, depth+1), max_depth(root.right, depth+1))
return max_depth(root, 0)
```
## Iterative solution
Breadth first
```python
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
queue = [root]
depth = 0
while True:
if not queue:
break
node_count = len(queue)
depth += 1
while node_count > 0:
node = queue[0]
queue.pop(0)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
node_count -= 1
return depth
```

View File

@ -0,0 +1,55 @@
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
# checks if tree is symmetric
# https://leetcode.com/problems/symmetric-tree/
# recursive approach, depth first
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def symm(root1, root2):
if not root1 and not root2:
return True
if not root1 or not root2 or root1.val != root2.val:
return False
return symm(root1.left, root2.right) and symm(root1.right, root2.left)
if not root:
return True
return symm(root.left, root.right)
# iterative approach, breadth first
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
queue = [(root.left, root.right)]
while True:
if not queue:
return True
count = len(queue)
while count > 0:
root1, root2 = queue[0]
queue.pop(0)
if not root1 and not root2:
return True
if not root1 or not root2 or root1.val != root2.val:
return False
if root1.left or root2.right:
queue.append((root1.left, root2.right))
if root1.right or root2.left:
queue.append((root1.right, root2.left))
count -= 1

View File

@ -8,11 +8,29 @@
Start at the beginning, swap the first two elements if the first is greater than the second. Go to the next pair and repeat, and so on until reaching the end of the array.
```python
nums = [2, 1, 4, 6, 3, 8, 0]
for k in range(len(nums)-1):
for i in range(len(nums) - k - 1):
if nums[i] > nums[i+1]:
nums[i], nums[i+1] = nums[i+1], nums[i]
```
### Selection sort
> Runtime O(n<sup>2</sup>) average and worst case. Memory O(1)
Simple but inefficient. Find the smallest element using a linear scan, move it to the front, swapping it with the first element. Then, find the second smallest and move it, doing a linear scan. And so on
Simple but inefficient. Find the smallest element using a linear scan, move it to the front, swapping it with the first element. Then, find the second smallest and move it, doing a linear scan. And so on.
```python
nums = [2, 1, 4, 6, 3, 8, 0]
for i in range(len(nums)):
min_pos = i
for j in range(i+1, len(nums)):
if nums[j] < nums[min_pos]:
min_pos = j
nums[i], nums[min_pos] = nums[min_pos], nums[i]
```
### Merge sort
@ -24,8 +42,44 @@ When merging, copy all the elements from the target array segment into a helper
Java algorithm in book.
```python
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr)//2
left = arr[:mid]
right = arr[mid:]
merge_sort(left)
merge_sort(right)
i, j, k = 0, 0, 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
arr[k] = left[i]
i += 1
else:
arr[k] = right[j]
j += 1
k += 1
while i < len(left):
arr[k] = left[i]
i += 1
k += 1
while j < len(right):
arr[k] = right[j]
j += 1
k += 1
return arr
```
### Quick sort
Similar to merge sort, divide and conquer.
> Runtime O(n log(n)) average, O(n<sup>2</sup>) worst case. Memory O(n log(n))
Pick a random element and partition the array, such that all numbers lower than the partitioning element come before all elements greater than it. Repeatedly partitioning the array (and its sub-arrays) around an element, the array is eventually sorted. But as the partitioned element is not guaranteed to be the median or close to it, the sorting could be very slow. That is why the worst case rutime is O(n<sup>2</sup>).
@ -83,7 +137,7 @@ def binarySearch(arr, x):
l = 0
r = len(arr) - 1
while l <= r:
mid = l + (r - l) // 2;
mid = l + (r - l) // 2
if arr[mid] == x:
return mid

View File

@ -0,0 +1,33 @@
# binary search in sorted array
# recursive
def binary_search_rec(nums, target, pos0, pos1):
if pos0 <= pos1:
midpoint = (pos0+pos1)//2
if target == nums[midpoint]:
return midpoint
elif target > nums[midpoint]:
return binary_search_rec(nums, target, midpoint+1, pos1)
elif target < nums[midpoint]:
return binary_search_rec(nums, target, pos0, midpoint-1)
else:
return -1
# iterative
def binary_search_iter(nums, target, pos0, pos1):
while True:
if pos0 <= pos1:
midpoint = (pos0+pos1)//2
if target == nums[midpoint]:
return midpoint
elif target > nums[midpoint]:
pos0 = midpoint + 1
elif target < nums[midpoint]:
pos1 = midpoint - 1
else:
return -1
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
target = 4
res = binary_search_iter(nums, target, 0, len(nums)-1)
print(res)

View File

@ -0,0 +1,22 @@
# efficient for small data values
def insertionSort(arr):
# Traverse through 1 to len(arr)
for i in range(1, len(arr)):
key = arr[i]
# Move elements of arr[0..i-1], that are
# greater than key, to one position ahead
# of their current position
j = i-1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
# Driver code to test above
arr = [12, 11, 13, 5, 6]
insertionSort(arr)
print(arr)

View File

@ -0,0 +1,35 @@
def merge_sort(nums):
if len(nums) > 1:
mid = len(nums)//2
left = nums[:mid]
right = nums[mid:]
merge_sort(left)
merge_sort(right)
i, j, k = 0, 0, 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
nums[k] = left[i]
i += 1
else:
nums[k] = right[j]
j += 1
k += 1
# finish merging remaining elements
while i < len(left):
nums[k] = left[i]
i += 1
k += 1
while j < len(right):
nums[k] = right[j]
j += 1
k += 1
return nums
nums = [5, 4, 2, 1]
res = merge_sort(nums)
print(res)

View File

@ -0,0 +1,45 @@
# Function to find the partition position
def partition(array, low, high):
# Choose the rightmost element as pivot
pivot = array[high]
# Pointer for greater element
i = low - 1
# Traverse through all elements
# compare each element with pivot
for j in range(low, high):
if array[j] <= pivot:
# If element smaller than pivot is found
# swap it with the greater element pointed by i
i += 1
# Swapping element at i with element at j
array[i], array[j] = array[j], array[i]
# Swap the pivot element with the greater element specified by i
array[i + 1], array[high] = array[high], array[i + 1]
# Return the position from where partition is done
return i + 1
# Function to perform quicksort
def quick_sort(array, low, high):
if low < high:
# Find pivot element such that
# element smaller than pivot are on the left
# element greater than pivot are on the right
pi = partition(array, low, high)
# Recursive call on the left of pivot
quick_sort(array, low, pi-1)
# Recursive call on the right of pivot
quick_sort(array, pi+1, high)
# Driver code
array = [3, 5, 4, 2, 1, 6] # 10, 7, 8, 9, 1, 5
quick_sort(array, 0, len(array)-1)
print(f'Sorted array: {array}')