5、    listnode

5.1    反转链表
while循环中引入两个中间变量pre,next存储当前节点的前一个节点和下一个节点初始值为None
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead == None or pHead.next ==None:
            return pHead

        pre = None              # 前一个节点(None初始化)
        next = None             # 下一个节点(None初始化)
        while pHead != None:
            next = pHead.next   # 先保存下一个节点
            pHead.next = pre    # 下一个节点指向前一个节点(反转链表)            
            pre = pHead         # 前一个节点更新(用于下一个循环使用,也用于返回值)
            pHead = next        # 用下一个节点替代当前节点(触发下一步循环)            
        return pre              # 原链表最后一个节点next为none, 因此循环结束返回pre

5.2    链表中的节点每k个一组翻转
1、对输出链表向尾向头赋值,引入一个临时变量next,尾部时next=None, 后续next=cur
class Solution:
    def reverseKGroup(self , head , k ):
        # write code here

        buf = []
        while head:
            buf.append(head.val)
            head = head.next

        n = len(buf)
        if n==0:
            return None

        i_max = n//k
        for i in range(i_max):
            t = buf[i*k:(i+1)*k]
            buf[i*k:(i+1)*k] = t[::-1]
        buf = buf[::-1]
        #print('buf=',buf)

        next = None
        for i in range(n):
            cur = ListNode(buf[i])
            cur.next = next
            next = cur

        return cur

5.3    链表中环的入口结点
遍历单链表的每个结点,如果当前结点地址没有出现在set中,则存入set中
否则,出现在set中,则当前结点就是环的入口结点,整个单链表遍历完,若没出现在set中,则不存在环
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here

        if not pHead or not pHead.next:
            return None

        visited = set()
        while pHead:
            if pHead not in visited:
                visited.add(pHead)
                pHead = pHead.next
            else:              
                return pHead
        return None

5.4    删除链表的倒数第n个节点
1、将链表节点加入一个List型数组 arr, 通过操作arr[i].next来实现删除
2、head实际长度可能为 0,1,2,3……,head值尽量不要动,其它操作用副本t=head
3、删除的位置在中间是正常情况,异常情况要考虑头尾,超范围等
class Solution:
    def removeNthFromEnd(self , head , n ):
        # write code here
        if not head:
            return None

        t = head
        arr = []
        while t:
            arr.append(t)
            t = t.next
        m = len(arr)

        if m==1:
            if n==1:
                return None
            else:
                return head

        if n==1:
            arr[-2].next = None
            head = arr[0]
        elif n==m:
            head = arr[1]
        elif 1<=n-1<=m and 1<=n+1<=m:
            arr[-(n+1)].next = arr[-(n-1)]
        return head

5.5    合并有序链表
1、读入两个链表合成一个list再由大小到排序
2、对输出链表向尾向头赋值,引入一个临时变量next,尾部时next=None, 后续next=cur
class Solution:
    def mergeTwoLists(self , l1 , l2 ):
        # write code here

        if l1==None and l2==None:
            return None

        tmp = []
        while l1:
            tmp.append(l1.val)
            l1 = l1.next
        while l2:
            tmp.append(l2.val)
            l2 = l2.next

        tmp = sorted(tmp,reverse=1)
        n = len(tmp)
        next = None
        for i in range(n):
            cur = ListNode(tmp[i])
            cur.next = next
            next = cur

        return cur

6、    tree

6.1    数组生成二叉树
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
L = [1,2,3,4,5,6,7,8,9]
n = len(L)
Tree = []
for i in range(n):
    Tree.append(TreeNode(L[i]))
for i in range(n):
    if 2*i+1<=n-1:
        Tree[i].left = Tree[2*i+1]
    if 2*i+2<=n-1:
        Tree[i].right = Tree[2*i+2]
root = Tree[0]

def dfs(root):
    if not root:
        return
    print(root.val, end=' ')
    dfs(root.left)
    dfs(root.right)
dfs(root)

6.2    二叉树的层序遍历
1、BFS广度优先搜索,先获得每一层需要输出节点的个数,再一个个减小到0,这一层输出结束后,再输出下一层
2、queue.insert(0, cur.left),新增节点插入到0位
class Solution:
    def levelOrder(self , root ):
        # write code here
        if not root:
            return None

        queue = [root]
        res = []
        def bfs(root):
            while queue:
                n = len(queue)
                level = []
                while n>0:
                    cur = queue.pop()
                    level.append(cur.val)
                    if cur.left:
                        queue.insert(0, cur.left)
                    if cur.right:
                        queue.insert(0, cur.right)
                    n -= 1
                res.append(level)
            return res

        return bfs(root)

