Sword Finger offer Online Programming (08-14) [9]

Posted by clint on Wed, 14 Aug 2019 15:48:51 +0200

Date: 2019-08-14

1. The entry node of the link in the list (inspecting knowledge points: list)

Topic Description

Give a linked list, if it contains a ring, please find the entry node of the ring of the linked list, otherwise, output null.

Analysis: In the first case, without considering the time complexity, we can use a list to store elements traversing the ring list directly. This time complexity is O(N). In storage, if the element is already in the list, it indicates the entrance to the ring list. Otherwise, continue walking backwards.

 

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not  pHead:
            return None
        p = pHead
        reslist = []
        while p:
            if p in reslist:
                return p
            else:
                reslist.append(p)
            p = p.next

The second way of thinking comes from the idea of offer ing by sword finger:

If there are n nodes in the link list, pointer P1 moves forward n steps on the list, and then the two pointers move forward at the same speed. When the second pointer points to the entry node of the ring, the first pointer has circled around the ring and returned to the entry node. But first we need to get the number of nodes in the ring. The idea of calculating the number is that the node that meets above must be in the ring, so we can start from this node and continue to move forward while counting. The next time we return to this node, we can get the number of rings.

Specifically:

  1. The first step is to find the intersection point in the ring. Point P1 and P2 at the head of the list, P1 takes one step at a time and P2 takes two steps at a time until p1==p2 finds the intersection point in the ring.
  2. The second step is to find the entrance of the ring. Next step, when p1= p2, P2 passes through 2x, p1 passes through x, suppose there are n nodes in the ring, P2 goes around 2x = n + X more than p1; n = x; we can see that P1 actually takes a step of a ring, and then P2 points to the head of the list, P1 position remains unchanged, p1,p2 goes one step at a time until p1= p2; at this time P1 points to the entrance of the ring.

 

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        # Judgment of preconditions
        if not pHead or not pHead.next or not pHead.next.next:
            return None
        # Let the slow pointer take one step at a time, and the fast pointer take two steps at a time. The first encounter must be in the ring. When meeting: Slow down x, then fast walk 2x = x + n (block actually takes an additional number of rings), so the slow pointer takes n steps altogether.
        low = pHead.next
        fast = pHead.next.next
        while low != fast:
            if not low or not fast:
                return None
            low = low.next
            fast = fast.next.next
        # When we meet, the slow pointer has already taken several steps in the ring, then let the fast pointer start from the beginning. Each time the two pointers take one step, the next encounter must be at the entrance node of the ring.
        fast = pHead
        while low != fast:
            low = low.next
            fast = fast.next
        return fast

2. Delete duplicate nodes in the linked list (inspect knowledge points: linked list)

Topic Description

In a sorted list, there are duplicate nodes. Please delete the duplicate nodes in the list. The duplicate nodes are not reserved and return to the header pointer of the list. For example, the chain table 1 - > 2 - > 3 - > 3 - > 4 - > 4 - > 5 is treated with 1 - > 2 - > 5.

The first idea is non-recursive deletion.

1. First, add a header node to facilitate the first node and the second node in the same situation.

2. Set up the pre, nex pointer, the pre pointer points to the node that is not duplicated currently, and the nex pointer is equivalent to the working pointer. Search backwards, delete the pointer that is duplicated with the current pre, and finally remember to delete the pre pointer in the current loop!

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        # First of all, judge the preconditions.
        if pHead == None or pHead.next == None:
            return pHead
        # Establish a new node to facilitate subsequent iterations
        new_head = ListNode(-1)
        new_head.next = pHead
        pre = new_head  # Set the new node to pre
        p = pHead       # Nodes that need to be judged whether they are duplicated or not need to be updated
        nex = None       # Initialize the next node
        while p != None and p.next != None:  # When p is not empty, the next node of p is not empty either. Set nex or return to the end directly.
            nex = p.next
            if p.val == nex.val:  # This if statement first fixes p, then judges the value of nex and p, if deletes nex equally, then searches continuously for repeated nex, and finally does not satisfy jumping out of the while statement for updating.
                while nex != None and nex.val == p.val:
                    nex = nex.next
                pre.next = nex
                p = nex
            else:  # If the values of p and nex are different, pre and p traverse downward to make a judgment.
                pre = p
                p = p.next
        return new_head.next  # Because new_head is a new header node, it returns its next node

The second way of thinking: Recursive thinking that some people use on cattle passengers: (time complexity is higher, after all, recursion)

class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        # Precondition
        if pHead is None or pHead.next is None:
            return pHead
        head1 = pHead.next
        if head1.val != pHead.val: # If the values of two nodes are not equal, the judgement is called recursively down
            pHead.next = self.deleteDuplication(pHead.next)
        else:
            while pHead.val == head1.val and head1.next is not None: # Otherwise, if head1.next is equal and not empty, delete head1 and loop while
                head1 = head1.next
            if head1.val != pHead.val:  # When the deletion node terminates and the nodes are unequal, the subsequent nodes of head1 are judged recursively.
                pHead = self.deleteDuplication(head1)
            else:
                return None
        return pHead

