python_10_贪心算法

1 贪心算法

贪心算法:常用堆和排序
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.1 题目一:会议问题

在这里插入图片描述

class Program:   # 每个会议有开始时间,结束时间
    def __init__(self,start,end):
        self.start = start
        self.end = end

    # 方法一。暴力,穷举

    def bestArrange1(self,programs):
        if programs is None or len(programs) == 0:
            return 0
        return self.process(programs,0,0)

    # 还剩什么会议都放在programs里
    # done 已经安排会议的数量
    # timeLine 目前来到的时间点是什么

    # 目前来到timeLine的时间点,已经安排了done多的会议,剩下的会议programs可以自由安排
    # 返回能安排的最多会议数量
    def process(self,programs,done,timeLine):
        if len(programs) == 0:
            return done   # 会议全安排完了,返回已经安排的会议
        # 如果有会议可以选,进行下面操作
        max = done
        Programs = []      # 新会议数组
        # 当前安排的会议是什么会议,每一个都枚举
        for i in range(len(programs)):
            if programs[i].start >= timeLine:
                Programs.append(programs.pop(i))   # 将第i号会议删除,并生成一个新的programs数组
                if max < self.process(Programs,done+1,programs[i].end):
                    max = self.process(Programs,done+1,programs[i].end)   # Programs为新安排会议,开会后时间变为programs[i].end
        return max





    # 方法二:贪心算法
    def bestArrange2(self,programs):
        # 什么会议结束时间早,什么会议排在前面
        self.paixu(programs)
        timeLine = 0
        result = 0
        for i in range(len(programs)):
            if timeLine <= programs[i].start:
                result = result + 1
                timeLine = programs[i].end
        return result

    def paixu(self,programs):
        programss = []
        while len(programs) != 0:
            min = programs[0].end
            index = 0
            for i in range(1,len(programs)):
                if min > programs[i].end:
                    min = programs[i].end
                    index = i
            programss.append(programs.pop(index))
        return programss

1.2 字符串x和.,灯照亮问题

这个暴力太难了

# 灯问题
# 方法一:纯暴力
def minLight1(road):
    if road is None or len(road) == 0:      # 路没了
        return 0
    return process(list(road),0,dict())   # 0位置开始做决定,还没放灯
# 10难,存在缺陷,难
# str[index....]位置,自由选择放灯还是不放灯
# str[0...index-1]位置呢?已经做完决定了,那些放了灯的位置,存在lights里
# 要求选出能照亮所有.的方案,并且在这些有效的方案中,返回最少需要几个灯
def process(str,index,lights):
    if index == len(str):    # 当index来到终止位置时,没有位置放灯了
        # 这种方案能不能把所有位置都照亮
        for i in range(len(str)):
            if str[i] != 'X':     # 如果当前位置为点,查询是否被照亮
                if not lights.get(i-1) and not lights.get(i) and not lights.get(i+1):  # 如果没有被照亮
                    return 11111                # 返回整数最大值作为灯的数量
        return len(lights)       # 有多长就放了几盏灯
    else:   # str没有结束
        # i 位置是x或点,都可以选择不放灯
        yes = 11111
        no = process(str,index+1,lights)   # 没有把i位置扔到lights里去,i位置加一,i位置不放灯
        if str[index] == '.':
            lights.update({index:1})
            yes = process(str,index+1,lights)
            lights.pop(index)             # 恢复现场
    min = 0
    if no > yes:
        min = yes
    else:
        min = no
    return min

方法二:贪心

# 方法二:贪心
def minLight2(road):
    str = list(road)
    index = 0
    light = 0                   # 当前灯数量
    while index < len(str):     # 路没有全部遍历时
        if str[index] == 'X':   # 当走到x,不放灯
            index += 1          # 路往后走
        else:
            light += 1          # 当走到点时,一定放灯,灯的数量加,但是后面决定灯放在哪一
            if index + 1 == len(str):  # 如果放灯的数量等于路的长度,跳出循环
                break
            else:
                if str[index + 1] == 'X':   # 如果下一个是X
                    index = index + 2       # 往后跳两个再决定
                else:
                    index = index + 3
    return light    # 返回灯数量

road = "xxx.x.x.x."
print(minLight2(road))

1.3

在这里插入图片描述
在这里插入图片描述
ks + te ->ks*26的2次方+te = ks00+te = kste
blog.csdnimg.cn/447316b0c43b4e3ca84ed38247f3fe92.png)

def lowestString(strs):
    if strs == None or len(strs) == 0:
        return ""
    a = sorted(strs)          
    t = "".join(a)      # 将排序后的列表转为字符串
    res = ""
    for i in range(len(t)):
        res = res + strs[i]
    return res

