数据结构与算法--python学习笔记一(听了左神的课,自己整理的,左神还是强啊)(前面提到的方法有的在后面的博客里)

import random
import numpy as np
import copy
import functools

# 综合排序的方式选择从样本容量和稳定性角度考虑:当样本量较小时,选择插入排序,即使是O(N**2),但常数项极低。
#       当排序的是基础类型,使用快排,因为不计较稳定性。当排序的是自定义类时,使用归并排序,需要考虑稳定性。
# processArray(size, start, end):产生[start, end]的size大小的随机整数数组
# bubbleSort(alist):冒泡排序,时间复杂度O(N**2)
# selectionSort(alist):选择排序,时间复杂度O(N**2),额外空间复杂度O(1)
# insertionSort(alist):插入排序,时间复杂度O(N**2)
# mergeSort(alist):归并排序,时间复杂度O(NlogN),额外空间复杂度O(n)
# NetherLandsFlag(alist, num):荷兰国旗问题(将数组调整为,左面比这个数小,中间和这个数相等,右面比这个数大),时间复杂度O(N),额外空间复杂度O(1)
# quickSort(alist):快速排序(最差时间复杂度O(N**2)),随机快速排序(期望时间复杂度O(N*logN),额外空间复杂度O(logN)(划分点的存储))
# heapSort(alist):堆排序
# maxGap(alist):通过桶排序实现了两个相邻数的最大差值
# rotateMatrix(matrix): 旋转正方形矩阵90度
# isPalindrome(pHead): 判断链表是否是回文结构,时间复杂度O(N),额外空间复杂度O(1)
# listPartition(pHead, num): 将链表调整为左面的数比num小,中间的数和num相等,右面的数大于num,时间复杂度为O(n),额外空间复杂度O(1)
# copyListWithRand(pHead): 复制复杂链表(节点指针包括随机指针),(使用字典,键为原来的节点,值为复制后的节点)
# copyListWithRand2(pHead): 复制复杂链表(在原有节点的基础上1->1`->2->2`->3->3`...,然后再将复制后的节点提出)
# getCommonNode():  求两个链表相交,求第一个公共节点(需要考虑单链表是否有环等)
# preOrderRecur(pHead): 先序遍历(递归版本)
# preOrderUnRecur(pHead): 先序遍历(非递归版本)
# serialByPre(pHead): 先序遍历序列化
# inOrderRecur(pHead): 中序遍历(递归版本)
# inOrderUnRecur(pHead): 中序遍历(非递归版本)
# posOrderRecur(pHead): 后序遍历(递归版本)
# posOrderUnRecur(pHead): 后序遍历(非递归版本)
# getSuccessorNode(node): 通过对节点中增加父节点指针,寻找节点的后继节点
# SerialByLevel(pHead): 按层遍历序列化
# reconByLevelString(levelStr):按层遍历反序列化
# isBalanceTree(pHead): 判断一棵树是否是平衡二叉树
# isBST(pHead): 判断一棵树是否是搜索二叉树
# isCBT(pHead): 判断一棵树是否是完全二叉树
# getTreeNodeNum(pHead): 求一颗完全二叉树的节点数,时间复杂度O((logN)**2)
# countIslands(matrix): 矩阵中有多少个岛
# Trie(): 前缀树
# 贪心策略: lowestString(strsList): 给定一个字符串类型的数组strsList,找到一种拼接方式,使得把所有字符串拼起来之后形成的字符串具有最低的字典序
#           lessMoney(alist): 哈夫曼编码问题
#           findMaximizedCapital(k, w, profitsList, capitalList):项目利润列表profitsList,成本列表capitalList。k个项目,w为起始资金
#           bestArrangement(programs, startTime): 会议室安排项目宣讲,安排尽可能多的项目
# 递归: hanoiProcess(n, fromStr, toStr, helpStr): 汉诺塔(递归)
#       printAllSub(str1, index, resultStr): 打印字符串所有的子序列
#       minPath1(matrix): 求矩阵中从左上角到右下角,所经节点的和最小
#       isSum1(arr1, aim): 数组中数字累加和能否正好是aim
#       coins(alist, aim): 再给定一个整数aim代表要找的钱数,求换钱有多少种方法
#              由暴力递归改成动态规划: coins2(alist, aim)、coins3(alist, aim)、coins4(alist, aim)
#       winCard1(alist):  排成一条线的纸牌博弈问题
#              由暴力递归改成动态规划: winCard2(alist)
#       ways(N, curPosition, restSteps, K):机器人处于位置M,经过P步后,走到位置K,一共有多少种方法
#              由暴力递归改成动态规划: ways2(N, curPosition, restSteps, K)
#       isMatch(str1, str2):  带有‘.’和‘*’的字符串匹配问题
#              由暴力递归改成动态规划: isMatchDPMatrix(str1, str2)
# getIndexOf(str1, str2): 使用KMP算法,检验str2是否是str1的子串
#       KMP应用:判断一棵树是否是另一棵树的子树(将两棵树进行序列化,如果这棵树序列化后的字符串是另一个字符串的子串,则满足)
# maxLcpsLength(str1): Manacher算法,求解最长回文子串的长度。
# shortestEnd(str1): 利用Manacher算法求解在字符串末尾添加最短字符串使整体构成回文串
# getMinKNumsByBFPRT(alist, k):  应用BFPRT算法求解数组中第k个小的数,并将前k个数返回
# getMaxWindow(alist, w): 应用双端队列,求解固定大小为w的窗口内的最大值
# getNum(arr, num): 应用双端队列求解,满足子数组中最大值和最小值的差值小于num的子数组的数量
# drabStrack(alist): 利用单调栈求解数组中左面离它最近的比它小的数的索引和右面最近的比它小的数的索引
# maxRecFromBottom(heightList): 应用单调栈求分布直方图中的最大面积
# maxRecSize(matrix): 应用单调栈求,全是1或0的所有矩形区域中,最大的矩形区域为1的数量
# morris(pHead): Morris遍历,利用叶节点的左右指针指向空的这个空间实现了额外空间复杂度为O(1)的遍历
# morrisPre(pHead):Morris先序遍历
# morrisIn(pHead):Morris中序遍历
# morrisPos(pHead): Morris后序遍历
# maxLength(alist, aim): 给定数组,返回满足累加和为aim的子数组的最大长度
# mostEOR(alist): 将给定数组进行分组,保证每组的异或和为0,返回最多的子数组数
# MaxDistanceInTree(pHead): 节点A走到节点B的距离为:A走到B最短路径上的节点个数。求一颗二叉树上的最远距离
# getMaxHuo(pHead): 活跃度的计算
# MyCache(object):  自定义一种缓存结构(LRU),实现某些特定功能
# LFUCache(object): 应用二维双向链表,在LRU的基础上实现了set()和get()的时间复杂度均是O(1)
# getValueFromStr(str1):  给定字符串,字符串表示一个公式,可能有整数、加减乘除符号和左右括号,返回公式计算结果
# SkipList(object):  跳表结构,跳跃表是为了解决平衡树插入或者删除操作过于复杂而进行设计的。
#       采用了随机的思想简化了维持平衡的过程,而保持查找的时间复杂度依旧是O(logN)
# maxLengthAwesom(alist, aim): 给定数组和一个整数aim,求累加和小于等于aim,的最长子数组。时间复杂度O(N)
# josephusKill2(pHead, m): 环形单链表的约瑟夫问题,链表长度N,时间复杂度O(N)
# isMatch(str1, str2):  带有‘.’和‘*’的字符串匹配问题
# getMinSteps(eggNum, floorNum):  扔鸡蛋问题(动态规划)