3. Next node of binary tree (inspecting knowledge point: tree)

Topic Description

Given a binary tree and one of its nodes, find the next node in the middle traversal order and return. Note that the nodes in the tree contain not only left and right child nodes, but also pointers to the parent node.

  
Ideas:

(1) If the node has a right subtree, the next node is the left-most subtree of the right subtree (as shown in Node B)

(2) If the node does not have a right subtree, there are two cases:

2.1 If the node is the left child of the parent, the next node is its parent (as shown in node D)

2.2 If the node is the right child of the parent node, it traverses upwards along the parent node until the left child of the parent node of a node is found to be the node, then the next node of the parent node of the node (as shown in Node I, B is the left child of the parent node) is found upwards along the parent node. Then the parent node A of B is the next node. The second scenario can be considered comprehensively.

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
    # write code here
        if pNode.right: #There are right subtrees
            p=pNode.right
            while p.left:
                p=p.left
            return p
        while pNode.next:   #If there is no right subtree, the first current node is the left child of the parent node.
             if(pNode.next.left==pNode):  # If the first if is set up, it indicates that it is the left child of the parent node and returns to the parent node.
                return pNode.next
             pNode = pNode.next   #Otherwise, traverse up the parent node        
        return  None  #If the root node is not found, it returns empty.

4. Symmetrical Binary Trees (Examining Knowledge Points: Trees)

Topic Description

Please implement a function to determine whether a binary tree is symmetrical. Note that if a binary tree has the same mirror image as the binary tree, it is defined as symmetric.

Analysis: There are many different processing details, some directly adopt the idea of recursion, some are to assign a tree, and then the left and right subtrees are traversed equally.

What I am using here is to go straight down and make gradual comparisons. First of all, four situations need to be judged:

The root is empty, True;

The left subtree is empty, the right subtree is not empty, False

Left subtree is not empty, right subtree is empty, False

Both left and right subtrees are empty, True

Finally, we recursively traverse the case that the left and right subtrees are not empty, and compare the values.

# -*- coding:utf-8 - * - My code, but did not pass, thinking and the latter version of the code is the same, doubtful. Is it the use of subfunctions?
# class TreeNode: 
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        if not pRoot:
            return True
        if not pRoot.left and not pRoot.right:
            return True
        if pRoot.left and not pRoot.right:
            return False
        if not pRoot.left and pRoot.right:
            return False
        while pRoot.left and pRoot.right:
            if pRoot.left.val == pRoot.right.val:
                return self.isSymmetrical(pRoot.left) and self.isSymmetrical(pRoot.right) 
            return False
        return True


# -*- coding:utf-8 -*-  # Code passed
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        def is_same(p1,p2):
            if not p1 and not p2:    # Both left and right subtrees are empty, True
                return True
            if (p1 and p2) and p1.val==p2.val:   # Neither left nor right subtrees are empty, and the values are equal.
                return is_same(p1.left,p2.right) and is_same(p1.right,p2.left)
            return False
        if not pRoot:  # The roots are empty, True
            return True
        if pRoot.left and not pRoot.right:  # The left subtree is not empty, the right subtree is empty, False
            return False
        if not pRoot.left and pRoot.right:   # Right subtree is not empty, left subtree is empty, False
            return False
        return is_same(pRoot.left,pRoot.right) # Otherwise, recursive calls

5. Print binary trees in zigzag order (inspecting knowledge points: stack + tree)

Topic Description

Please implement a function to print the binary tree in zigzag, that is, the first line is printed in left-to-right order, the second layer is printed in right-to-left order, the third line is printed in left-to-right order, and so on.

Analysis:

* Many of our implementations are to store data from each layer in ArrayList and perform reverse operations on even layers. But it's too inefficient when there's a lot of data.

If an interview is conducted, the algorithmic test is to print a zigzag binary tree, and use reverse, it will be despised. The interviewer will say that the efficiency of mass data is not at all good.

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        # write code here
        root=pRoot
        if not root:
            return []
        level=[root]
        result=[]
        lefttoright=False  # Marker, to determine whether to False from left to right or True from right to left
        while level:
            curvalues=[] # Current values, generally from left to right
            nextlevel=[]  # The node record in this layer, left node + right node
            for i in level:
                curvalues.append(i.val)
                if i.left:
                    nextlevel.append(i.left)
                if i.right:
                    nextlevel.append(i.right)
            if lefttoright:   
                curvalues.reverse() # The first floor is from left to right False, and the next floor is from right to left True.
            if curvalues:
                result.append(curvalues)  # Put the layer values in the correct order into the final result
            level=nextlevel #  level updates used in loops
            lefttoright=not lefttoright  # Changes in markers
        return result