1.4 返回分割最小代价

在这里插入图片描述
创建小根堆,弹两个数据结合后扔回去,堆里只剩一个数字停,所有叶子节点加起来就是代价最小(和哈夫曼树差不多)

# 小根堆
class Heap:
    def __init__(self):
        self.heap = []
        self.heapSize = 0       # 堆当前大小

    def push(self,val):
        self.heap.append(val)        # 新值在heapSize上
        self.heapInsert(self.heap,self.heapSize)
        self.heapSize = self.heapSize + 1     # heapSize有值的后一位

    def heapInsert(self,heap,heapSize):       # 小根堆规则,(heapSize - 1) / 2,可以找到父节点位置
        while heap[int(heapSize)] < heap[int((heapSize - 1) / 2)]:   # 如果小于父节点,那么就交换
            self.swap(heap,heapSize,int((heapSize - 1) / 2))
            heapSize = int((heapSize - 1) / 2)


    def swap(self,arr, i, j):
        tmp = arr[i]
        arr[i] = arr[j]
        arr[j] = tmp

    # 用户此时,返回最大值,并且在大根堆中,把最小值删除
    # 剩下的数,依然保持小根堆组织
    def pop(self):
        self.heapSize = self.heapSize - 1    # 最后一个值的位置
        self.swap(self.heap,0,self.heapSize)   # 第0位和最后一位调换位置,最后一位为最小值
        ans = self.heap.pop()
        self.heapify(self.heap,0,self.heapSize)   # 重新修复为小根堆
        return ans

    # 从index位置往下,不断下沉
    # 停:孩子都不再比我大 或 已经没有孩子了
    def heapify(self,heap,index,heapSize):
        left = index * 2 + 1     # 左孩子下标
        while left < heapSize:   # 防止越界,说明我是有左孩子的,没有越界往下执行,没有左孩子就没孩子了
            # 左右两个孩子中,谁小,谁把自己的下标给largest
            # 条件:1.有右孩子 && 2. 右孩子的值比左孩子的值大
            # 否则为左孩子
            if left + 1 < heapSize and heap[left+1] < heap[left]:
                largest = left + 1   # 那么右孩子位置给largest
            else:
                largest = left
            # largest是最大孩子的位置
            if heap[largest] >= heap[index]:  # 如果父节点值小于两孩子,lar就指向父节点
                largest = index

            if largest == index:    # 如果largest是父节点位置,不用交换,退出循环
                break

            self.swap(heap,largest,index)
            index = largest
            left = index * 2 + 1   # 继续找下一个节点的左孩子

def lessMoney(arr):
    pQ = Heap()   # 小根堆
    for i in range(len(arr)):
        pQ.push(arr[i])
    sum = 0
    while pQ.heapSize > 1:  # 只剩下一个元素,停止
        cur = pQ.pop() + pQ.pop() # 弹出两个最小的
        sum = sum + cur
        pQ.push(cur)       # 结合后放回去
    return sum

arr = [10,20,30]
print(lessMoney(arr))

1.5 项目花费最少在这里插入图片描述

class Program:
    def __init__(self,p,c):
        self.p = p         # 利润
        self.c = c         # 花费

# 最多k个项目
# w是初始资金
# profits[] 和 Capital[] 一定等长
# 返回最终最大资金
def findMaximizedCapital(k,w,Profits,Capital):
    minCostQ = []
    maxProfitQ = []
    for i in range(len(Profits)):         # 以项目类型加入到minCostQ列表中
        minCostQ.append(Program(Profits[i],Capital[i]))
    minCostQ = sorted(minCostQ, key=lambda x: x.c)      # minCostQ,按照花费值排序,从小到大
    for i in range(k):    # 最多完成k个项目
        while minCostQ and minCostQ[0].c <= w:    # 花费组不为空,且花费组最少的花费小于w的
            maxProfitQ.append(minCostQ.pop(0))    # 将花费组第一个元素弹出,也就是取出最小花费项目放到maxProfitQ数组
        maxProfitQ = sorted(maxProfitQ, key=lambda x: x.p,reverse=True)    # 加入的新元素后,对整体以利润的方式排序,最前面的利润最大
        if not maxProfitQ:   # 如果利润列表为空,结束
            return w
        w = w + maxProfitQ.pop(0).p   # 资金叠加,弹出最大利润
    return w
Profits = [2,4,3,5,8]
Capital = [1,3,1,3,4]
w = findMaximizedCapital(2,1,Profits,Capital)
print(w)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值