递归的改造——间隔挑硬币

【信息科学与工程学】【控制科学】第二篇 决策控制与决策科学01 多属性决策分析马尔可夫决策过程和行为决策理论。多属性决策分析:静态、多准则决策问题的结构化方法马尔可夫决策过程:动态、序贯决策的数学框架行为决策理论:描述实际决策行为的心理学基础每个表格都严格遵循要求的18个维度理论基础(定理/规律/数学特征)算法实现核心数学描述关键参数精度与误差分析边界条件影响因素计量方法多学科关联实现目标完整工作流程应用场景优点与局限瓶颈知识连接点决策控制知识体系的特点多层次:从描述性(行为理论)到规范性(MCDA、MDP)多学科。 阅读详情

递归的改造

接前面

把前面写的汉诺塔递归函数改成非递归方式。这只是个开场白,他们享受的是慢时光,寺庙又不加班。这个故事只是叫我们敬畏智慧,沉下心来。

递归函数都可以转成非递归函数

书上说所有的递归调用都可以改成非递归调用的方式。那是编译器,解释器的工作。计算机是用栈处理递归的,但处理深度有限。自己改没说一定要用栈。比如兔子数列
在这里插入图片描述

兔子数列

这里还使用了存储的方法,提高运行速度。

def memorizeFib(x):
    memo = [0, 1, 1, 2, 3]
    if len(memo)-1 >= x:
        return memo[x]
    else:
        while len(memo)-1 < x:
            memo.append(memo[-1] + memo[-2])
        return memo[x]

非递归快速排序

离智慧再近一点,‘非递归快速排序’1500个数据就出现调用深度报错。改成后进先出的栈就可以了。不用换成资源更好的电脑,搏一搏单车当摩托。

广度优先

广度优先里是没有递归调用的,比如红黑树转2-3-4树——雨后春笋的层序打印,层序打印比递归的前中后根更直观。在改造递归调用的时候可以考虑一下广度优先。

间隔一个选硬币

硬币价值[14,3,27,4,5,15,1,],一次最多只能拿一枚,就是要间隔至少一枚才能拿后面的,应该怎么选?

递归调用法

def coins(row, table):
    '''至少隔一个才能选的硬币
    Arguments:
        row:硬币列表
        table:记录所选硬币总金额的字典
    Return:
        result:所选最大金额
        table:记录所选硬币总金额的字典,用于打印选择的路径
    '''
    if len(row) == 0:
        table[0] = 0
        return 0, table
    elif len(row) == 1:
        table[1] = row[0]
        return row[0], table
    #第0个选后跳一个选row[2:]
    pick = coins(row[2:],table)[0] + row[0]
    #第0个跳过选row[1:]
    skip = coins(row[1:],table)[0]
    result = max(pick, skip)
    table[len(row)] = result
    return result, table

打印

>>>print(coins(row, {}))
(56, {1: 1, 0: 0, 2: 15, 3: 15, 4: 19, 5: 42, 6: 42, 7: 56})

可以了吗?似乎总有点不放心,把1改成100试试。
(146, {1: 100, 0: 0, 2: 100, 3: 105, 4: 105, 5: 132, 6: 132, 7: 146})
观察打印的字典会发现它是从后面往前面选的。递归真是个叛离的孩子。

递归与回溯

回溯打印选择过程

def traceback(row, table):
    '''打印选择的硬币
    Arguments:
        row:硬币列表
        table:记录所选硬币总金额的字典
    Return:
        打印选择的硬币select
    '''
    select = []
    i = 0#从后面复盘路径
    while i < len(row):
        if (table[len(row)-i] == row[i])\
           or(table[len(row)-i] ==\
              table[len(row)-i-2] + row[i]):
            select.append(row[i])
            i += 2
        else:
            i += 1
    print('Selected coins are', select, 'and sum up to', table[len(row)])
>>> result,table = coins(row,{})
>>> traceback(row, table)
Selected coins are [14, 27, 5, 100] and sum up to 146

存储中间变量改造

跟前面的兔子数列一样,存储中间变量改造递归调用。