Other methods: instead of using reverse to change the order of storage first, they are in place one step at a time:

'''Solution: Use a flag variable to mark left-to-right or right-to-right
 If you go from left to right, traverse the node current_nodes at the current level from beginning to end, then append the left child and the right child to a list new_nodes, respectively.
If you go from right to front, you traverse the current_nodes of the current layer from end to end, and insert the right child and the left child into a list new_nodes, respectively.
The resulting new_nodes are also left-to-right ordered''
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:   
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        falg = 0  # 0 means left to right, 1 means right to left
        node_list = [[pRoot]]
        result = []
        while node_list:
            current_nodes = node_list[0] # Nodes in the current layer            
            node_list = node_list[1:]
            new_nodes = [] # Next-tier nodes are stored in left-to-right order            
            res = [] # Output from the current layer
            while len(current_nodes) > 0:
                # From left to right
                if falg == 0:
                    res.append(current_nodes[0].val)
                    if current_nodes[0].left != None:
                        new_nodes.append(current_nodes[0].left)
                    if current_nodes[0].right != None:
                        new_nodes.append(current_nodes[0].right)
                    current_nodes = current_nodes[1:]
                # From right to left
                else:
                    res.append(current_nodes[-1].val)
                    if current_nodes[-1].right != None:
                        new_nodes.insert(0, current_nodes[-1].right)
                    if current_nodes[-1].left != None:
                        new_nodes.insert(0, current_nodes[-1].left)
                    current_nodes = current_nodes[:-1]
            result.append(res)
            falg = 1 - falg
            if new_nodes:
                node_list.append(new_nodes)
        return result

6. Print the binary tree into multiple rows (inspect knowledge points: tree + queue)

Topic Description

Print the binary tree layer by layer from top to bottom, and output the same layer node from left to right. Each layer outputs one line.

Analysis: This problem is simpler than the previous one. The first implementation is as follows: Store the node value from left to right and the node of left and right children of each node from left to right directly from top to bottom.

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:   
    # Returns a two-dimensional list [[1,2], [4,5]]
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        node_list = [[pRoot]]
        result = [] # The values of nodes at each level are written as a list from left to right
        while node_list:
            current_nodes = node_list[0] # Each time the first value is taken as the order of nodes from left to right in the current layer, the nodes in the current layer            
            node_list = node_list[1:]   # After that, node_list will delete and update the first value.
            new_nodes = [] # Next-tier nodes are stored in left-to-right order            
            res = [] # The value of the current layer node is output in left-to-right order
            while len(current_nodes) > 0:
                res.append(current_nodes[0].val)  # Store the value of a node in res
                if current_nodes[0].left != None:  #The left and right child nodes of the node store current_nodes in sequence
                    new_nodes.append(current_nodes[0].left)
                if current_nodes[0].right != None:
                    new_nodes.append(current_nodes[0].right)
                current_nodes = current_nodes[1:]  # Delete and update of current node
            result.append(res)
            if new_nodes:
                node_list.append(new_nodes)
        return result

A more concise implementation is to initialize two lists and use res as the maximum list for storing the row value of each row node. tmp is used to store continuously updated current nodes.

1. First, update and store the row value of each row node, and save it in res.

2. Then update the TMP of the node in the layer: delete the node in the layer (from left to right), and get the node of the left and right children into the tmp. [Note: There is only a len(tmp) loop for the number of nodes in this layer: delete and update]

# -*- coding:utf-8 -*-  # Personal support for this, easy to understand
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:   
    # Returns a two-dimensional list [[1,2], [4,5]]
    def Print(self, pRoot):
        # write code here
        if not pRoot: # If the root node is empty, the final result is also empty.
            return []
        res = []  # A large list for storing row s of node values at each level
        tmp = [pRoot]  # Nodes used to store the current layer, in left-to-right order
        while tmp:
            row = [] # Storage of node values at the layer to form a small list
            for i in tmp:
                row.append(i.val)
            res.append(row)  # After storing the node value of the layer, the tmp of the node storing the layer is deleted and updated.
            for i in range(len(tmp)):
                t = tmp.pop(0)  # Delete the node from left to right while storing the left and right child nodes of the node
                if t.left:
                    tmp.append(t.left)
                if t.right:
                    tmp.append(t.right)
        return res
                    

7. Serialized Binary Tree (Queue + Tree for Knowledge Points)

Topic Description

Please implement two functions to serialize and deserialize the binary tree, respectively

The serialization of binary tree means that a binary tree is saved as a string in a certain format according to the result of a certain traversal way, so that the binary tree built in memory can be persisted. Serialization can be modified by binary tree traversal based on order, middle order, post order and sequence. The result of serialization is a string. When serialization, empty nodes (#) are represented by some symbol. Represents the end of a node value.


Deserialization of a binary tree is to reconstruct a binary tree based on the result str of a serialized string obtained in a certain traversal order.