def processArray(size, start, end):
    alist1 = [None] * size
    alist2 = [None] * random.randint(0, size)
    for i in range(len(alist2)):
        randomNum = random.randint(start, end)
        while randomNum in alist2:
            randomNum = random.randint(start, end)
        alist2[i] = randomNum
    for i in range(size):
        randomNum = random.randint(start, end)
        while randomNum in alist1:
            randomNum = random.randint(start, end)
        alist1[i] = randomNum
    return alist1, alist2


def insertionSort(alist):
    """插入排序"""
    if len(alist) < 2:
        return alist
    for i in range(1, len(alist)):
        j = i
        while alist[j] < alist[j - 1] and j > 0:
            alist[j], alist[j - 1] = alist[j - 1], alist[j]
            j = j - 1
    return alist


def selectionSort(alist):
    """选择排序"""
    if len(alist) < 2:
        return alist
    for i in range(len(alist) - 1):
        minIndex = i
        for j in range(i + 1, len(alist)):
            minIndex = j if alist[j] < alist[minIndex] else minIndex
        alist[i], alist[minIndex] = alist[minIndex], alist[i]
    return alist


def bubbleSort(alist):
    """冒泡排序"""
    if len(alist) < 2:
        return alist
    for end in range(len(alist) - 1, 0, -1):
        for i in range(end):
            if alist[i] > alist[i + 1]:
                alist[i], alist[i + 1] = alist[i + 1], alist[i]
    return alist