def coinsMemorize(row, memo):
    print('this is len(memo)',len(memo))
    if len(row) == 0:
        memo[0] = 0
        return (0, memo)
    elif len(row) == 1:
        memo[1] = row[0]
        return (row[0], memo)
    try:
        return (memo[len(row)], memo)
    except KeyError:
        pick = coinsMemorize(row[2:], memo)[0] + row[0]
        skip = coinsMemorize(row[1:], memo)[0]
        result = max(pick, skip)
        memo[len(row)] = result
        return (result, memo)

递归改造成迭代

1,用字典table类似中间变量的增加来选。
2,考虑table0,1的基础情况。
3,参照前面递归的从后面选。

def coinsIterative(row):
    '''至少隔一个才能选的硬币,从后往前
    Arguments:
        row:硬币列表
    Return:
        result:所选最大金额
        table:记录所选硬币总金额的字典,是从后往前的。        
    '''
    table = {}
    table[0] = 0
    table[1] = row[-1]
    for i in range(2, len(row)+1):
        skip = table[i-1]
        pick = table[i-2] + row[-i]
        result = max(pick, skip)
        table[i] = result
    return table[len(row)], table    
>>> _, table = coinsIterative(row)
traceback(row, table)(146, {0: 0, 1: 100, 2: 100, 3: 105, 4: 105, 5: 132, 6: 132, 7: 146})
Selected coins are [14, 27, 5, 100] and sum up to 146

能从前面选吗?

递归调用与回溯

把-1改成0,-i改成i-1

def coinsIterative2(row):
    '''至少隔一个才能选的硬币
    Arguments:
        row:硬币列表
    Return:
        result:所选最大金额
    '''
    table = {}
    table[0] = 0
    table[1] = row[0]
    for i in range(2, len(row)+1):
        skip = table[i-1]
        pick = table[i-2] + row[i-1]
        result = max(pick, skip)
        table[i] = result
    return table[len(row)], table
>>> print('coinsIterative:',coinsIterative2(row))
coinsIterative: (146, {0: 0, 1: 14, 2: 14, 3: 41, 4: 41, 5: 46, 6: 56, 7: 146})
>>> 

真的可以!
原来就是先选一个;第二个大就改第二个;第三步可能用第二步的,也可能是第三个加第一步的;后面都是用前一步或者前前步加一个。如果从中间看书的,一定不会再往前面看了。
停一下,感受僧人的智慧。他们一定知道所有的细节,比如汉诺塔的移动次数是 2 n − 1 2^n-1 2n−1。
是否可以在max选择的时候直接打印路径,我试了,但是打印不了。应该是选来选去,中间会有很多变化,还是要回溯好。看来要回溯的时候,递归是首选。
递归调用与回溯

间隔两个硬币

现在最多可以连续选两枚硬币,但是选了之后要至少间隔两枚硬币。

递归调用

还是先看递归调用方法。

def coins2(row, table):
    if len(row) == 0:
        table[0] = 0
        return 0, table
    elif len(row) == 1:
        table[1] = row[0]
        return row[0], table
    #选了0、1就要从4开始选
    pick1 = coins2(row[4:], table)[0] + row[0] + row[1]
    #只选0,可以从3开始选
    pick2 = coins2(row[3:], table)[0] + row[0]
    #0不选,就从1开始选
    pick3 = coins2(row[1:], table)[0]
    #0、1不选,就从2开始选
    pick4 = coins2(row[2:], table)[0]    
    result = max(pick1, pick2, pick3, pick4)
    table[len(row)] = result
    return (result, table)
>>> print('coinsIterative:',coins2(row,{}))
coinsIterative: (145, {0: 0, 1: 100, 2: 115, 3: 115, 4: 115, 5: 142, 6: 145, 7: 145})
>>> 

推导

重点。

    elif len(row) == 2:#一次最多连续选择两枚,下次选择至少跳过两枚,选两个跳两个吧
        table[2] = row[0] + row[1]
        return table[2], table

    elif len(row) == 3:
        table[3] = max(row[0]+row[1],row[1]+row[2])
        return table[3], table
    elif len(row) == 4:
        table[4] = max(row[0]+row[1],row[1]+row[2],row[2]+row[3],row[0]+row[3])
        return table[4], table    
    elif len(row) == 5:
        table[5] = max(row[0]+row[1]+row[4],row[1]+row[2],row[2]+row[3],
                       row[3]+row[4],row[0]+row[3]+row[4])
        return table[5], table
    elif len(row) == 6:
        table[6] = max(row[0]+row[1]+row[4]+row[5],row[1]+row[2]+row[5],row[2]+row[3],
                       row[0]+row[3]+row[4])
        return table[6], table
    elif len(row) == 7:
        table[7] = max(row[0]+row[1]+row[4]+row[5],row[0]+row[1]+row[5]+row[6],
                       row[0]+row[3]+row[4],row[0]+row[4]+row[5],row[0]+row[5]+row[6],
                       row[1]+row[2]+row[5]+row[6],row[2]+row[3]+row[6])
        return table[7], table

