- 二分法的继续执行条件用:
l <= r
,因为如果只有一个元素,那么l == r,如果不包含等号,那么就会跳过这个元素 - 用left表示大于等于当前left的都是满足条件的,用right表示小于当前right的都是满足条件的
- 如果 left > right,那么说明所有元素都不满足条件
Refer to https://swsmile.info/post/sorting-algorithm/
算法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 排序方式 | 稳定性 | 备注 |
---|---|---|---|---|---|---|---|
冒泡排序 | $O(N^2)$ | $O(N)$ | $O(N^2)$ | $O(1)$ | In-place | 稳定 | |
选择排序 | $O(N^2)$ | $O(N^2)$ | $O(N^2)$ | $O(1)$ | In-place | 稳定 | |
插入排序 | $O(N^2)$ | $O(N)$ | $O(N^2)$ | $O(1)$ | In-place | 稳定 | 时间复杂度和初始顺序有关 |
希尔排序(Shell Sort) | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $$O(N^2)$ | $O(1)$ | In-place | 不稳定 | 改进版插入排序 |
归并排序(Merge Sort) | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $O(N)$ | Out-place | 不稳定 | |
快速排序 | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $O(N^2)$ | $O(1)$ | In-place | 不稳定 | |
堆排序(Heap Sort) | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $O(Nlog_2N)$ | $O(1)$ | In-place | 不稳定 | |
桶排序 (bucke sort) | O(N) | O(N) | $O(N^2)$ or $O(Nlog_2N)$ | $O(N)$ | Out-place | 稳定 | 最坏时间复杂度取决于对于桶内元素进行排序的算法 |
def bubbleSort(arr):
n = len(arr)
# Traverse through all array elements
for i in range(n-1):
# Last i elements are already in place
for j in range(0, n-i-1):
# Traverse the array from 0 to n-i-1
# Swap if the element found is greater than the next element
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
# Example usage
arr = [64, 34, 25, 12, 22, 11, 90]
bubbleSort(arr)
print("Sorted array is:")
for i in range(len(arr)):
print("%d" % arr[i], end=" ")
def quick_sort(arr):
# Base case: an array with 0 or 1 elements is already sorted
if len(arr) <= 1:
return arr
# Choosing the pivot element from the array
pivot = arr[len(arr) // 2]
# Elements less than pivot
left = [x for x in arr if x < pivot]
# Elements equal to pivot
middle = [x for x in arr if x == pivot]
# Elements greater than pivot
right = [x for x in arr if x > pivot]
# Recursively sort the left and right parts and combine them with the middle
return quick_sort(left) + middle + quick_sort(right)
# Example usage
array = [3, 6, 8, 10, 1, 2, 1]
sorted_array = quick_sort(array)
print(sorted_array)
def heapify(arr, n, i):
largest = i # Initialize largest as root
left = 2 * i + 1 # left child
right = 2 * i + 2 # right child
# See if left child of root exists and is greater than root
if left < n and arr[i] < arr[left]:
largest = left
# See if right child of root exists and is greater than root
if right < n and arr[largest] < arr[right]:
largest = right
# Change root, if needed
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i] # swap
# Heapify the root.
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
# One by one extract elements
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # swap
heapify(arr, i, 0)
# Example usage
arr = [12, 11, 13, 5, 6, 7]
heapSort(arr)
print("Sorted array is:", arr)
def bucketSort(arr):
# Find maximum value in the array and use length of the array to determine which value in the array goes into which bucket
max_value = max(arr)
size = max_value/len(arr)
# Create n empty buckets where n is equal to the length of the array
buckets_list= [[] for _ in range(len(arr))]
# Put array elements in different buckets based on size
for i in range(len(arr)):
j = int(arr[i] / size)
if j != len (arr):
buckets_list[j].append(arr[i])
else:
buckets_list[len(arr) - 1].append(arr[i])
# Sort elements within the buckets using Insertion Sort
for z in range(len(arr)):
insertionSort(buckets_list[z])
# Concatenate buckets with sorted elements into a single array
final_output = []
for x in range(len(arr)):
final_output = final_output + buckets_list[x]
return final_output
def insertionSort(b):
for i in range(1, len(b)):
up = b[i]
j = i - 1
while j >=0 and b[j] > up:
b[j + 1] = b[j]
j -= 1
b[j + 1] = up
return b
# Example usage
arr = [0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434]
print("Sorted Array is")
print(bucketSort(arr))
https://www.youtube.com/watch?v=TGveA1oFhrc
https://www.youtube.com/watch?v=Kk6mXAzqX3Y
nums = [73, 74, 75, 71, 69, 72, 76, 73]
stack = [] # (n, idx), mono decreasing stack
res = [0] * len(nums) # if there is no clement larger than the current element, the distance is 0
for idx, num in enumerate(nums):
while stack and stack[-1][0] < num:
_, pre_idx = stack.pop()
res[pre_idx] = idx - pre_idx
# print(idx, pre_idx)
# print("while stack", stack)
stack.append((num, idx))
# print("not while stack", stack)
return res
def isValid(self, s):
stack = []
m = {"(": ")", "{": "}", "[": "]"}
for char in s:
if char in m:
stack.append(char)
else:
if len(stack) == 0 or char != m[stack[-1]]:
return False
stack.pop()
return len(stack) == 0
给定一个只包含 "()[]{}" 六种字符的字符串。规定它们的优先级由外至内为:"{}", "[]", "()",同一级的可以嵌套,并列。要求判断给定的字符串是否是合法的括号字串?
例:"()", "{((()())())[()]}()" 是合法的。"())", "([])", "())(()" 都是不合法的。
({})
样例1:
[输入]
"{((()())())[()]}()"
[输出]
True
解法
# ()[] OK
# {[()]} OK
# {([]{})} !OK
def isValidString(str):
stack = [] # space: O(n)
cur_max_priority = 0
m = {"(": ")", "{": "}", "[": "]"}
priority_m = {"{": 1, "[": 2, "(": 3}
for c in str: # time: O(n)
if c in m: # e.g., {, [, (
stack.append(c)
cur_max_priority = max(cur_max_priority, priority_m[c])
if priority_m[c] < cur_max_priority: # {([
return False
else: # e.g., ], }, )
if len(stack) == 0: # e.g., ]]]]
return False
top_element = stack.pop(-1)
if c != m[top_element]: # [}
return False
if stack:
cur_max_priority = priority_m[stack[-1]]
else: # reset priority
cur_max_priority = 0
return len(stack) == 0
def generateParenthesis(self, n: int) -> List[str]:
res = []
stack = []
def backTracking(openCountUsed, closeCountUsed):
if openCountUsed == closeCountUsed == n: # All open and close have been used
res.append("".join(stack))
return
if openCountUsed < n: # Still have open to be used
stack.append("(")
backTracking(openCountUsed + 1, closeCountUsed)
stack.pop(-1)
if closeCountUsed < openCountUsed: # Able to add a close, e.g., "(()", and not able to add a close if like "()"
stack.append(")")
backTracking(openCountUsed, closeCountUsed + 1)
stack.pop(-1)
backTracking(0, 0)
return res
ref
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token == "+":
res = stack.pop(-1) + stack.pop(-1)
stack.append(res)
elif token == "-":
# e.g., ["13","5","/"] -> 13/5
n1 = stack.pop(-1) # 5
n2 = stack.pop(-1) # 13
stack.append(n2 - n1)
elif token == "*":
res = stack.pop(-1) * stack.pop(-1)
stack.append(res)
elif token == "/":
n1 = stack.pop(-1) # 5
n2 = stack.pop(-1) # 13
stack.append(int(n2 / n1)) # The division between two integers always truncates toward zero.
else:
stack.append(int(token))
return stack[-1]
class MinStack:
def __init__(self):
self.stack = [] # [cur_element, cur_min]
def push(self, val: int) -> None:
curMin = val
if len(self.stack) > 0:
curMin = min(curMin, self.stack[-1][1])
self.stack.append([val, curMin])
def pop(self) -> None:
return self.stack.pop(-1)[0]
def top(self) -> int:
return self.stack[-1][0]
def getMin(self) -> int:
return self.stack[-1][1]
ref
# solution 1 - 两个 queue
class MyStack(object):
def __init__(self):
# space: O(n)
self.queue1 = [] # queue1 用于存储栈内的元素
self.queue2 = [] # queue 作为入栈操作的辅助队列。
# time: O(n)
def push(self, x):
# 入栈操作时,首先将元素入队到 queue2 ,然后将 queue1 的全部元素依次出队并入队到 queue2,此时 queue2的左端的元素即为新入栈的元素,
# 再将 queue1 和 queue2 互换,则 queue1 的元素即为栈内的元素,queue1 的左端和右端分别对应栈顶和栈底。
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1.pop(0))
self.queue1, self.queue2 = self.queue2, self.queue1
# 由于每次入栈操作都确保 queue1 的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。
# 出栈操作只需要移除 queue1 的前端元素并返回即可,获得栈顶元素操作只需要获得 queue1 的前端元素并返回即可(不移除元素)。
def pop(self):
return self.queue1.pop(0)
def top(self):
return self.queue1[0]
def empty(self):
# 由于 queue1 用于存储栈内的元素,判断栈是否为空时,只需要判断 queue1 是否为空即可。
return not self.queue1
# solution 2 - 一个 queue
class MyStack(object):
def __init__(self):
# space: O(n)
self.queue = []
# time: O(n)
def push(self, x):
n = len(self.queue)
self.queue.append(x)
for _ in range(n):
self.queue.append(self.queue.pop(0))
def pop(self):
return self.queue.pop(0)
def top(self):
return self.queue[0]
def empty(self):
return not self.queue
ref
class MyQueue:
def __init__(self):
# space: O(n). 最差情况下,栈 A 和 B 共保存 N 个元素。
self.inStack = []
self.outStack = []
# time: O(1)
def push(self, x: int) -> None:
self.inStack.append(x)
# pop 和 peek 为均摊 O(1)。对于每个元素,至多入栈和出栈各两次,故均摊复杂度为 O(1)
def pop(self) -> int:
self.peek()
return self.outStack.pop()
# pop 和 peek 为均摊 O(1)。对于每个元素,至多入栈和出栈各两次,故均摊复杂度为 O(1)
def peek(self) -> int:
if not self.outStack:
while self.inStack:
self.outStack.append(self.inStack.pop(-1))
return self.outStack[-1]
# time: O(1)
def empty(self) -> bool:
return not self.inStack and not self.outStack
ref