def mergeSort(alist):
    """归并排序"""
    if alist == [] or len(alist) < 2:
        return alist
    mid = len(alist) // 2
    leftList = mergeSort(alist[:mid])
    rightList = mergeSort(alist[mid:])
    resultList = []
    leftIndex, rightIndex = 0, 0
    while leftIndex < len(leftList) and rightIndex < len(rightList):
        if leftList[leftIndex] < rightList[rightIndex]:
            resultList.append(leftList[leftIndex])
            leftIndex += 1
        else:
            resultList.append(rightList[rightIndex])
            rightIndex += 1
    resultList += leftList[leftIndex:]
    resultList += rightList[rightIndex:]
    return resultList


def quickSort(alist):
    """快速排序"""
    if alist == [] or len(alist) < 2:
        return alist
    quickSortProcess(alist, 0, len(alist) - 1)
    return alist


def quickSortProcess(arr, start, end):
    if start < end:
        # 随机快速排序是随机选取一个数作为标准值进行排序
        # 经典快速排序是直接将最后一个值作为标准值进行比较排序
        temp = random.randint(start, end)
        arr[temp], arr[end] = arr[end], arr[temp]
        lessRight, moreRight = partition(arr, start, end)
        quickSortProcess(arr, start, lessRight - 1)
        quickSortProcess(arr, moreRight + 1, end)


def partition(arr, start, end):
    cur, less, more = start, start - 1, end
    while cur < more:
        if arr[cur] < arr[end]:
            arr[cur], arr[less + 1] = arr[less + 1], arr[cur]
            cur += 1
            less += 1
        elif arr[cur] > arr[end]:
            arr[cur], arr[more - 1] = arr[more - 1], arr[cur]
            more -= 1
        else:
            cur += 1
    arr[more], arr[end] = arr[end], arr[more]
    return less + 1, more


def heapSort(alist):
    """堆排序"""
    if len(alist) < 2:
        return alist
    for i in range(len(alist)):
        heapInsert(alist, i)
    heapSize = len(alist)
    alist[0], alist[heapSize - 1] = alist[heapSize - 1], alist[0]
    heapSize -= 1
    while heapSize > 0:
        heapify(alist, 0, heapSize)
        alist[0], alist[heapSize - 1] = alist[heapSize - 1], alist[0]
        heapSize -= 1
    return alist