我是把7种情况都写了,再参照前面间隔一枚硬币的迭代方法。

def coins2Iterative(row):
    table = {}
    table[0] = 0
    table[1] = row[0]
    table[2] = row[0] + row[1]
    table[3] = max(table[2], row[2] + row[1])
    table[4] = max(table[3], row[3] + row[2],
                   row[3] + table[1])
    table[5] = max(table[4], row[4] + row[3] + table[1],
                 row[4] + table[2])
    table[6] = max(table[5] , row[5] + row[4] + table[2],
                 row[5] + table[3])
    for i in range(5, len(row) + 1):
        #print(i)
        table[i] = max(table[i-1],row[i-1] + row[i-2] + table[i-4],
                       row[i-1] + table[i-2])
    return table[len(row)], table

一百个硬币

间隔两枚所选择的硬币打印还没有完成。可以打印选择的总价值。

>>> print('一百个硬币:',coins2Iterative(list(range(100))))
一百个硬币: (2525, {0: 0, 1: 0, 2: 1, 3: 3, 4: 5, 5: 7, 6: 10, 7: 14, 8: 18, 9: 22, 10: 27, 11: 33, 12: 39, 13: 45, 14: 52, 15: 60, 16: 68, 17: 76, 18: 85, 19: 95, 20: 105, 21: 115, 22: 126, 23: 138, 24: 150, 25: 162, 26: 175, 27: 189, 28: 203, 29: 217, 30: 232, 31: 248, 32: 264, 33: 280, 34: 297, 35: 315, 36: 333, 37: 351, 38: 370, 39: 390, 40: 410, 41: 430, 42: 451, 43: 473, 44: 495, 45: 517, 46: 540, 47: 564, 48: 588, 49: 612, 50: 637, 51: 663, 52: 689, 53: 715, 54: 742, 55: 770, 56: 798, 57: 826, 58: 855, 59: 885, 60: 915, 61: 945, 62: 976, 63: 1008, 64: 1040, 65: 1072, 66: 1105, 67: 1139, 68: 1173, 69: 1207, 70: 1242, 71: 1278, 72: 1314, 73: 1350, 74: 1387, 75: 1425, 76: 1463, 77: 1501, 78: 1540, 79: 1580, 80: 1620, 81: 1660, 82: 1701, 83: 1743, 84: 1785, 85: 1827, 86: 1870, 87: 1914, 88: 1958, 89: 2002, 90: 2047, 91: 2093, 92: 2139, 93: 2185, 94: 2232, 95: 2280, 96: 2328, 97: 2376, 98: 2425, 99: 2475, 100: 2525})

反恐应用

无人机已扫描所有的建筑,总台给出了每栋建筑可疑人员的概率。但兵力有限最多只能连续搜索两栋,还要跳过两栋以免打草惊蛇。情况紧急,必须在天亮之前赶到下一战区。

后话

深广度优先
回溯方法
间隔两枚的打印

美的集团-数据挖掘工程师面试分享 阅读详情

相关推荐

Mac上快速部署DeepSeek模型:Ollama终端操作全指南

本文详细介绍了在Mac上使用Ollama终端快速部署DeepSeek模型的完整指南。从硬件要求、Ollama安装、模型下载运行,到高级配置、可视化界面及常见问题解决,提供了全流程操作步骤与优化技巧,帮助开发者高效搭建本地AI助手,实现稳定、私密的离线使用体验。

weixin_29251567的博客 551

反恐搜索——打印间隔两枚选择的硬币

