{"id":38249194,"url":"https://github.com/peterlamar/python-cp-cheatsheet","last_synced_at":"2026-01-17T01:26:06.451Z","repository":{"id":39254056,"uuid":"285307360","full_name":"peterlamar/python-cp-cheatsheet","owner":"peterlamar","description":"Python3 interview prep cheatsheet and examples","archived":false,"fork":false,"pushed_at":"2024-11-30T12:39:41.000Z","size":358,"stargazers_count":709,"open_issues_count":0,"forks_count":148,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-30T13:33:13.717Z","etag":null,"topics":["competitive-programming","faang-interview","interview","leetcode","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peterlamar.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-05T14:09:59.000Z","updated_at":"2024-11-30T12:39:46.000Z","dependencies_parsed_at":"2024-12-01T16:49:48.416Z","dependency_job_id":null,"html_url":"https://github.com/peterlamar/python-cp-cheatsheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/peterlamar/python-cp-cheatsheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterlamar%2Fpython-cp-cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterlamar%2Fpython-cp-cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterlamar%2Fpython-cp-cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterlamar%2Fpython-cp-cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peterlamar","download_url":"https://codeload.github.com/peterlamar/python-cp-cheatsheet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterlamar%2Fpython-cp-cheatsheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28491479,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T00:50:05.742Z","status":"ssl_error","status_checked_at":"2026-01-17T00:43:11.982Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["competitive-programming","faang-interview","interview","leetcode","python3"],"created_at":"2026-01-17T01:26:06.297Z","updated_at":"2026-01-17T01:26:06.434Z","avatar_url":"https://github.com/peterlamar.png","language":"Python","readme":"Python3 reference for interview coding problems/light competitive programming. Contributions welcome!\n\n## How\n\nI built this cheatsheet while teaching myself Python3 for various interviews and leetcoding for fun after not using Python for about a decade. This cheetsheet only contains code that I didn't know but needed to use to solve a specific coding problem. I did this to try to get a smaller high frequency subset of Python vs a comprehensive list of all methods. Additionally, the act of recording the syntax and algorithms helped me store it in memory and as a result I almost never actually referenced this sheet. Hopefully it helps you in your efforts or inspires you to build your own and best of luck!\n\n## Why\n\nThe [rule of least power](https://en.wikipedia.org/wiki/Rule_of_least_power)\n\nI choose Python3 despite being more familiar with Javascript, Java, C++ and Golang for interviews as I felt Python had the combination of the most standard libraries available as well as syntax that resembles psuedo code, therefore being the most expressive. Python and Java both have the most examples but Python wins in this case due to being much more concise. I was able to get myself reasonably prepared with Python syntax in six weeks of practice. After picking up Python I have timed myself solving the same exercises in Golang and Python. Although I prefer Golang, I find that I can complete Python examples in half the time even accounting for +50% more bugs (approximately) that I tend to have in Python vs Go. This is optimizing for solved interview questions under pressure, when performance is considered then Go/C++ does consistently perform 1/10 the time of Python. In some rare cases, algorithms that time out in Python sometimes pass in C++/Go on Leetcode.\n\n[Language Mechanics](#language-mechanics)\n\n1. [Literals](#literals)\n1. [Loops](#loops)\n1. [Strings](#strings)\n1. [Slicing](#slicing)\n1. [Tuples](#tuple)\n1. [Sort](#sort)\n1. [Hash](#hash)\n1. [Set](#set)\n1. [List](#list)\n1. [Dict](#dict)\n1. [Binary Tree](#binarytree)\n1. [heapq](#heapq)\n1. [lambda](#lambda)\n1. [zip](#zip)\n1. [Random](#random)\n1. [Constants](#constants)\n1. [Ternary Condition](#ternary)\n1. [Bitwise operators](#bitwise-operators)\n1. [For Else](#for-else)\n1. [Modulo](#modulo)\n1. [any](#any)\n1. [all](#all)\n1. [bisect](#bisect)\n1. [math](#math)\n1. [iter](#iter)\n1. [map](#map)\n1. [filter](#filter)\n1. [reduce](#reduce)\n1. [itertools](#itertools)\n1. [regular expression](#regular-expression)\n1. [Types](#types)\n1. [Grids](#grids)\n\n[Collections](#collections)\n\n1. [Deque](#deque)\n1. [Counter](#counter)\n1. [Default Dict](#default-dict)\n\n[Algorithms](#algorithms)\n\n1. [General Tips](#general-tips)\n1. [Binary Search](#binary-search)\n1. [Topological Sort](#topological-sort)\n1. [Sliding Window](#sliding-window)\n1. [Tree Tricks](#tree-tricks)\n1. [Binary Search Tree](#binary-search-tree)\n1. [Anagrams](#anagrams)\n1. [Dynamic Programming](#dynamic-programming)\n1. [Cyclic Sort](#cyclic-sort)\n1. [Quick Sort](#quick-sort)\n1. [Merge Sort](#merge-sort)\n1. [Merge K Sorted Arrays](#merge-arrays)\n1. [Linked List](#linked-list)\n1. [Convert Base](#convert-base)\n1. [Parenthesis](#parenthesis)\n1. [Max Profit Stock](#max-profit-stock)\n1. [Shift Array Right](#shift-array-right)\n1. [Continuous Subarrays with Sum k ](#continuous-subarrays-with-sum-k)\n1. [Events](#events)\n1. [Merge Meetings](#merge-meetings)\n1. [Trie](#trie)\n1. [Kadane's Algorithm - Max subarray sum](#kadane)\n1. [Union Find/DSU](#union-find)\n1. [Fast Power](#fast-power)\n1. [Fibonacci Golden](#fibonacci-golden)\n1. [Basic Calculator](#basic-calculator)\n1. [Reverse Polish](#reverse-polish)\n1. [Resevior Sampling](#resevior-sampling)\n1. [Candy Crush](#candy-crush)\n\n# Language Mechanics\n\n## Literals\n\n```python\n255, 0b11111111, 0o377, 0xff # Integers (decimal, binary, octal, hex)\n123.0, 1.23                  # Float\n7 + 5j, 7j                   # Complex\n'a', '\\141', '\\x61'          # Character (literal, octal, hex)\n'\\n', '\\\\', '\\'', '\\\"'       # Newline, backslash, single quote, double quote\n\"string\\n\"                   # String of characters ending with newline\n\"hello\"+\"world\"              # Concatenated strings\nTrue, False                  # bool constants, 1 == True, 0 == False\n[1, 2, 3, 4, 5]              # List\n['meh', 'foo', 5]            # List\n(2, 4, 6, 8)                 # Tuple, immutable\n{'name': 'a', 'age': 90}     # Dict\n{'a', 'e', 'i', 'o', 'u'}    # Set\nNone                         # Null var\n```\n\n## Loops\n\nGo through all elements\n\n```python\ni = 0\nwhile i \u003c len(str):\n  i += 1\n```\n\nequivalent\n\n```python\nfor i in range(len(message)):\n  print(i)\n```\n\nGet largest number index from right\n\n```python\nwhile i \u003e 0 and nums [i-1] \u003e= nums[i]:\n  i -= 1\n```\n\nManually reversing\n\n```python\nl, r = i, len(nums) - 1\nwhile l \u003c r:\n  nums[l], nums[r] = nums[r], nums[l]\n  l += 1\n  r -= 1\n```\n\nGo past the loop if we are clever with our boundry\n\n```python\nfor i in range(len(message) + 1):\n  if i == len(message) or message[i] == ' ':\n```\n\nFun with Ranges - range(start, stop, step)\n\n```python\nfor a in range(0,3): # 0,1,2\nfor a in reversed(range(0,3)) # 2,1,0\nfor i in range(3,-1,-1) # 3,2,1,0\nfor i in range(len(A)//2): # A = [0,1,2,3,4,5]\n  print(i) # 0,1,2\n  print(A[i]) # 0,1,2\n  print(~i) # -1,-2,-3\n  print(A[~i]) # 5,4,3\n```\n\n## Strings\n\n```python\nstr1.find('x')          # find first location of char x and return index\nstr1.rfind('x')         # find first int location of char x from reverse\n```\n\nParse a log on \":\"\n\n```python\nl = \"0:start:0\"\ntokens = l.split(\":\")\nprint(tokens) # ['0', 'start', '0']\n```\n\nReverse works with built in split, [::-1] and \" \".join()\n\n```python\n# s = \"the sky  is blue\"\ndef reverseWords(self, s: str) -\u003e str:\n  wordsWithoutWhitespace = s.split() # ['the', 'sky', 'is', 'blue']\n  reversedWords = wordsWithoutWhitespace[::-1] # ['blue', 'is', 'sky', 'the']\n  final = \" \".join(reversedWords) # blue is sky the\n```\n\nManual split based on isalpha()\n\n```python\ndef splitWords(input_string) -\u003e list:\n  words = [] #\n  start = length = 0\n  for i, c in enumerate(input_string):\n     if c.isalpha():\n       if length == 0:\n          start = i\n          length += 1\n     else:\n        if length !=0:\n\t   words.append(input_string[start:start+length])\n           length = 0\n  if length \u003e 0:\n    words.append(input_string[start:start+length])\n  return words\n```\n\nTest type of char\n\n```python\ndef rotationalCipher(input, rotation_factor):\n  rtn = []\n  for c in input:\n    if c.isupper():\n      ci = ord(c) - ord('A')\n      ci = (ci + rotation_factor) % 26\n      rtn.append(chr(ord('A') + ci))\n    elif c.islower():\n      ci = ord(c) - ord('a')\n      ci = (ci + rotation_factor) % 26\n      rtn.append(chr(ord('a') + ci))\n    elif c.isnumeric():\n      ci = ord(c) - ord('0')\n      ci = (ci + rotation_factor) % 10\n      rtn.append(chr(ord('0') + ci))\n    else:\n      rtn.append(c)\n  return \"\".join(rtn)\n```\n\nAlphaNumberic\n\n```python\nisalnum()\n```\n\nGet charactor index\n\n```python\nprint(ord('A')) # 65\nprint(ord('B')-ord('A')+1) # 2\nprint(chr(ord('a') + 2)) # c\n```\n\nReplace characters or strings\n\n```python\ndef isValid(self, s: str) -\u003e bool:\n  while '[]' in s or '()' in s or '{}' in s:\n    s = s.replace('[]','').replace('()','').replace('{}','')\n  return len(s) == 0\n```\n\nInsert values in strings\n\n```python\ntxt3 = \"My name is {}, I'm {}\".format(\"John\",36) # My name is John, I'm 36\n```\n\nMultiply strings/lists with \\*, even booleans which map to True(1) and False(0)\n\n```python\n'meh' * 2 # mehmeh\n['meh'] * 2 # ['meh', 'meh']\n['meh'] * True #['meh']\n['meh'] * False #[]\n```\n\nFind substring in string\n\n```python\ntxt = \"Hello, welcome to my world.\"\nx = txt.find(\"welcome\")  # 7\n```\n\nstartswith and endswith are very handy\n\n```python\nstr = \"this is string example....wow!!!\"\nstr.endswith(\"!!\") # True\nstr.startswith(\"this\") # True\nstr.endswith(\"is\", 2, 4) # True\n```\n\nPython3 format strings\n\n```python\nname = \"Eric\"\nprofession = \"comedian\"\naffiliation = \"Monty Python\"\nmessage = (\n     f\"Hi {name}. \"\n     f\"You are a {profession}. \"\n     f\"You were in {affiliation}.\"\n)\nmessage\n'Hi Eric. You are a comedian. You were in Monty Python.'\n```\n\nPrint string with all chars, useful for debugging\n\n```python\nprint(repr(\"meh\\n\"))     # 'meh\\n'\n```\n\n## Slicing\n\nSlicing [intro](https://stackoverflow.com/questions/509211/understanding-slice-notation)\n\n```python\n                +---+---+---+---+---+---+\n                | P | y | t | h | o | n |\n                +---+---+---+---+---+---+\nSlice position: 0   1   2   3   4   5   6\nIndex position:   0   1   2   3   4   5\np = ['P','y','t','h','o','n']\np[0] 'P' # indexing gives items, not lists\nalpha[slice(2,4)] # equivalent to p[2:4]\np[0:1] # ['P'] Slicing gives lists\np[0:5] # ['P','y','t','h','o'] Start at beginning and count 5\np[2:4] = ['t','r'] # Slice assignment  ['P','y','t','r','o','n']\np[2:4] = ['s','p','a','m'] # Slice assignment can be any size['P','y','s','p','a','m','o','n']\np[4:4] = ['x','y'] # insert slice ['P','y','t','h','x','y','o','n']\np[0:5:2] # ['P', 't', 'o'] sliceable[start:stop:step]\np[5:0:-1] # ['n', 'o', 'h', 't', 'y']\n```\n\nGo through num and get combinations missing a member\n\n```python\nnumList = [1,2,3,4]\nfor i in range(len(numList)):\n    newList = numList[0:i] + numList[i+1:len(numList)]\n    print(newList) # [2, 3, 4], [1, 3, 4], [1, 2, 4], [1, 2, 3]\n```\n\n## Tuple\n\nCollection that is ordered and unchangable\n\n```python\nthistuple = (\"apple\", \"banana\", \"cherry\")\nprint(thistuple[1]) # banana\n```\n\nCan be used with Dicts\n\n```python\ndef groupAnagrams(self, strs: List[str]) -\u003e List[List[str]]:\n    d = defaultdict(list)\n    for w in strs:\n        key = tuple(sorted(w))\n        d[key].append(w)\n    return d.values()\n```\n\n## Sort\n\nsorted(iterable, key=key, reverse=reverse)\n\nSort sorts alphabectically, from smallest to largest\n\n```python\nprint(sorted(['Ford', 'BMW', 'Volvo'])) # ['BMW', 'Ford', 'Volvo']\nnums = [-4,-1,0,3,10]\nprint(sorted(n*n for n in nums)) # [0,1,9,16,100]\n```\n\n```python\ncars = ['Ford', 'BMW', 'Volvo']\ncars.sort() # returns None type\ncars.sort(key=lambda x: len(x) ) # ['BMW', 'Ford', 'Volvo']\nprint(sorted(cars, key=lambda x:len(x))) # ['BMW', 'Ford', 'Volvo']\n```\n\nSort key by value, even when value is a list\n\n```python\nmeh = {'a':3,'b':0,'c':2,'d':-1}\nprint(sorted(meh, key=lambda x:meh[x])) # ['d', 'b', 'c', 'a']\nmeh = {'a':[0,3,'a'],'b':[-2,-3,'b'],'c':[2,3,'c'],'d':[-2,-2,'d']}\nprint(sorted(meh, key=lambda x:meh[x])) # ['b', 'd', 'a', 'c']\n```\n\n```python\ndef merge_sorted_lists(arr1, arr2): # built in sorted does Timsort optimized for subsection sorted lists\n    return sorted(arr1 + arr2)\n```\n\nSort an array but keep the original indexes\n\n```python\nself.idx, self.vals = zip(*sorted([(i,v) for i,v in enumerate(nums)], key=lambda x:x[1]))\n```\n\nSort by tuple, 2nd element then 1st ascending\n\n```python\na = [(5,10), (2,20), (2,3), (0,100)]\ntest = sorted(a, key = lambda x: (x[1],x[0]))\nprint(test) # [(2, 3), (5, 10), (2, 20), (0, 100)]\ntest = sorted(a, key = lambda x: (-x[1],x[0]))\nprint(test) # [(0, 100), (2, 20), (5, 10), (2, 3)]\n```\n\nSort and print dict values by key\n\n```python\nans = {-1: [(10, 1), (3, 3)], 0: [(0, 0), (2, 2), (7, 4)], -3: [(8, 5)]}\nfor key, value in sorted(ans.items()): print(value)\n# [(8, 5)]\n# [(10, 1), (3, 3)]\n# [(0, 0), (2, 2), (7, 4)]\n\n# sorted transforms dicts to lists\nsorted(ans) # [-3, -1, 0]\nsorted(ans.values()) # [[(0, 0), (2, 2), (7, 4)], [(8, 5)], [(10, 1), (3, 3)]]\nsorted(ans.items()) # [(-3, [(8, 5)]), (-1, [(10, 1), (3, 3)]), (0, [(0, 0), (2, 2), (7, 4)])]\n# Or just sort the dict directly\n[ans[i] for i in sorted(ans)]\n# [[(8, 5)], [(10, 1), (3, 3)], [(0, 0), (2, 2), (7, 4)]]\n```\n\n## Hash\n\n```python\nfor c in s1: # Adds counter for c\n  ht[c] = ht.get(c, 0) + 1 # ht[a] = 1, ht[a]=2, etc\n```\n\n## Set\n\n```python\na = 3\nst = set()\nst.add(a) # Add to st\nst.remove(a) # Remove from st\nst.discard(a) # Removes from set with no error\nst.add(a) # Add to st\nnext(iter(s)) # return 3 without removal\nst.pop() # returns 3\n```\n\n```python\ns = set('abc') # {'c', 'a', 'b'}\ns |= set('cdf') # {'f', 'a', 'b', 'd', 'c'} set s with elements from new set\ns \u0026= set('bd') # {'d', 'b'} only elements from new set\ns -= set('b') # {'d'} remove elements from new set\ns ^= set('abd') # {'a', 'b'} elements from s or new but not both\n```\n\n## List\n\nStacks are implemented with Lists. Stacks are good for parsing and graph traversal\n\n```python\ntest = [0] * 100 # initialize list with 100 0's\n```\n\n2D\n\n```python\nrtn.append([])\nrtn[0].append(1) # [[1]]\n```\n\nList Comprehension\n\n```python\nnumber_list = [ x for x in range(20) if x % 2 == 0]\nprint(number_list) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n```\n\nReverse a list\n\n```python\nss = [1,2,3]\nss.reverse()\nprint(ss) #3,2,1\n```\n\nJoin list\n\n```python\nlist1 = [\"a\", \"b\" , \"c\"]\nlist2 = [1, 2, 3]\nlist3 = list1 + list2 # ['a', 'b', 'c', 1, 2, 3]\n```\n\n## Dict\n\nHashtables are implemented with dictionaries\n\n```python\nd = {'key': 'value'}         # Declare dict{'key': 'value'}\nd['key'] = 'value'           # Add Key and Value\n{x:0 for x in {'a', 'b'}}    # {'a': 0, 'b': 0} declare through comprehension\nd['key'])                    # Access value\nd.items()                    # Items as tuple list dict_items([('key', 'value')])\nif 'key' in d: print(\"meh\")  # Check if value exists\npar = {}\npar.setdefault(1,1)          # returns 1, makes par = { 1 : 1 }\npar = {0:True, 1:False}\npar.pop(0)                   # Remove key 0, Returns True, par now {1: False}\nfor k in d: print(k)         # Iterate through keys\n```\n\nCreate Dict of Lists that match length of list to count votes\n\n```python\nvotes = [\"ABC\",\"CBD\",\"BCA\"]\nrnk = {v:[0] * len(votes[0]) for v in votes[0]}\nprint(rnk) # {'A': [0, 0, 0], 'B': [0, 0, 0], 'C': [0, 0, 0]}\n```\n\n## Tree\n\n1. A [tree](https://www.geeksforgeeks.org/some-theorems-on-trees/) is an undirected [graph](https://www.cs.sfu.ca/~ggbaker/zju/math/trees.html) in which any two vertices are\n   connected by exactly one path.\n1. Any connected graph who has n nodes with n-1 edges is a tree.\n1. The degree of a vertex is the number of edges connected to the vertex.\n1. A leaf is a vertex of degree 1. An internal vertex is a vertex of degree at least 2.\n1. A [path graph](https://en.wikipedia.org/wiki/Path_graph) is a tree with two or more vertices with no branches, degree of 2 except for leaves which have degree of 1\n\n1. Any two vertices in G can be connected by a unique simple path.\n1. G is acyclic, and a simple cycle is formed if any edge is added to G.\n1. G is connected and has no cycles.\n1. G is connected but would become disconnected if any single edge is removed from G.\n\n## BinaryTree\n\nDFS Pre, In Order, and Post order Traversal\n\n- Preorder\n  - encounters roots before leaves\n  - Create copy\n- Inorder\n  - flatten tree back to original sequence\n  - Get values in non-decreasing order in BST\n- Post order\n  - encounter leaves before roots\n  - Helpful for deleting\n\nRecursive\n\n```python\n\"\"\"\n     1\n    / \\\n   2   3\n  / \\\n 4   5\n\"\"\"\n# PostOrder 4 5 2 3 1  (Left-Right-Root)\ndef postOrder(node):\n  if node is None:\n    return\n  postorder(node.left)\n  postorder(node.right)\n  print(node.value, end=' ')\n```\n\nIterative PreOrder\n\n```python\n# PreOrder  1 2 4 5 3 (Root-Left-Right)\ndef preOrder(tree_root):\n  stack = [(tree_root, False)]\n  while stack:\n    node, visited = stack.pop()\n    if node:\n      if visited:\n        print(node.value, end=' ')\n      else:\n        stack.append((node.right, False))\n        stack.append((node.left, False))\n        stack.append((node, True))\n```\n\nIterative InOrder\n\n```python\n# InOrder   4 2 5 1 3 (Left-Root-Right)\ndef inOrder(tree_root):\n  stack = [(tree_root, False)]\n  while stack:\n    node, visited = stack.pop()\n    if node:\n      if visited:\n        print(node.value, end=' ')\n      else:\n        stack.append((node.right, False))\n        stack.append((node, True))\n        stack.append((node.left, False))\n```\n\nIterative PostOrder\n\n```python\n# PostOrder 4 5 2 3 1  (Left-Right-Root)\ndef postOrder(tree_root):\n  stack = [(tree_root, False)]\n  while stack:\n    node, visited = stack.pop()\n    if node:\n      if visited:\n        print(node.value, end=' ')\n      else:\n        stack.append((node, True))\n        stack.append((node.right, False))\n        stack.append((node.left, False))\n```\n\nIterative BFS(LevelOrder)\n\n```python\nfrom collections import deque\n\n#BFS levelOrder 1 2 3 4 5\ndef levelOrder(tree_root):\n  queue = deque([tree_root])\n  while queue:\n    node = queue.popleft()\n    if node:\n        print(node.value, end=' ')\n        queue.append(node.left)\n        queue.append(node.right)\n\ndef levelOrderStack(tree_root):\n    stk = [(tree_root, 0)]\n    rtn = []\n    while stk:\n        node, depth = stk.pop()\n        if node:\n            if len(rtn) \u003c depth + 1:\n                rtn.append([])\n            rtn[depth].append(node.value)\n            stk.append((node.right, depth+1))\n            stk.append((node.left, depth+1))\n    print(rtn)\n    return True\n\ndef levelOrderStackRec(tree_root):\n    rtn = []\n\n    def helper(node, depth):\n        if len(rtn) == depth:\n            rtn.append([])\n        rtn[depth].append(node.value)\n        if node.left:\n            helper(node.left, depth + 1)\n        if node.right:\n            helper(node.right, depth + 1)\n\n    helper(tree_root, 0)\n    print(rtn)\n    return rtn\n```\n\nTraversing data types as a graph, for example BFS\n\n```python\ndef removeInvalidParentheses(self, s: str) -\u003e List[str]:\n    rtn = []\n    v = set()\n    v.add(s)\n    if len(s) == 0: return [\"\"]\n    while True:\n        for n in v:\n            if self.isValid(n):\n                rtn.append(n)\n        if len(rtn) \u003e 0: break\n        level = set()\n        for n in v:\n            for i, c in enumerate(n):\n                if c == '(' or c == ')':\n                    sub = n[0:i] + n[i + 1:len(n)]\n                    level.add(sub)\n        v = level\n    return rtn\n```\n\nReconstructing binary trees\n\n1. Binary tree could be constructed from preorder and inorder traversal\n1. Inorder traversal of BST is an array sorted in the ascending order\n\nConvert tree to array and then to balanced tree\n\n```python\ndef balanceBST(self, root: TreeNode) -\u003e TreeNode:\n    self.inorder = []\n\n    def getOrder(node):\n        if node is None:\n            return\n        getOrder(node.left)\n        self.inorder.append(node.val)\n        getOrder(node.right)\n\n    # Get inorder treenode [\"1,2,3,4\"]\n    getOrder(root)\n\n    # Convert to Tree\n    #        2\n    #       1 3\n    #          4\n    def bst(listTree):\n        if not listTree:\n            return None\n        mid = len(listTree) // 2\n        root = TreeNode(listTree[mid])\n        root.left = bst(listTree[:mid])\n        root.right = bst(listTree[mid+1:])\n        return root\n\n    return bst(self.inorder)\n```\n\n## Graph\n\nBuild an [adjecency graph](https://www.khanacademy.org/computing/computer-science/algorithms/graph-representation/a/representing-graphs) from edges list\n\n```python\n# N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]\ngraph = [[] for _ in range(N)]\nfor u,v in edges:\n    graph[u].append(v)\n    graph[v].append(u)\n# [[1, 2], [0], [0, 3, 4, 5], [2], [2], [2]]\n```\n\nBuild adjecency graph from traditional tree\n\n```python\nadj = collections.defaultdict(list)\ndef dfs(node):\n    if node.left:\n        adj[node].append(node.left)\n        adj[node.left].append(node)\n        dfs(node.left)\n    if node.right:\n        adj[node].append(node.right)\n        adj[node.right].append(node)\n        dfs(node.right)\ndfs(root)\n```\n\nTraverse Tree in graph notation\n\n```python\n# [[1, 2], [0], [0, 3, 4, 5], [2], [2], [2]]\ndef dfs(node, par=-1):\n    for nei in graph[node]:\n        if nei != par:\n            res = dfs(nei, node)\ndfs(0) # 1-\u003e2-\u003e3-\u003e4-\u003e5\n```\n\n## Heapq\n\n```\n      1\n     / \\\n    2   3\n   / \\ / \\\n  5  6 8  7\n```\n\n[Priority Queue](https://realpython.com/python-heapq-module/#data-structures-heaps-and-priority-queues)\n\n1. Implemented as complete binary tree, which has all levels as full excepted deepest\n1. In a heap tree the node is smaller than its children\n\n```python\ndef maximumProduct(self, nums: List[int]) -\u003e int:\n  l = heapq.nlargest(3, nums)\n  s = heapq.nsmallest(3, nums)\n  return max(l[0]*l[1]*l[2],s[0]*s[1]*l[0])\n```\n\nHeap elements can be tuples, heappop() frees the smallest element (flip sign to pop largest)\n\n```python\ndef kClosest(self, points: List[List[int]], K: int) -\u003e List[List[int]]:\n    heap = []\n    for p in points:\n        distance = sqrt(p[0]* p[0] + p[1]*p[1])\n        heapq.heappush(heap,(-distance, p))\n        if len(heap) \u003e K:\n            heapq.heappop(heap)\n    return ([h[1] for h in heap])\n```\n\nnsmallest can take a lambda argument\n\n```python\ndef kClosest(self, points: List[List[int]], K: int) -\u003e List[List[int]]:\n    return heapq.nsmallest(K, points, lambda x: x[0]*x[0] + x[1]*x[1])\n```\n\nThe key can be a function as well in nsmallest/nlargest\n\n```python\ndef topKFrequent(self, nums: List[int], k: int) -\u003e List[int]:\n    count = Counter(nums)\n    return heapq.nlargest(k, count, count.get)\n```\n\nTuple sort, 1st/2nd element. increasing frequency then decreasing order\n\n```python\ndef topKFrequent(self, words: List[str], k: int) -\u003e List[str]:\n    freq = Counter(words)\n    return heapq.nsmallest(k, freq.keys(), lambda x:(-freq[x], x))\n```\n\n## Lambda\n\nCan be used with (list).sort(), sorted(), min(), max(), (heapq).nlargest,nsmallest(), map()\n\n```python\n# a=3,b=8,target=10\nmin((b,a), key=lambda x: abs(target - x)) # 8\n```\n\n```python\n\u003e\u003e\u003e ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100']\n\u003e\u003e\u003e print(sorted(ids)) # Lexicographic sort\n['id1', 'id100', 'id2', 'id22', 'id3', 'id30']\n\u003e\u003e\u003e sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort\n\u003e\u003e\u003e print(sorted_ids)\n['id1', 'id2', 'id3', 'id22', 'id30', 'id100']\n```\n\n```python\ntrans = lambda x: list(al[i] for i in x) # apple, a-\u003e0..\nprint(trans(words[0])) # [0, 15, 15, 11, 4]\n```\n\nLambda can sort by 1st, 2nd element in tuple\n\n```python\nsorted([('abc', 121),('bbb',23),('abc', 148),('bbb', 24)], key=lambda x: (x[0],x[1]))\n# [('abc', 121), ('abc', 148), ('bbb', 23), ('bbb', 24)]\n```\n\n## Zip\n\nCombine two dicts or lists\n\n```python\ns1 = {2, 3, 1}\ns2 = {'b', 'a', 'c'}\nlist(zip(s1, s2)) # [(1, 'a'), (2, 'c'), (3, 'b')]\n```\n\nTraverse in Parallel\n\n```python\nletters = ['a', 'b', 'c']\nnumbers = [0, 1, 2]\nfor l, n in zip(letters, numbers):\n  print(f'Letter: {l}') # a,b,c\n  print(f'Number: {n}') # 0,1,2\n```\n\nEmpty in one list is ignored\n\n```python\nletters = ['a', 'b', 'c']\nnumbers = []\nfor l, n in zip(letters, numbers):\n  print(f'Letter: {l}') #\n  print(f'Number: {n}') #\n```\n\nCompare characters of alternating words\n\n```python\nfor a, b in zip(words, words[1:]):\n    for c1, c2 in zip(a,b):\n        print(\"c1\", c1, end=\" \")\n        print(\"c2\", c2, end=\"\\n \")\n```\n\nPassing in [\\*](https://stackoverflow.com/questions/29139350/difference-between-ziplist-and-ziplist/29139418) unpacks a list or other iterable, making each of its elements a separate argument.\n\n```python\na = [[1,2],[3,4]]\ntest = zip(*a)\nprint(list(test)) # [(1, 3) (2, 4)]\nmatrix = [[1,2,3],[4,5,6],[7,8,9]]\ntest = zip(*matrix)\nprint(*test) # (1, 4, 7) (2, 5, 8) (3, 6, 9)\n```\n\nUseful when rotating a matrix\n\n```python\n# matrix = [[1,2,3],[4,5,6],[7,8,9]]\nmatrix[:] = [list(t) for t in zip(*matrix[::-1])] # [[7,4,1],[8,5,2],[9,6,3]]\n```\n\nIterate through chars in a list of strs\n\n```python\nstrs = [\"cir\",\"car\",\"caa\"]\nfor i, l in enumerate(zip(*strs)):\n    print(l)\n    # ('c', 'c', 'c')\n    # ('i', 'a', 'a')\n    # ('r', 'r', 'a')\n```\n\nDiagonals can be traversed with the help of a list\n\n```python\n\"\"\"\n[[1,2,3],\n [4,5,6],\n [7,8,9],\n [10,11,12]]\n\"\"\"\ndef printDiagonalMatrix(self, matrix: List[List[int]]) -\u003e bool:\n    R = len(matrix)\n    C = len(matrix[0])\n\n    tmp = [[] for _ in range(R+C-1)]\n\n    for r in range(R):\n        for c in range(C):\n            tmp[r+c].append(matrix[r][c])\n\n    for t in tmp:\n        for n in t:\n            print(n, end=' ')\n        print(\"\")\n\"\"\"\n 1,\n 2,4\n 3,5,7\n 6,8,10\n 9,11\n 12\n\"\"\"\n```\n\n## Random\n\n```Python\nfor i, l in enumerate(shuffle):\n  r = random.randrange(0+i, len(shuffle))\n  shuffle[i], shuffle[r] = shuffle[r], shuffle[i]\nreturn shuffle\n```\n\nOther random generators\n\n```Python\nimport random\nints = [0,1,2]\nrandom.choice(ints) # 0,1,2\nrandom.choices([1,2,3],[1,1,10]) # 3, heavily weighted\nrandom.randint(0,2) # 0,1, 2\nrandom.randint(0,0) # 0\nrandom.randrange(0,0) # error\nrandom.randrange(0,2) # 0,1\n```\n\n## Constants\n\n```Python\nmax = float('-inf')\nmin = float('inf')\n```\n\n## Ternary\n\na if condition else b\n\n```Python\ntest = stk.pop() if stk else '#'\n```\n\n## Bitwise Operators\n\n```python\n'0b{:04b}'.format(0b1100 \u0026 0b1010) # '0b1000' and\n'0b{:04b}'.format(0b1100 | 0b1010) # '0b1110' or\n'0b{:04b}'.format(0b1100 ^ 0b1010) # '0b0110' exclusive or\n'0b{:04b}'.format(0b1100 \u003e\u003e 2)     # '0b0011' shift right\n'0b{:04b}'.format(0b0011 \u003c\u003c 2)     # '0b1100' shift left\n```\n\n## For Else\n\nElse condition on for loops if break is not called\n\n```python\nfor w1, w2 in zip(words, words[1:]): #abc, ab\n    for c1, c2 in zip(w1, w2):\n        if c1 != c2:\n            adj[c1].append(c2)\n            degrees[c2] += 1\n            break\n    else: # nobreak\n        if len(w1) \u003e len(w2):\n            return \"\"   # Triggers since ab should be before abc, not after\n```\n\n## Modulo\n\n```python\nfor n in range(-8,8):\n    print n, n//4, n%4\n\n -8 -2 0\n -7 -2 1\n -6 -2 2\n -5 -2 3\n\n -4 -1 0\n -3 -1 1\n -2 -1 2\n -1 -1 3\n\n  0  0 0\n  1  0 1\n  2  0 2\n  3  0 3\n\n  4  1 0\n  5  1 1\n  6  1 2\n  7  1 3\n```\n\n## Any\n\nif any element of the iterable is True\n\n```python\ndef any(iterable):\n    for element in iterable:\n        if element:\n            return True\n    return False\n```\n\n## All\n\n```python\ndef all(iterable):\n    for element in iterable:\n        if not element:\n            return False\n    return True\n```\n\n## Bisect\n\n- bisect.bisect_left returns the leftmost place in the sorted list to insert the given element\n- bisect.bisect_right returns the rightmost place in the sorted list to insert the given element\n\n```python\nimport bisect\nbisect.bisect_left([1,2,3,4,5], 2)  # 1\nbisect.bisect_right([1,2,3,4,5], 2) # 2\nbisect.bisect_left([1,2,3,4,5], 7)  # 5\nbisect.bisect_right([1,2,3,4,5], 7) # 5\n```\n\nInsert x in a in sorted order. This is equivalent to a.insert(bisect.bisect_left(a, x, lo, hi), x) assuming that a is already sorted. Search is binary search O(logn) and insert is O(n)\n\n```python\nimport bisect\nl = [1, 3, 7, 5, 6, 4, 9, 8, 2]\nresult = []\nfor e in l:\n    bisect.insort(result, e)\nprint(result) # [1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n\n```python\nli1 = [1, 3, 4, 4, 4, 6, 7] # [1, 3, 4, 4, 4, 5, 6, 7]\nbisect.insort(li1, 5) #\n```\n\nBisect can give two ends of a range, if the array is sorted of course\n\n```python\ns = bisect.bisect_left(nums, target)\ne = bisect.bisect(nums, target) -1\nif s \u003c= e:\n    return [s,e]\nelse:\n    return [-1,-1]\n```\n\n## Math\n\nCalulate power\n\n```python\n# (a ^ b) % p.\nd = pow(a, b, p)\n```\n\nDivision with remainder\n\n```python\ndivmod(8, 3) # (2, 2)\ndivmod(3, 8) #  (0, 3)\n```\n\n## eval\n\nEvaluates an expression\n\n```python\nx = 1\nprint(eval('x + 1'))\n```\n\n## Iter\n\nCreates iterator from container object such as list, tuple, dictionary and set\n\n```python\nmytuple = (\"apple\", \"banana\", \"cherry\")\nmyit = iter(mytuple)\nprint(next(myit)) # apple\nprint(next(myit)) # banana\n```\n\n## Map\n\nmap(func, \\*iterables)\n\n```python\nmy_pets = ['alfred', 'tabitha', 'william', 'arla']\nuppered_pets = list(map(str.upper, my_pets)) # ['ALFRED', 'TABITHA', 'WILLIAM', 'ARLA']\nmy_strings = ['a', 'b', 'c', 'd', 'e']\nmy_numbers = [1,2,3,4,5]\nresults = list(map(lambda x, y: (x, y), my_strings, my_numbers)) # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]\n```\n\n```python\nA1 = [1, 4, 9]\n''.join(map(str, A1))\n```\n\n## Filter\n\nfilter(func, iterable)\n\n```python\nscores = [66, 90, 68, 59, 76, 60, 88, 74, 81, 65]\nover_75 = list(filter(lambda x: x\u003e75, scores)) # [90, 76, 88, 81]\n```\n\n```python\nscores = [66, 90, 68, 59, 76, 60, 88, 74, 81, 65]\ndef is_A_student(score):\n    return score \u003e 75\nover_75 = list(filter(is_A_student, scores)) # [90, 76, 88, 81]\n```\n\n```python\ndromes = (\"demigod\", \"rewire\", \"madam\", \"freer\", \"anutforajaroftuna\", \"kiosk\")\npalindromes = list(filter(lambda word: word == word[::-1], dromes)) # ['madam', 'anutforajaroftuna']\n```\n\nGet degrees == 0 from list\n\n```python\nstk = list(filter(lambda x: degree[x]==0, degree.keys()))\n```\n\n## Reduce\n\nreduce(func, iterable[, initial])\nwhere initial is optional\n\n```python\nnumbers = [3, 4, 6, 9, 34, 12]\nresult = reduce(lambda x, y: x+y, numbers) # 68\nresult = reduce(lambda x, y: x+y, numbers, 10) #78\n```\n\n## itertools\n\n[itertools.accumulate(iterable[, func]) –\u003e accumulate object](https://www.geeksforgeeks.org/python-itertools-accumulate/)\n\n```python\nimport itertools\ndata = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]\nlist(itertools.accumulate(data)) # [3, 7, 13, 15, 16, 25, 25, 32, 37, 45]\nlist(accumulate(data, max))  # [3, 4, 6, 6, 6, 9, 9, 9, 9, 9]\ncashflows = [1000, -90, -90, -90, -90]  # Amortize a 5% loan of 1000 with 4 annual payments of 90\nlist(itertools.accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]\nfor k,v in groupby(\"aabbbc\")    # group by common letter\n    print(k)                    # a,b,c\n    print(list(v))              # [a,a],[b,b,b],[c,c]\n```\n\n## Regular Expression\n\nRE module allows regular expressions in python\n\n```python\ndef removeVowels(self, S: str) -\u003e str:\n    return re.sub('a|e|i|o|u', '', S)\n```\n\n## Types\n\nfrom typing import List, Set, Dict, Tuple, Optional\n[cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)\n\n## Grids\n\nUseful helpful function\n\n```python\nR = len(grid)\nC = len(grid[0])\n\ndef neighbors(r, c):\n    for nr, nc in ((r,c-1), (r,c+1), (r-1, c), (r+1,c)):\n        if 0\u003c=nr\u003cR and 0\u003c=nc\u003cC:\n            yield nr, nc\n\ndef dfs(r,c, index):\n    area = 0\n    grid[r][c] = index\n    for x,y in neighbors(r,c):\n        if grid[x][y] == 1:\n            area += dfs(x,y, index)\n    return area + 1\n```\n\n# Collections\n\nStack with appendleft() and popleft()\n\n## Deque\n\n```python\nfrom collections import deque\ndeq = deque([1, 2, 3])\ndeq.appendleft(5)\ndeq.append(6)\ndeq\ndeque([5, 1, 2, 3, 6])\ndeq.popleft()\n5\ndeq.pop()\n6\ndeq\ndeque([1, 2, 3])\n```\n\n## Counter\n\n```python\nfrom collections import Counter\ncount = Counter(\"hello\") # Counter({'h': 1, 'e': 1, 'l': 2, 'o': 1})\ncount['l'] # 2\ncount['l'] += 1\ncount['l'] # 3\n```\n\nGet counter k most common in list of tuples\n\n```python\n# [1,1,1,2,2,3]\n# Counter  [(1, 3), (2, 2)]\ndef topKFrequent(self, nums: List[int], k: int) -\u003e List[int]:\n    if len(nums) == k:\n        return nums\n    return [n[0] for n in Counter(nums).most_common(k)] # [1,2]\n```\n\nelements() lets you walk through each number in the Counter\n\n```python\ndef intersect(self, nums1: List[int], nums2: List[int]) -\u003e List[int]:\n    c1 = collections.Counter(nums1) # [1,2,2,1]\n    c2 = collections.Counter(nums2) # [2,2]\n    dif = c1 \u0026 c2                   # {2:2}\n    return list(dif.elements())     # [2,2]\n```\n\noperators work on Counter\n\n```python\nc = Counter(a=3, b=1)\nd = Counter(a=1, b=2)\nc + d # {'a': 4, 'b': 3}\nc - d # {'a': 2}\nc \u0026 d # {'a': 1, 'b': 1}\nc | d # {'a': 3, 'b': 2}\nc = Counter(a=2, b=-4)\n+c # {'a': 2}\n-c # {'b': 4}\n```\n\n## Default Dict\n\n```python\nd={}\nprint(d['Grapes'])# This gives Key Error\nfrom collections import defaultdict\nd = defaultdict(int) # set default\nprint(d['Grapes']) # 0, no key error\nd = collections.defaultdict(lambda: 1)\nprint(d['Grapes']) # 1, no key error\n```\n\n```python\nfrom collections import defaultdict\ndd = defaultdict(list)\ndd['key'].append(1) # defaultdict(\u003cclass 'list'\u003e, {'key': [1]})\ndd['key'].append(2) # defaultdict(\u003cclass 'list'\u003e, {'key': [1, 2]})\n```\n\n# Algorithms\n\n## General Tips\n\n- Get all info\n- Debug example, is it a special case?\n- Brute Force\n  - Get to brute-force solution as soon as possible. State runtime and then optimize, don't code yet\n- Optimize\n  - Look for unused info\n  - Solve it manually on example, then reverse engineer thought process\n  - Space vs time, hashing\n  - BUDS (Bottlenecks, Unnecessary work, Duplication)\n- Walk through approach\n- Code\n- Test\n  - Start small\n  - Hit edge cases\n\n## Binary Search\n\n```python\ndef firstBadVersion(self, n):\n    l, r = 0, n\n    while l \u003c r:\n        m = l + (r-l) // 2\n        if isBadVersion(m):\n            r = m\n        else:\n            l = m + 1\n    return l\n```\n\n```python\n\"\"\"\n12345678\nFFTTTTTT\n\"\"\"\ndef mySqrt(self, x: int) -\u003e int:\n  def condition(value, x) -\u003e bool:\n    return value * value \u003e x\n\n  if x == 1:\n    return 1\n\n  left, right = 1, x\n  while left \u003c right:\n    mid = left + (right-left) // 2\n    if condition(mid, x):\n      right = mid\n    else:\n      left = mid + 1\n\n  return left - 1\n```\n\n[binary search](https://leetcode.com/discuss/general-discussion/786126/python-powerful-ultimate-binary-search-template-solved-many-problems)\n\n## Binary Search Tree\n\nUse values to detect if number is missing\n\n```python\ndef isCompleteTree(self, root: TreeNode) -\u003e bool:\n    self.total = 0\n    self.mx = float('-inf')\n    def dfs(node, cnt):\n        if node:\n            self.total += 1\n            self.mx = max(self.mx, cnt)\n            dfs(node.left, (cnt*2))\n            dfs(node.right, (cnt*2)+1)\n    dfs(root, 1)\n    return self.total == self.mx\n```\n\nGet a range sum of values\n\n```python\ndef rangeSumBST(self, root: TreeNode, L: int, R: int) -\u003e int:\n    self.total = 0\n    def helper(node):\n        if node is None:\n            return 0\n        if L \u003c= node.val \u003c= R:\n            self.total += node.val\n        if node.val \u003e L:\n            left = helper(node.left)\n        if node.val \u003c R:\n            right = helper(node.right)\n    helper(root)\n    return self.total\n```\n\nCheck if valid\n\n```python\ndef isValidBST(self, root: TreeNode) -\u003e bool:\n    if not root:\n        return True\n    stk = [(root, float(-inf), float(inf))]\n    while stk:\n        node, floor, ceil = stk.pop()\n        if node:\n            if node.val \u003e= ceil or node.val \u003c= floor:\n                return False\n            stk.append((node.right, node.val, ceil))\n            stk.append((node.left, floor, node.val))\n    return True\n```\n\n## Topological Sort\n\n[Kahn's algorithm](https://www.geeksforgeeks.org/all-topological-sorts-of-a-directed-acyclic-graph/), detects cycles through degrees and needs all the nodes represented to work\n\n1. Initialize vertices as unvisited\n1. Pick vertex with zero indegree, append to result, decrease indegree of neighbors\n1. Now repeat for neighbors, resulting list is sorted by source -\u003e dest\n\nIf cycle, then degree of nodes in cycle will not be 0 since there\nis no origin\n\n```python\ndef canFinish(self, numCourses: int, prerequisites: List[List[int]]) -\u003e bool:\n    # Kahns algorithm, topological sort\n    adj = collections.defaultdict(list)\n    degree = collections.Counter()\n\n    for dest, orig in prerequisites:\n        adj[orig].append(dest)\n        degree[dest] += 1\n\n    bfs = [c for c in range(numCourses) if degree[c] == 0]\n\n    for o in bfs:\n        for d in adj[o]:\n            degree[d] -= 1\n            if degree[d] == 0:\n                bfs.append(d)\n\n    return len(bfs) == numCourses\n```\n\n```python\ndef alienOrder(self, words: List[str]) -\u003e str:\n    nodes = set(\"\".join(words))\n    adj = collections.defaultdict(list)\n    degree = collections.Counter(nodes)\n\n    for w1, w2 in zip(words, words[1:]):\n        for c1, c2 in zip(w1, w2):\n            if c1 != c2:\n                adj[c1].append(c2)\n                degree[c2] += 1\n                break\n        else:\n            if len(w1) \u003e len(w2):\n                return \"\"\n\n    stk = list(filter(lambda x: degree[x]==1, degree.keys()))\n\n    ans = []\n    while stk:\n        node = stk.pop()\n        ans.append(node)\n        for nei in adj[node]:\n            degree[nei] -= 1\n            if degree[nei] == 1:\n                stk.append(nei)\n\n    return \"\".join(ans) * (set(ans) == nodes)\n```\n\n## Sliding Window\n\n1. Have a counter or hash-map to count specific array input and keep on increasing the window toward right using outer loop.\n1. Have a while loop inside to reduce the window side by sliding toward right. Movement will be based on constraints of problem.\n1. Store the current maximum window size or minimum window size or number of windows based on problem requirement.\n\n### Typical Problem Clues:\n\n1. Get min/max/number of satisfied sub arrays\n1. Return length of the subarray with max sum/product\n1. Return max/min length/number of subarrays whose sum/product equals K\n\nCan require [2 or 3 pointers to solve](https://medium.com/algorithms-and-leetcode/magic-solution-to-leetcode-problems-sliding-window-algorithm-891e3d60bf89)\n\n```python\n    def slidingWindowTemplate(self, s: str):\n        #init a collection or int value to save the result according the question.\n        rtn = []\n\n        # create a hashmap to save the Characters of the target substring.\n        # (K, V) = (Character, Frequence of the Characters)\n        hm = {}\n\n        # maintain a counter to check whether match the target string as needed\n        cnt = collections.Counter(s)\n\n        # Two Pointers: begin - left pointer of the window; end - right pointer of the window if needed\n        l = r = 0\n\n        # loop at the begining of the source string\n        for r, c in enumerate(s):\n\n            if c in hm:\n                l = max(hm[c]+1, l) # +/- 1 or set l to index, max = never move l left\n\n            # update hm\n            hm[c] = r\n\n            # increase l pointer to make it invalid/valid again\n            while cnt == 0: # counter condition\n                cnt[c] += 1  # modify counter if needed\n\n            # Save result / update min/max after loop is valid\n            rtn = max(rtn, r-l+1)\n\n        return rtn\n```\n\n```python\ndef fruits_into_baskets(fruits):\n  maxCount, j = 0, 0\n  ht = {}\n\n  for i, c in enumerate(fruits):\n    if c in ht:\n      ht[c] += 1\n    else:\n      ht[c] = 1\n\n    if len(ht) \u003c= 2:\n      maxCount = max(maxCount, i-j+1)\n    else:\n      jc = fruits[j]\n      ht[jc] -= 1\n      if ht[jc] \u003c= 0:\n        del ht[jc]\n      j += 1\n\n  return maxCount\n```\n\n## Greedy\n\nMake the optimal [choice](https://brilliant.org/wiki/greedy-algorithm/) at each step.\n\n[Increasing Triplet Subsequence](https://leetcode.com/problems/increasing-triplet-subsequence/), true if i \u003c j \u003c k\n\n```python\ndef increasingTriplet(self, nums: List[int]) -\u003e bool:\n    l = m = float('inf')\n\n    for n in nums:\n        if n \u003c= l:\n            l = n\n        elif n \u003c= m:\n            m = n\n        else:\n            return True\n\n    return False\n```\n\n## Tree Tricks\n\nBottom up solution with arguments for min, max\n\n```python\ndef maxAncestorDiff(self, root: TreeNode) -\u003e int:\n    if not root:\n        return 0\n    self.ans = 0\n    def dfs(node, minval, maxval):\n        if not node:\n            self.ans = max(self.ans, abs(maxval - minval))\n            return\n        dfs(node.left, min(node.val, minval), max(node.val, maxval))\n        dfs(node.right, min(node.val, minval), max(node.val, maxval))\n    dfs(root, float('inf'), float('-inf'))\n    return self.ans\n```\n\nBuilding a path through a tree\n\n```python\ndef binaryTreePaths(self, root: TreeNode) -\u003e List[str]:\n    rtn = []\n    if root is None: return []\n    stk = [(root, str(root.val))]\n    while stk:\n        node, path = stk.pop()\n        if node.left is None and node.right is None:\n            rtn.append(path)\n        if node.left:\n            stk.append((node.left, path + \"-\u003e\" + str(node.left.val)))\n        if node.right:\n            stk.append((node.right, path + \"-\u003e\" + str(node.right.val)))\n    return rtn\n```\n\nUsing return value to sum\n\n```python\ndef diameterOfBinaryTree(self, root: TreeNode) -\u003e int:\n    self.mx = 0\n    def dfs(node):\n        if node:\n            l = dfs(node.left)\n            r = dfs(node.right)\n            total = l + r\n            self.mx = max(self.mx, total)\n            return max(l, r) + 1\n        else:\n            return 0\n    dfs(root)\n    return self.mx\n```\n\nChange Tree to Graph\n\n```python\ndef distanceK(self, root: TreeNode, target: TreeNode, K: int) -\u003e List[int]:\n    adj = collections.defaultdict(list)\n\n    def dfsa(node):\n        if node.left:\n            adj[node].append(node.left)\n            adj[node.left].append(node)\n            dfsa(node.left)\n        if node.right:\n            adj[node].append(node.right)\n            adj[node.right].append(node)\n            dfsa(node.right)\n\n    dfsa(root)\n\n    def dfs(node, prev, d):\n        if node:\n            if d == K:\n                rtn.append(node.val)\n            else:\n                for nei in adj[node]:\n                    if nei != prev:\n                        dfs(nei, node, d+1)\n\n    rtn = []\n    dfs(target, None, 0)\n    return rtn\n```\n\n## Anagrams\n\nSubsection of sliding window, solve with Counter Dict\n\ni.e.\nabc = bca != eba\n111 111 111\n\n```python\ndef isAnagram(self, s: str, t: str) -\u003e bool:\n    sc = collections.Counter(s)\n    st = collections.Counter(t)\n    if sc != st:\n        return False\n    return True\n```\n\nSliding Window version (substring)\n\n```python\ndef findAnagrams(self, s: str, p: str) -\u003e List[int]:\n    cntP = collections.Counter(p)\n    cntS = collections.Counter()\n    P = len(p)\n    S = len(s)\n    if P \u003e S:\n        return []\n    ans = []\n    for i, c in enumerate(s):\n        cntS[c] += 1\n        if i \u003e= P:\n            if cntS[s[i-P]] \u003e 1:\n                cntS[s[i-P]] -= 1\n            else:\n                del cntS[s[i-P]]\n        if cntS == cntP:\n            ans.append(i-(P-1))\n    return ans\n```\n\n## Dynamic Programming\n\n1. [dynamic programming](https://leetcode.com/discuss/general-discussion/458695/Dynamic-Programming-Patterns)\n\n```python\ndef coinChange(self, coins: List[int], amount: int) -\u003e int:\n  MAX = float('inf')\n  dp =  [MAX] * (amount + 1)\n  dp[0] = 0\n  for c in coins:\n    for a in range(c, amount+1):\n      dp[a] =  min(dp[a], dp[a-c]+1)\n  return dp[amount] if dp[amount] != MAX else -1\n```\n\nClassic DP grid, longest common subsequence\n\n```python\ndef longestCommonSubsequence(self, text1: str, text2: str) -\u003e int:\n    Y = len(text2)+1\n    X = len(text1)+1\n    dp = [[0] * Y for _ in range(X)]\n    # [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]\n    for i, c in enumerate(text1):\n        for j, d in enumerate(text2):\n            if c == d:\n                dp[i + 1][j + 1] = 1 + dp[i][j]\n            else:\n                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j])\n    return dp[-1][-1]\n# [[0,0,0,0],[0,1,1,1],[0,1,1,1],[0,1,2,2],[0,1,2,2],[0,1,2,3]]\n# abcde\n# \"ace\"\n```\n\n## Cyclic Sort\n\n1. Useful algo when sorting in place\n\n```python\n# if my number is equal to my index, i+1\n# if my number is equal to this other number, i+1 (dups)\n# else swap\ndef cyclic_sort(nums):\n  i = 0\n  while i \u003c len(nums):\n    j = nums[i] - 1\n    if nums[i] != nums[j]:\n      nums[i], nums[j] = nums[j], nums[i]\n    else:\n      i += 1\n  return nums\n```\n\n## Quick Sort\n\n1. Can be modified for divide in conquer problems\n\n```python\ndef quickSort(array):\n\tdef sort(arr, l, r):\n\t\tif l \u003c r:\n\t\t\tp = part(arr, l, r)\n\t\t\tsort(arr, l, p-1)\n\t\t\tsort(arr, p+1, r)\n\n\tdef part(arr, l, r):\n\t\tpivot = arr[r]\n\t\ta = l\n\t\tfor i in range(l,r):\n\t\t\tif arr[i] \u003c pivot:\n\t\t\t\tarr[i], arr[a] = arr[a], arr[i]\n\t\t\t\ta += 1\n\t\tarr[r], arr[a] = arr[a], arr[r]\n\t\treturn a\n\n\tsort(array, 0, len(array)-1)\n\treturn array\n```\n\n## Merge Sort\n\n```python\nfrom collections import deque\ndef mergeSort(array):\n    def sortArray(nums):\n        if len(nums) \u003e 1:\n            mid = len(nums)//2\n            l1 = sortArray(nums[:mid])\n            l2 = sortArray(nums[mid:])\n            nums = sort(l1,l2)\n        return nums\n\n    def sort(l1,l2):\n        result = []\n        l1 = deque(l1)\n        l2 = deque(l2)\n        while l1 and l2:\n            if l1[0] \u003c= l2[0]:\n                result.append(l1.popleft())\n            else:\n                result.append(l2.popleft())\n        result.extend(l1 or l2)\n        return result\n\treturn sortArray(array)\n```\n\n## Merge Arrays\n\nMerge K sorted Arrays with a heap\n\n```python\ndef mergeSortedArrays(self, arrays):\n    return list(heapq.merge(*arrays))\n```\n\nOr manually with heappush/heappop.\n\n```python\nclass Solution:\ndef mergeSortedArrays(self, arrays):\n    pq = []\n    for i, arr in enumerate(arrays):\n        pq.append((arr[0], i, 0))\n    heapify(pq)\n\n    res = []\n    while pq:\n        num, i, j = heappop(pq)\n        res.append(num)\n        if j + 1 \u003c len(arrays[i]):\n            heappush(pq, (arrays[i][j + 1], i, j + 1))\n    return res\n```\n\nMerging K Sorted Lists\n\n```python\ndef mergeKLists(self, lists: List[ListNode]) -\u003e ListNode:\n    prehead = ListNode()\n    heap = []\n    for i in range(len(lists)):\n        node = lists[i]\n        while node:\n            heapq.heappush(heap, node.val)\n            node = node.next\n    node = prehead\n    while len(heap) \u003e 0:\n        val = heapq.heappop(heap)\n        node.next = ListNode()\n        node = node.next\n        node.val = val\n    return prehead.next\n```\n\n## Linked List\n\n1. Solutions typically require 3 pointers: current, previous and next\n1. Solutions are usually made simplier with a prehead or dummy head node you create and then add to. Then return dummy.next\n\nReverse:\n\n```python\ndef reverseLinkedList(head):\n    prev, node  = None, head\n    while node:\n        node.next, prev, node = prev, node, node.next\n    return prev\n```\n\nReversing is easier if you can modify the values of the list\n\n```python\ndef reverse(head):\n  node = head\n  stk = []\n  while node:\n    if node.data % 2 == 0:\n      stk.append(node)\n    if node.data % 2 == 1 or node.next is None:\n      while len(stk) \u003e 1:\n        stk[-1].data, stk[0].data = stk[0].data, stk[-1].data\n        stk.pop(0)\n        stk.pop(-1)\n      stk.clear()\n    node = node.next\n  return head\n```\n\nMerge:\n\n```python\ndef mergeTwoLists(self, l1: ListNode, l2: ListNode) -\u003e ListNode:\n    dummy = ListNode(-1)\n\n    prev = dummy\n\n    while l1 and l2:\n        if l1.val \u003c l2.val:\n            prev.next = l1\n            l1 = l1.next\n        else:\n            prev.next = l2\n            l2 = l2.next\n        prev = prev.next\n\n    prev.next = l1 if l1 is not None else l2\n\n    return dummy.next\n```\n\n## Convert Base\n\n1. Typically two steps. A digit modulo step and a integer division step by the next base then reverse the result or use a deque()\n\nBase 10 to 16, or any base by changing '16' and index\n\n```python\ndef toHex(self, num: int) -\u003e str:\n  rtn = []\n  index = \"0123456789abcdef\"\n  if num == 0: return '0'\n  if num \u003c 0: num += 2 ** 32\n  while num \u003e 0:\n    digit = num % 16\n    rtn.append(index[digit])\n    num = num // 16\n  return \"\".join(rtn[::-1])\n```\n\n## Parenthesis\n\n1. Count can be used if simple case, otherwise stack. [Basic Calculator](#basic-calculator) is an extension of this algo\n\n```python\ndef isValid(self, s) -\u003e bool:\n  cnt = 0\n  for c in s:\n    if c == '(':\n      cnt += 1\n    elif c == ')':\n      cnt -= 1\n      if cnt \u003c 0:\n        return False\n  return cnt == 0\n```\n\nStack can be used if more complex\n\n```python\ndef isValid(self, s: str) -\u003e bool:\n  stk = []\n  mp = {\")\":\"(\", \"}\":\"{\", \"]\":\"[\"}\n    for c in s:\n      if c in mp.values():\n        stk.append(c)\n      elif c in mp.keys():\n        test = stk.pop() if stk else '#'\n        if mp[c] != test:\n          return False\n  return len(stk) == 0\n```\n\nOr must store parenthesis index for further modification\n\n```python\ndef minRemoveToMakeValid(self, s: str) -\u003e str:\n  rtn = list(s)\n  stk = []\n  for i, c in enumerate(s):\n    if c == '(':\n      stk.append(i)\n    elif c == ')':\n      if len(stk) \u003e 0:\n        stk.pop()\n      else:\n        rtn[i] = ''\n  while stk:\n    rtn[stk.pop()] = ''\n  return \"\".join(rtn)\n```\n\n## Max Profit Stock\n\nInfinite Transactions, [base formula](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/discuss/75924/Most-consistent-ways-of-dealing-with-the-series-of-stock-problems)\n\n```python\ndef maxProfit(self, prices: List[int]) -\u003e int:\n    t0, t1 = 0, float('-inf')\n    for p in prices:\n        t0old = t0\n        t0 = max(t0, t1 + p)\n        t1 = max(t1, t0old - p)\n    return t0\n```\n\nSingle Transaction, t0 (k-1) = 0\n\n```python\ndef maxProfit(self, prices: List[int]) -\u003e int:\n    t0, t1 = 0, float('-inf')\n    for p in prices:\n        t0 = max(t0, t1 + p)\n        t1 = max(t1, - p)\n    return t0\n```\n\nK Transactions\n\n```python\nt0 = [0] * (k+1)\nt1 = [float(-inf)] * (k+1)\nfor p in prices:\n    for i in range(k, 0, -1):\n        t0[i] = max(t0[i], t1[i] + p)\n        t1[i] = max(t1[i], t0[i-1] - p)\nreturn t0[k]\n```\n\n## Shift Array Right\n\nArrays can be shifted right by reversing the whole string, and then reversing 0,k-1 and k,len(str)\n\n```python\ndef rotate(self, nums: List[int], k: int) -\u003e None:\n    def reverse(l, r, nums):\n        while l \u003c r:\n            nums[l], nums[r] = nums[r], nums[l]\n            l += 1\n            r -= 1\n    if len(nums) \u003c= 1: return\n    k = k % len(nums)\n    reverse(0, len(nums)-1, nums)\n    reverse(0, k-1, nums)\n    reverse(k, len(nums)-1, nums)\n```\n\n## Continuous Subarrays with Sum k\n\nThe total number of continuous subarrays with sum k can be found by hashing the continuous sum per value and adding the count of continuous sum - k\n\n```python\ndef subarraySum(self, nums: List[int], k: int) -\u003e int:\n    mp = {0: 1}\n    rtn, total = 0, 0\n    for n in nums:\n        total += n\n        rtn += mp.get(total - k, 0)\n        mp[total] = mp.get(total, 0) + 1\n    return rtn\n```\n\n## Events\n\nEvents pattern can be applied when to many interval problems such as 'Find employee free time between meetings' and 'find peak population' when individual start/ends\nare irrelavent and sum start/end times are more important\n\n```python\ndef employeeFreeTime(self, schedule: '[[Interval]]') -\u003e '[Interval]':\n    events = []\n    for e in schedule:\n        for m in e:\n            events.append((m.start, 1))\n            events.append((m.end, -1))\n    events.sort()\n    itv = []\n    prev = None\n    bal = 0\n    for t, c in events:\n        if bal == 0 and prev is not None and t != prev:\n            itv.append(Interval(prev, t))\n        bal += c\n        prev = t\n    return itv\n```\n\n## Merge Meetings\n\nMerging a new meeting into a list\n\n```python\ndef insert(self, intervals: List[List[int]], newInterval: List[int]) -\u003e List[List[int]]:\n    bisect.insort(intervals, newInterval)\n    merged = [intervals[0]]\n    for i in intervals:\n        ms, me = merged[-1]\n        s, e = i\n        if me \u003e= s:\n            merged[-1] = (ms, max(me, e))\n        else:\n            merged.append(i)\n    return merged\n```\n\n## Trie\n\nGood for autocomplete, spell checker, IP routing (match longest prefix), predictive text, solving word games\n\n```python\nclass Trie:\n    def __init__(self):\n        self.root = {}\n\n    def addWord(self, s: str):\n        tmp = self.root\n        for c in s:\n            if c not in tmp:\n                tmp[c] = {}\n            tmp = tmp[c]\n        tmp['#'] = s # Store full word at '#' to simplify\n\n    def matchPrefix(self, s: str, tmp=None):\n        if not tmp: tmp = self.root\n        for c in s:\n            if c not in tmp:\n                return []\n            tmp = tmp[c]\n\n        rtn = []\n\n        for k in tmp:\n            if k == '#':\n                rtn.append(tmp[k])\n            else:\n                rtn += self.matchPrefix('', tmp[k])\n        return rtn\n\n    def hasWord(self, s: str):\n        tmp = self.root\n        for c in s:\n            if c in tmp:\n                tmp = tmp[c]\n            else:\n                return False\n        return True\n```\n\nSearch example with . for wildcards\n\n```python\ndef search(self, word: str) -\u003e bool:\n    def searchNode(word, node):\n        for i,c in enumerate(word):\n            if c in node:\n                node = node[c]\n            elif c == '.':\n                return any(searchNode(word[i+1:], node[cn]) for cn in node if cn != '$' )\n            else:\n                return False\n        return '$' in node\n    return searchNode(word, self.trie)\n```\n\n## Kadane\n\nlocal_maxiumum[i] = max(A[i], A[i] + local_maximum[i-1])\n[Explanation](https://medium.com/@rsinghal757/kadanes-algorithm-dynamic-programming-how-and-why-does-it-work-3fd8849ed73d)\nDetermine max subarray sum\n\n```python\n# input: [-2,1,-3,4,-1,2,1,-5,4]\ndef maxSubArray(self, nums: List[int]) -\u003e int:\n    for i in range(1, len(nums)):\n        if nums[i-1] \u003e 0:\n            nums[i] += nums[i-1]\n    return max(nums) # max([-2,1,-2,4,3,5,6,1,5]) = 6\n```\n\n## Union Find\n\n[Union Find](https://www.geeksforgeeks.org/union-find/) is a useful algorithm for graph\n\nDSU for integers\n\n```python\nclass DSU:\n    def __init__(self, N):\n        self.par = list(range(N))\n\n    def find(self, x): # Find Parent\n        if self.par[x] != x:\n            self.par[x] = self.find(self.par[x])\n        return self.par[x]\n\n    def union(self, x, y):\n        xr, yr = self.find(x), self.find(y)\n        if xr == yr: # If parents are equal, return False\n            return False\n        self.par[yr] = xr # Give y node parent of x\n        return True # return True if union occured\n```\n\nDSU for strings\n\n```python\nclass DSU:\n    def __init__(self):\n        self.par = {}\n\n    def find(self, x):\n        if x != self.par.setdefault(x, x):\n            self.par[x] = self.find(self.par[x])\n        return self.par[x]\n\n    def union(self, x, y):\n        xr, yr = self.find(x), self.find(y)\n        if xr == yr: return\n        self.par[yr] = xr\n```\n\nDSU with union by rank\n\n```python\nclass DSU:\n    def __init__(self, N):\n        self.par = list(range(N))\n        self.sz = [1] * N\n\n    def find(self, x):\n        if self.par[x] != x:\n            self.par[x] = self.find(self.par[x])\n        return self.par[x]\n\n    def union(self, x, y):\n        xr, yr = self.find(x), self.find(y)\n        if xr == yr:\n            return False\n        if self.sz[xr] \u003c self.sz[yr]:\n            xr, yr = yr, xr\n        self.par[yr] = xr\n        self.sz[xr] += self.sz[yr]\n        return True\n```\n\n## Fast Power\n\nFast Power, or Exponential by [squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) allows calculating squares in logn time (x^n)*2 = x^(2*n)\n\n```python\ndef myPow(self, x: float, n: int) -\u003e float:\n    if n \u003c 0:\n        n *= -1\n        x = 1/x\n    ans = 1\n    while n \u003e 0:\n        if n % 2 == 1:\n            ans = ans * x\n        x *= x\n        n = n // 2\n    return ans\n```\n\n## Fibonacci Golden\n\nFibonacci can be calulated with [Golden Ratio](https://demonstrations.wolfram.com/GeneralizedFibonacciSequenceAndTheGoldenRatio/)\n\n```python\ndef fib(self, N: int) -\u003e int:\n    golden_ratio = (1 + 5 ** 0.5) / 2\n    return int((golden_ratio ** N + 1) / 5 ** 0.5)\n```\n\n## Basic Calculator\n\nA calculator can be simulated with stack\n\n```python\nclass Solution:\n    def calculate(self, s: str) -\u003e int:\n        s += '$'\n        def helper(stk, i):\n            sign = '+'\n            num = 0\n            while i \u003c len(s):\n                c = s[i]\n                if c == \" \":\n                    i += 1\n                    continue\n                elif c.isdigit():\n                    num = num * 10 + int(c)\n                    i += 1\n                elif c == '(':\n                    num, i = helper([], i+1)\n                else:\n                    if sign == '+':\n                        stk.append(num)\n                    if sign == '-':\n                        stk.append(-num)\n                    if sign == '*':\n                        stk.append(stk.pop() * num)\n                    if sign == '/':\n                        stk.append(int(stk.pop() / num))\n                    i += 1\n                    num = 0\n                    if c == ')':\n                        return sum(stk), i\n                    sign = c\n            return sum(stk)\n        return helper([],0)\n```\n\n## Reverse Polish\n\n```python\nclass Solution:\n    def evalRPN(self, tokens: List[str]) -\u003e int:\n        stk = []\n        while tokens:\n            c = tokens.pop(0)\n            if c not in '+-/*':\n                stk.append(int(c))\n            else:\n                a = stk.pop()\n                b = stk.pop()\n                if c == '+':\n                    stk.append(a + b)\n                if c == '-':\n                    stk.append(b-a)\n                if c == '*':\n                    stk.append(a * b)\n                if c == '/':\n                    stk.append(int(b / a))\n        return stk[0]\n```\n\n## Resevior Sampling\n\nUsed to sample large unknown populations. Each new item added has a 1/count chance of being selected\n\n```python\ndef __init__(self, nums):\n    self.nums = nums\ndef pick(self, target):\n    res = None\n    count = 0\n    for i, x in enumerate(self.nums):\n        if x == target:\n            count += 1\n            chance = random.randint(1, count)\n            if chance == 1:\n                res = i\n    return res\n```\n\n## String Subsequence\n\nCan find the min number of subsequences of strings in some source through binary search and a dict of the indexes of the source array\n\n```python\ndef shortestWay(self, source: str, target: str) -\u003e int:\n    ref = collections.defaultdict(list)\n    for i,c in enumerate(source):\n        ref[c].append(i)\n\n    ans = 1\n    i = -1\n    for c in target:\n        if c not in ref:\n            return -1\n        offset = ref[c]\n        j = bisect.bisect_left(offset, i)\n        if j == len(offset):\n            ans += 1\n            i = offset[0] + 1\n        else:\n            i = offset[j] + 1\n\n    return ans\n```\n\n## Candy Crush\n\nRemoving adjacent duplicates is much more effective with a stack\n\n```python\ndef removeDuplicates(self, s: str, k: int) -\u003e str:\n    stk = []\n    for c in s:\n        if stk and stk[-1][0] == c:\n            stk[-1][1] += 1\n            if stk[-1][1] \u003e= k:\n                stk.pop()\n        else:\n            stk.append([c, 1])\n    ans = []\n    for c in stk:\n        ans.extend([c[0]] * c[1])\n    return \"\".join(ans)\n```\n\n## Dutch Flag\n\n[Dutch National Flag Problem](https://en.wikipedia.org/wiki/Dutch_national_flag_problem) proposed by [Edsger W. Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)\n\n```python\ndef sortColors(self, nums: List[int]) -\u003e None:\n    \"\"\"\n    Do not return anything, modify nums in-place instead.\n    \"\"\"\n    # for all idx \u003c p0 : nums[idx \u003c p0] = 0\n    # curr is an index of element under consideration\n    p0 = curr = 0\n    # for all idx \u003e p2 : nums[idx \u003e p2] = 2\n    p2 = len(nums) - 1\n\n    while curr \u003c= p2:\n        if nums[curr] == 0:\n            nums[p0], nums[curr] = nums[curr], nums[p0]\n            p0 += 1\n            curr += 1\n        elif nums[curr] == 2:\n            nums[curr], nums[p2] = nums[p2], nums[curr]\n            p2 -= 1\n        else:\n            curr += 1\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterlamar%2Fpython-cp-cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeterlamar%2Fpython-cp-cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterlamar%2Fpython-cp-cheatsheet/lists"}