def heapInsert(alist, index):
    """建立大根堆结构"""
    while alist[index] > alist[(index - 1) // 2] and ((index - 1) // 2 >= 0):
        alist[index], alist[(index - 1) // 2] = alist[(index - 1) // 2], alist[index]
        index = (index - 1) // 2


def heapify(alist, index, heapSize):
    left = index * 2 + 1
    while left < heapSize:
        largest = left + 1 if left + 1 < heapSize and alist[left + 1] > alist[left] else left
        largest = largest if alist[largest] > alist[index] else index
        if largest == index:
            break
        alist[largest], alist[index] = alist[index], alist[largest]
        index = largest
        left = index * 2 + 1


def maxGap(alist):
    """桶排序"""
    if alist is None or len(alist) < 2:
        return 0

    n = len(alist)
    minNum = min(alist)
    maxNum = max(alist)

    if minNum == maxNum:
        return 0

    bucketBool = [False] * (n + 1)
    bucketMax = [0] * (n + 1)
    bucketMin = [0] * (n + 1)

    for i in range(n):
        bid = bucket(alist[i], n, minNum, maxNum)
        bucketMin[bid] = min(bucketMin[bid], alist[i]) if bucketBool[bid] else alist[i]
        bucketMax[bid] = max(bucketMax[bid], alist[i]) if bucketBool[bid] else alist[i]
        bucketBool[bid] = True
    res = 0
    lastMax = bucketMax[0]
    for i in range(n + 1):
        if bucketBool[i]:
            res = max(res, bucketMin[i] - lastMax)
            lastMax = bucketMax[i]
    return res


def bucket(num, n, minNum, maxNum):
    return int((num - minNum) * n / (maxNum - minNum))


def NetherLandsFlag(alist, num):
    start, cur, end = -1, 0, len(alist)
    while cur < end:
        if alist[cur] < num:
            alist[start + 1], alist[cur] = alist[cur], alist[start + 1]
            start += 1
            cur += 1
        elif alist[cur] > num:
            alist[cur], alist[end - 1] = alist[end - 1], alist[cur]
            end -= 1
        else:
            cur += 1
    return alist


def rightMethod(alist):
    """绝对正确的方法"""
    return alist


def copyArray(alist):
    """产生一个相同的数组"""
    # if alist == []:
    #     return []
    # res = [None] * len(alist)
    # for i in range(len(alist)):
    #     res[i] = alist[i]
    res = copy.deepcopy(alist)
    return res


def testMain():
    testTimes = 50000
    size = 10
    start, end = 0, 100
    testFlag = True
    for i in range(testTimes):
        arr1, arr2 = processArray(size, start, end)
        res1 = copyArray(arr2)
        res2 = copyArray(arr2)
        resultList1 = heapSort(res1)
        resultList2 = mergeSort(res2)
        if resultList1 != resultList2:
            testFlag = False
    if testFlag:
        print("方法测试正确!")
    else:
        print('arr1: ', arr2)
        print('resultList1: ', resultList1)
        print('resultList2: ', resultList2)


def rotateMatrix(matrix):
    """旋转矩阵90度"""
    tR, tC, dR, dC = 0, 0, len(matrix) - 1, len(matrix[0]) - 1
    while tR < dR:
        rotateEdge(matrix, tR, tC, dR, dC)
        tR += 1
        tC += 1
        dR -= 1
        dC -= 1
    return matrix


def rotateEdge(matrix, tR, tC, dR, dC):
    for i in range(dR - tR):
        matrix[tR][tC + i], matrix[tR + i][dC], matrix[dR][dC - i], matrix[dR - i][tC] = \
            matrix[dR - i][tC], matrix[tR][tC + i], matrix[tR + i][dC], matrix[dR][dC - i]


class listNode(object):
    def __init__(self, value):
        self.value = value
        self.next = None


class treeNode(object):
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None


def isPalindrome(pHead):
    """判断链表是否是回文结构"""
    if pHead is None or pHead.next is None:
        return True
    quickPoint = pHead
    slowPoint = pHead
    while quickPoint.next is not None and quickPoint.next.next is not None:
        quickPoint = quickPoint.next.next
        slowPoint = slowPoint.next
    # 此时slowPoint指向的是中点位置
    tempPoint = slowPoint.next
    slowPoint.next = None
    while tempPoint is not None:
        tempPoint2 = tempPoint.next
        tempPoint.next = slowPoint
        slowPoint = tempPoint
        tempPoint = tempPoint2
    point1 = pHead
    point2 = slowPoint
    res = True
    while point1 is not None and point2 is not None:
        if point1.value != point2.value:
            res = False
            break
        point1 = point1.next
        point2 = point2.next
    # 检查完后需要将原来逆序的部分进行还原
    tempPoint = slowPoint.next
    slowPoint.next = None
    while tempPoint is not None:
        tempPoint2 = tempPoint.next
        tempPoint.next = slowPoint
        slowPoint = tempPoint
        tempPoint = tempPoint2
    return res


def listPartition(pHead, num):
    """调整链表顺序,满足左面的部分比num小,中间的部分和num相等,右面的部分比num大"""
    sH, sT = listNode(None), listNode(None)  # small head, small tail
    eH, eT = listNode(None), listNode(None)  # equal head, equal tail
    bH, bT = listNode(None), listNode(None)  # big head, big tail
    nextNode = listNode(None)
    while pHead is not None:
        nextNode = pHead.next
        pHead.next = None
        if pHead.value < num:
            if sH is None:
                sH, sT = pHead, pHead
            else:
                sT.next = pHead
                sT = pHead
        elif pHead.value == num:
            if eH is None:
                eH, eT = pHead, pHead
            else:
                eT.next = pHead
                eT = pHead
        else:
            if bH is None:
                bH, bT = pHead, pHead
            else:
                bT.next = pHead
                bT = pHead
        pHead = nextNode
    if sT is not None:
        sT.next = eH
        eT = sT if eT is None else eT
    if eT is not None:
        eT.next = bH
    return sH if sH is not None else eH if eH is not None else bH


def copyListWithRand(pHead):
    """复制复杂链表(带有随机指针)"""
    nodeDict = {}
    cur = pHead
    while cur:
        nodeDict.update({cur: listNode(cur.value)})
        cur = cur.next
    cur = pHead
    while cur:
        nodeDict.get(cur).next = nodeDict.get(cur.next)
        nodeDict.get(cur).rand = nodeDict.get(cur.rand)
        cur = cur.next
    return nodeDict.get(pHead)


def copyListWithRand2(head):
    """复制复杂链表(带有随机指针)"""
    if not head:
        return None
    cur = head
    while cur:
        nextNode = cur.next
        cur.next = listNode(cur.val)
        cur.next.next = nextNode
        cur = nextNode
    cur = head
    while cur:
        nextNode = cur.next.next
        copyNode = cur.next
        copyNode.random = cur.random.next if cur.random is not None else None
        cur = nextNode
    res = head.next
    cur = head
    while cur:
        nextNode = cur.next.next
        copyNode = cur.next
        cur.next = nextNode
        copyNode.next = nextNode.next if nextNode is not None else None
        cur = nextNode
    return res
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值