1,调式的时候发现前面文章写的coins2Iterative,间隔两枚选硬币的迭代方法是错的,还有没考虑到的情况。2,前面文章写递归调用的coins2直接选择0~99枚硬币也是长时间没有运行结果。3,实际我是从后面一步一步尝试到最前面才成功。这文章应该倒着看。4,一个函数里4次调用自己,而且问题规模没有太大的缩小,复杂度应该是很高的。4,穷举递归应该是第一个尝试的办法。

denghai_csdn的博客 258

汽车OTA安全启动:ECU双验签机制与实战排障指南

汽车OTA升级中的安全启动,本质是基于密码学的信任建立过程,其核心在于ECU上电时对固件镜像的可信验证。该机制依托硬件信任根(Secure Boot ROM),通过RSA/ECDSA等非对称算法完成签名验签,确保升级包未被篡改且来源可信。技术价值体现在防止恶意固件注入、支撑功能安全(ASIL)与信息安全(ISO/SAE 21434)合规。典型应用场景包括4S店远程升级、BMS控制器固件更新及多ECU协同启动。实践中,验签名失败往往源于证书链断裂、Flash布局错位或KeyUsage字段不匹配等底层工程细节,

weixin_29314405的博客 77

泛型编程之乘法

从叠加变成乘法来看,被乘除就是叠加次数,被叠加的次数。乘数就是被叠加的那个数。

denghai_csdn的博客 1472

OpenBCI脑电帽硬件DIY与低成本搭建实战

本文详细介绍了如何通过第三方兼容硬件和开源设计,低成本DIY一套功能完备的OpenBCI脑电采集系统。从硬件选购、组装、软件配置到信号调试,提供了完整的实战指南,将总成本控制在千元级别,使脑机接口技术对爱好者、学生和研究者变得更加触手可及。

weixin_29322855的博客 788

如何在huggingface上申请下载使用llama2/3模型

huggingface-cli download --resume-download 模型名称 --local-dir 存放模型的位置 --local-dir-use-symlinks False --resume-download --token token序列号xxxxxxx。登录huggingface,在模型详情页面上,找到这个表单,填写内容,提交申请。需要使用梯子,country填写梯子的位置吧(比如美国)等待一小时左右,会有邮件通知。

a61022706的博客 1万+

欧几里得算法

用Python模拟STL的代码。这个也是求最大公约数的方法。

denghai_csdn的博客 430

arduino esp8266_Arduino传感器教程 第22章ESP8266 控制 5V 继电器

ESP8266控制5V继电器目录一、NodeMCU二、工作原理本文将使用亚马逊 AlexaEcho 和 ESP8266 控制 5V 继电器。NodeMCUNodeMCU 是一个开源的 IoT 物联网硬件开发板,由于它支持 WIFI 功能且使用方法十分类似 Arduino 开发板,所以近些年获得了越来越多来自全世界的创客朋友们的青睐。NodeMCU 尺寸与 Arduino Nano 类似。...

weixin_39611722的博客 3456

回溯——3、5升杯倒4升水

只有8升水,用3升和5升杯子可以倒出4升吗?

denghai_csdn的博客 477

诊断测试工具CANoe.DiVa从入门到精通系列——开门见山

### 工具主要用于测试ECU的诊断功能。关于自动化诊断测试可以分为如下内容: ### -> 1、根据诊断需求规范进行cdd文件的编辑(现阶段主要是诊断问卷调查表); ### -> 2、新建Diva工程,导入对应的诊断数据库文件生成测试用例; ### -> 3、新建CANoe工程,导入CANoe.DiVa生成的Diva工程; ### -> 4、根据测试报告进行错误处理。

Soly_kun的博客 3555

基于GEC6818开发板+Linux+Qt设计的智能养老院出入管理系统(195)

当前,传统的养老院出入管理模式普遍存在信息更新滞后、数据统计繁琐、实时监控能力不足等问题,难以满足现代养老机构对安全管理与服务质量提升的需求。本系统设计正是针对这些问题,通过集成先进的硬件设备如高性能GEC6818开发板以及RFID刷卡模块,结合稳定高效的嵌入式Linux操作系统和QT开发框架,构建一套功能齐全、操作直观、响应迅速的智能出入管理系统。 该系统能自动记录并实时显示老人的进出时间,方便管理人员及时了解每位老人的活动轨迹,同时具备强大的后台管理功能,支持管理员便捷地进行老人信息的增删改查操作。通

1069