6.3    二叉树的之字形层序遍历
1、BFS广度优先搜索,先获得每一层需要输出节点的个数,再一个个减小到0,这一层输出结束后,再输出下一层
2、queue.insert(0, cur.left),新增节点插入到0位
3、之字型:引入一个变量k记录奇偶层,层数从0开始,奇数层tmp.appe***al) 改成 tmp.insert(0,t.val)
class Solution:
    def zigzagLevelOrder(self , root ):
        # write code here
        if not root:
            return None

        queue = [root]
        res = []
        k = 0
        while queue:
            n = len(queue)
            tmp = []
            while n>0:
                t = queue.pop()
                #print('k=',k)
                if k%2==0:
                    tmp.appe***al)
                else:
                    tmp.insert(0,t.val)
                if t.left:
                    queue.insert(0,t.left)
                if t.right:
                    queue.insert(0,t.right)
                n -= 1
            k += 1
            res.append(tmp)
        print('res=',res)
        return res

6.4    二叉树先序,中序和后序遍历
pre = []
def dfs_pre(root):
    if not root:
        return
    pre.append(root.val)
    dfs_pre(root.left)
    dfs_pre(root.right)

mid = []
def dfs_mid(root):
    if not root:
        return
    dfs_mid(root.left)
    mid.append(root.val)    
    dfs_mid(root.right)

post = []
def dfs_post(root):
    if not root:
        return
    dfs_post(root.left)
    dfs_post(root.right)
    post.append(root.val)   

class Solution:

    def threeOrders(self , root ):
        # write code here
        dfs_pre(root)
        dfs_mid(root)
        dfs_post(root)        
        return [pre,mid,post]

6.5    二叉树中找到两个节点的最近公共祖先
1、先dfs搜索,返回节点路径
2、取路径交集返回最近的交点
def dfs(root,o1,res):
    if root.val == o1:
        #print('res=',res)
        return res
    if root.left:
        t = dfs(root.left,o1,res+[root.left.val])
        if t:
            return t
    if root.right:
        t = dfs(root.right,o1,res+[root.right.val])
        if t:
            return t

class Solution:
    def lowestCommonAncestor(self , root , o1 , o2 ):
        # write code here
        L1 = dfs(root,o1,[root.val])
        L2 = dfs(root,o2,[root.val])      
        #print(L1)
        #print(L2)
        L1 = L1[::-1]
        L2 = L2[::-1]
        for i in L1:
            for j in L2:
                if i==j:
                    return i
        return None

6.6    二叉树根节点到叶子节点和为指定值的路径
1、先dfs搜索,返回节点路径
2、当前为末端节点,且满足路径和条件,全局保存
class Solution:
    def pathSum(self , root , i ):
        # write code here
        if not root:
            return []

        res = [root.val]
        out = []
        def dfs(root,res):
            if not root.left and not root.right and sum(res)==i:
                out.append(res)     
            if root.left:     
                dfs(root.left,res+[root.left.val])
            if root.right:
                dfs(root.right,res+[root.right.val])

        dfs(root,res)
        #print('out=',out)
        return out

'''
6.7    二叉树重建
#=============================================================================================
https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=196&&tqId=37109&rp=1&ru=/activity/oj&qru=/ta/job-code-total/question-ranking

解题思路:
前序遍历:先根节点,再左子树,最后右子树
中序遍历:先左子树,再根节点,最后右子树
我们可以先从前序遍历的第一个元素得到根节点root=TreeNode(pre.pop(0))
再从中序排序中找到根节点所在位置,以这个位置为中心,可以得到二叉树的左子树与右子树
二叉树可以分开看,左子树可以看成一个新的二叉树,不断细分,可以确定到每一个叶子节点
同理,右子树也可以,看成新的二叉树,我们可以通过递归来实现
特殊情况的考虑:无论哪一个遍历为空,题目所求都没有意义
#=============================================================================================
'''
# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here

        if not pre or not tin:
            return None

        #print('pre=',pre)
        #print('tin=',tin)
        #print('---')

        val = pre.pop(0)
        root = TreeNode(val)
        i = tin.index(val)
        root.left = self.reConstructBinaryTree(pre, tin[:i])
        root.right = self.reConstructBinaryTree(pre, tin[i+1:])
        return root

