<jupyter_start><jupyter_text>String<jupyter_code>s1=str()
s2="Arkytiao"
print(len(s2))
print(s2[-3:])
print(s2[5:8])
print(s2[:5])
s2+="tiao"
print(s2)
print(list(s2))
print(s2[4])
print(s2.index('a'))
print(s2.find('A'))
print(s2.find('c')) #not found, return -1<jupyter_output>8
iao
iao
Arkyt
Arkytiaotiao
['A', 'r', 'k', 'y', 't', 'i', 'a', 'o', 't', 'i', 'a', 'o']
t
6
0
-1<jupyter_text>Linked List Do not have adjacent memory location, only request additional memory when new item is added - saves memoryworst case find time O(n)Add or delege O(1)<jupyter_code>class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None
    def reverse(self, head):
        prev = None #prev, head->head.next
        while head: #traverse with head directly because the last node visited will be head
            #flip
            temp = head.next #head->temp
            head.next = prev #prev<-head, temp
            #forward
            prev, head = head, temp #prev, head->
            #until temp is none, then prev is the final head
        return prev
class DListNode: #doubly linked list
    def __init__(self, val):
        self.val = val
        self.prev = self.next = None
    def __repr__(self):
        return str(self.val)
class LinkedList:
    """A Linked List construction of DListNode"""
    def __init__(self,head):
        self.head = head
    def reverse(self):
        curt = None #do not use prev here because prev is already in definition
        head = self.head
        while head:
            print(head)
            #forward
            curt = head #curt
            head = curt.next #curt->head
            #flip
            curt.next, curt.prev = curt.prev, head #curt.prev<-curt<-head
        self.head = curt
    def delete(self, val):
        if not self.head:
            print("value not in list")
            return
        dummy = DListNode(None)
        dummy.next = self.head
        cur = dummy
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
                if cur.next.next:
                    cur.next.next.prev = cur
            cur = cur.next
        self.head = dummy.next
    def __repr__(self): 
        """
        display linked list as val->val->val... """
        li = []
        head = self.head
        while head:
            li.append(str(head.val))
            head = head.next
        return "->".join(li)
            
n1 = DListNode(1)
n2 = DListNode(2)
n3 = DListNode(3)
n1.next = n2
n2.prev, n2.next = n1, n3
n3.prev = n2
li = LinkedList(n1)
print(li)
li.delete(2)
print(li)<jupyter_output>1->2->3
1->3<jupyter_text>Binary Tree      $2^{i-1}$ nodes on i'th level      depth k -> total $2^k-1$ nodes for full tree      complete binary tree: all filled except last right leaves   Tree traversal  Depth First      Pre-order: root, left, right      In-order: left, root, right      Post-order: left, right, root  Breadth Firstroot, level_1 from left to right, level_2 from left to right... BST every left < current < rightinorder traversal gives ordered list reference: https://www.tutorialspoint.com/python_data_structure/python_tree_traversal_algorithms.htm<jupyter_code>class Tree:
    def __init__(self, data=None):
        self.left, self.right, self.data = None, None, data
    def insert(self, data):
        if not self.data:
            self.data=data
            return
        if data<self.data:
            if self.left is None:
                self.left = Tree(data)
            else:
                self.left.insert(data)
        else:
            if self.right is None:
                self.right = Tree(data)
            else:
                self.right.insert(data)
    def inorderTraversal(self,node):
        res=[]
        if node:
            res = self.inorderTraversal(node.left)
            res.append(node.data)
            res = res + self.inorderTraversal(node.right)
        return res
    def preorderTraversal(self,node):
        res=[]
        if node:
            res.append(node.data)
            res = res+ self.preorderTraversal(node.left)
            res = res+ self.preorderTraversal(node.right)
        return res
    def postorderTraversal(self,node):
        res=[]
        if node:
            res = res + self.postorderTraversal(node.left)
            res = res + self.postorderTraversal(node.right)
            res.append(node.data)
        return res
    

root = Tree()
root.insert(14)
root.insert(35)
root.insert(10)
root.insert(19)
root.insert(31)
root.insert(42)
print(root.inorderTraversal(root))<jupyter_output>[10, 14, 19, 31, 35, 42]
{'fraction_non_alphanumeric': 0.11690842173630656, 'fraction_numerical': 0.016237280796709243, 'mean_word_length': 2.065693430656934, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 21, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '230016', 'license': 'MIT', 'n_tokens_mistral': 1528, 'n_tokens_neox': 1481, 'n_words': 405, 'path': 'basics/L1_string_LL_Tree.ipynb', 'repo_name': 'qyangaa/algorithm_practice', 'size': '4619'}