算法题-hot100学习总结

针对于上题,本题采用一维数组(滚动数组);将二维数组压缩至一维,这里一维指的是将上一层dp[i-1]的值拷贝到dp[i]中;故递推公式:dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);3、初始化:对其可全部初始化为非负最小值;4、遍历顺序采用倒序遍历,正序会将前一个的物品价值重复使用,且遵循先遍历for物品再遍历for背包;

m0_69666329的博客 549

Taro React组件使用(5) —— RuiPasswordInput 密码输入框显示隐藏和清空

初始化时,需要将传入的 value 赋值给当前组件的 value, 不能直接修改 props 的 value;在组件内输出组件内的变量时,最好先判断输出函数是否定义,再输出,否则很容易引起报错。

止于至善 891

Python机器学习:从零基础到项目实战

当您翻开此书,您正踏入一场数据与智慧的修行。机器学习,并非冰冷的符码,而是机器模拟人类洞察世界的法门。本书将带您,以Python为舟,泛游于算法之海。我们不只传授“术”,更探求其后的“道”——从数据的生灭流转中观照规律,于模型的迭代演进里体悟得失。愿您合上书卷时,收获的不仅是驾驭数据的技能,更有一双洞悉复杂、化繁为简的“智慧之眼”。现在,让我们一同启程。

YunWisdom 969

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Prepare50

遍历一次,建一个value为dict,key为下标的dict,每次去里面判断下,要找的数是否存在,时间复杂度O(n),空间负责度O(n)。

liuhe2296044的博客 940

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 253

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 322

把 KV Cache 压到 FP4:BitDecoding-FP4 的算法-系统协同设计复盘

长上下文推理卡在KV Cache的显存与带宽上,而现有FP4方案要么精度崩、要么速度废。这篇文章复盘BitDecoding-FP4如何用三个算法补丁加一个系统重构,在B300上把服务吞吐提升2.4–3.0倍,精度几乎不掉。

helloagent的博客 302

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 597

优选算法:分治-归并排序

交易逆序对的总数

Wangshijie1015的博客 137

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 23

408 算法 06|堆与 Top-K:最小的 10 个数,到底该用数组还是堆

2022(42) 找 100 万个数里最小的 10 个,官方给了"10 元素有序数组"和"大根堆"两种答案。我把两种都实现并数了比较次数:k=10 时两者几乎打平,k=10000 时堆少 111 倍。另附 2021(42) 计数排序的比较次数与稳定性实测。

m0_56226131的博客 358

牛客周赛165C题(前后缀性质,递推,排序,枚举)

题目大意:给定长度为 `n` 的数组,选择 `k ∈ [1,n]`,将前 `k` 个元素整体翻转,后面的元素不变。要求操作后的整个数组非递减,统计满足条件的 `k` 的数量。题目链接:https://ac.nowcoder.com/acm/contest/141721/C。时间复杂度:O(nlogn)

2501_94316951的博客 172

408 算法 04|主元素与三元组最小距离:两种“扫描时做决定“的思路

2013(41) 的主元素用摩尔投票一遍选出候选,但真正的考点是"选完必须验票";2020(41) 的三元组最小距离,三指针每次只挪最小的那个,靠的是 D=2×(max−min) 这个恒等式。两套完整 C 代码加真实输出,附官方评分档位表。

m0_56226131的博客 415

【数据结构-3】算法美学之降复杂度

在while循环的循环体内,首先用临时变量保存最后一个位置的数据,再通过for循环把所有元素往后移动一位,最后把tmp中保存的值放到下标为0的位置上去。方法二的思路是:创建新数组,让原数组中后k个数据移动到新数组中前面的位置,让原数组中前numsSize-k个数据移动到新数组中后面的位置,这。这段代码的思路是:三次逆置,第一次逆置前numsSize-k个数据,第二次逆置后k个数据,最后整体逆置。这篇博文分享一道解法不一的算法题,求解过程的目的在于降低算法的时间复杂度,题源力扣。,属于空间换时间的操作。

a bit 89

算法61,判定是否为字符重排

两字符串能互为重排 ⇔。

sheshibenniaodan的博客 220
上一篇: 递归调用——单向汉诺塔
下一篇: 2-3-4树的层序打印
denghai邓海
博客等级 码龄6年 629粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值