pre = [1,2,3,4,5,6,7]
tin = [3,2,4,1,6,5,7]
Solution().reConstructBinaryTree(pre, tin)

'''
6.8    二叉树深度
https://www.nowcoder.com/practice/8a2b2bf6c19b4f23a9bdb9b233eefa73?tpId=196&&tqId=37055&rp=1&ru=/activity/oj&qru=/ta/job-code-total/question-ranking
'''
# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

# @param root TreeNode类 
# @return int整型
#
class Solution:
    def maxDepth(self , root ):
        # write code here

        if not root:
            return 0

        out = []
        def dfs(root,res):
            if not root:
                return
            if not root.left and not root.right:
                out.append(res)
            if root.left:
                dfs(root.left, res+[root.left.val])
            if root.right:
                dfs(root.right, res+[root.right.val])

        dfs(root,[root.val])

        depth = 0
        for i in out:
            if len(i)>depth:
                depth = len(i)

        return depth

'''
6.9    最小生成树

https://www.nowcoder.com/practice/735a34ff4672498b95660f43b7fcd628?tpId=196&&tqId=37574&rp=1&ru=/activity/oj&qru=/ta/job-code-total/question-ranking
'''
# 返回最小的花费代价使得这n户人家连接起来
# @param n int n户人家的村庄
# @param m int m条路
# @param cost int二维数组 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
# @return int
#
class Solution:
    def miniSpanningTree(self , n , m , cost ):
        # write code here

        p = list(range(n+1))
        height = [0 for _ in range(n+1)]
        cost = list(sorted(cost, key=lambda x: x[2]))
        def find(n):
            while n != p[n]:
                n = p[n]
            return n

        i = 0
        ans = 0
        for a, b, c in cost:
            if i == n - 1: break
            pa = find(a)
            pb = find(b)
            if pa == pb:
                continue
            if height[pa] > height[pb]:
                p[pb] = pa
            elif height[pb] > height[pa]:
                p[pa] = pb
            else:
                height[pb] += 1
                p[pa] = pb
            ans += c
            i += 1
        return ans

Solution().miniSpanningTree(3,3,[[1,3,3],[1,2,1],[2,3,1]])

7、    biSearch

def biSearch(L, v):
    x1 = 0
    x2 = len(L)-1    
    while x1<x2:
        #print('x1=',x1,'x2=',x2)        
        xm = (x1+x2)//2        
        if L[xm] < v:       # 注意这里<,<=要多测试
            x1 = xm+1       # 注意这里xm+1,xm要多测试
        else:
            x2 = xm
    return x1   

7.1    最长增长子序列
        L = arr
        n = len(L)
        #--------------------------------------
        # 数组B维护的是当前最长递增子序列的最小末尾值,参见下文
        # https://blog.csdn.net/sinat_31790817/article/details/78348722
        B = [L[0]]
        dp = [1]
        for i in range(1, n):
            if L[i]>B[-1]:
                B.append(L[i])
                dp.append(len(B))
            else:
                t = biSearch(B, L[i])
                B[t] = L[i]
                dp.append(t+1)
        print('B=',B)
        print('dp=',dp)

        #--------------------------------------
        # 在dp序列中反向寻找第一个出现的maxLen,maxLen-1,maxLen-2,…… 1,所对应的原数组元素
        C = []
        maxLen = max(dp)
        for i in range(len(dp)-1,-1,-1):
            if dp[i]==maxLen:
                C.append(L[i])
                maxLen -= 1
        return C[::-1]

7.2    求平方根
def f(x):
    return x*x

class Solution:
    def sqrt(self , x ):
        # write code here

        y = x        
        if y<0:
            return None
        elif y==0:
            return 0
        elif y==1:
            return 1
        else:
            x1 = 1
            x2 = x
            while x2-x1>1e-4:
                xm = (x1+x2)/2
                #print('xm=',xm)
                if (f(x1)-y)*(f(xm)-y)>0:
                    x1 = xm
                else:
                    x2 = xm
            print('x2=',x2)
            return int(x2)

7.3    求立方根
        y = float(input())
        x1 = 0.0
        if y>0:
            x2 = max(y,1)
        else:
            x2 = min(y,-1)
        f = lambda x:x**3

        k = 0
        while abs(x1-x2) > 1e-4:
            x0 = (x1+x2)/2    
            if (f(x1)-y)*(f(x0)-y)>0:
                x1 = x0
            else:
                x2 = x0    
            k += 1    
        print(round(x1*10)/10)