大家好,我是牛牛,终于又到了最爱的周五啦,大家是不是已经无心工作,就等着愉快的周末到来?

不瞒你说,牛牛也是这样!今天就给大家分享一道有趣的算法题,希望能给大家带来一个好心情~

01

故事起源

故事,要从住在森林里的大熊发现了一个装满苹果的山洞说起...

牛牛码特

13:14

85%

微信(116)

相亲相爱一家熊????

我发现一个山洞,里面有好多苹果????,看起来很好吃的样子~

不过我们只能从洞口和洞尾拿苹果,我们来比比看谁拿的苹果重量最大吧~

好啊好啊

那我们赶快去山洞吧!

熊熊们山洞之旅遇到的问题,归纳起来就是:给定一个装满苹果的山洞,只能从洞口和洞尾拿苹果,每轮两只熊交替拿,并且只能拿一个,谁拿的苹果总重量最大谁就获胜,那谁会是最终的赢家呢?

02

问题剖析

假定山洞里苹果的分布为:1KG,3KG,14KG,7KG。

直觉上来说,是不是我们每轮拿最大的,就一定赢?如果是这种策略,那么大熊第一轮拿7KG,此时的状况就变成了:

这时候很显然,二熊会拿最右边14KG的苹果:

现在山洞里只剩下1KG和3KG两个苹果,无论大熊拿哪一个,它手上苹果总重量,也没二熊的重。难道这是大熊的必输局?

那么,让我们换种拿法,重来一遍。

如果第一轮,大熊选择拿第一个苹果,那此时状态就变成了:

这个时候,二熊只能从3KG、7KG里面选,无论拿哪个,大熊第三轮拿到14KG都能获胜。因此,只要开局拿1KG,大熊就是必胜的。

所以说,每轮选最大这种策略行不通,我们还需要考虑到对后面苹果的影响。

相信经过这个分析,大家已经对题目比较清楚,甚至有点解题思路了吧?别着急,现在我们就一起来看看有哪些解决办法吧。

03

花式取苹果

深度优先递归法

我们可以把问题抽象出来,大熊第一轮去取苹果,是否能赢取决于两个因素:一个是取的苹果的重量,另一个是二熊对剩下的进行选择。再仔细一想,二熊面临的问题,其实和大熊开始时是一模一样的。这样思路就很明显了,我们可以用递归的方法去解决问题。

下面这张图,可以帮助我们辅助思考。

我们从最右边往左边看,每一轮都选择当前的最优解,整个流程走下来,就是递归的实际执行流程了。

经过上述分析,代码也很清晰明了:

func CanFistBearWin(nums []int) bool {    return picker(0, len(nums)-1, nums) >= 0}
// i, j 表示当前子问题中,山洞左右从哪里开始func picker(i, j int, nums []int) int {    if i == j {        return nums[i]    }    head := nums[i] - picker(i+1, j, nums)    end := nums[j] - picker(i, j-1, nums)    return max(head, end)}

记忆化递归法

问题虽然解决了,但是跑了一下测试用例,发现用时100ms以上。这样看来,性能上是不是还有优化空间呢?

可以看到,图上是有重复子问题的,那我们完全可以将子问题的解答记录下来。等到后面再遇到的时候,直接返回结果,而不用再递归下去,这样就可以节约大量时间了。

动态规划法

在上面的分析中,我们已经把问题拆分为子问题,既然是子问题,又可以递归解决,那么就不由地会去想,能不能通过动态规划,递推解决?

依照惯例,我们需要一个dp数组,在上面的分析中不难看出,这个数组应该是二维的,dp[i][j]就表示左边起点为i,右边起点为j的山洞,在先手的情况下,熊熊能拿多少KG的苹果。

既然要用动态规划,那么一定要找到一个公式。我们前面分析过,如果大熊先手,是否能赢取决于两个因素:一个是取的苹果的重量,另一个是二熊对剩下的进行选择。

根据这两个因素,我们可以转化为下列公式:

dp[i][j] = Max(nums[i]-dp[i+1][j], nums[j]-dp[i]dp[j-1])

再结合下面的图来进行推导。我们还是以四个苹果为例,为苹果从左到右编上号。

0号位置对应的dp[0][0]就是其苹果的重量,我们从1号位置开始,对每个位置往前递推:

????红苹果配合代码食用更佳:

func CanFistBearWin(nums []int) bool {    // 提前计算数组长度,避免反复消耗    length := len(nums)    dp := make([][]int, length)    // 子数组初始化    for i := 0; i < length; i++ {        dp[i] = make([]int, length)        // 左右在一个点的情况,取了这个苹果即可        dp[i][i] = nums[i]    }    // j表示山洞右侧位置    for j := 1; j < length; j++ {        // i表示山洞左侧位置        for i := j-1;  i >= 0; i-- {            head := nums[i] - dp[i+1][j]            end := nums[j] - dp[i][j-1]            dp[i][j] = max(head, end)        }    }    return dp[0][length-1] >= 0}果不其然,成功拿到了苹果,熊熊开心地跳起了舞

04

熊熊复盘

解决此类问题的核心思想,是将从洞两端选择苹果这个问题抽离出来,成为子问题。然后,在此基础上,我们建立了递归解法,根据实际运行的结果,使用记忆化搜索优化,提高了性能。

解决了问题就算完成任务了?我们的目标可是成为一名追求极致的工程师,当然会想还有没有其它解决方案。于是,我们将同一种抽象模型,从递归转换成递推,玩了把动态规划。

换个角度看问题,生命会展现出另一种美。生活中不是缺少美,而是缺少发现。算法也一样,同一个问题,学着用多个角度去思考、解决,你会发现它别样的魅力!

【腾讯面试题】熊出没相关推荐

  1. android获取指针空间大小_腾讯笔试题:浅谈计算机中cpu位数和指针

    来一个腾讯笔试题 在刷题的时候看到了腾讯笔试题的这个问题 long a = (long)(((int *) 0) + 4);printf("%ld ",a); 请问输出 a 的值是 ...

  2. 腾讯面试题:char 和 varchar的最大长度是多少,以及他们之间的区别(看完你就能和面试官笑谈人生了)

    title: 腾讯面试题:char 和 varchar的最大长度是多少,以及他们之间的区别(看完你就能和面试官笑谈人生了) tags: 面试常见题 腾讯面试题:char 和 varchar的最大长度是 ...

  3. 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了)

    title: 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了) tags: 面试常见题 腾讯面试题:创建索引时,你会怎么考虑呢?(看完你就能和面试官谈人生了) 腾讯面试题:创建索 ...

  4. 腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

    1.腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中? 思想:用数组来存这40亿个数,而且只能用bit来表示.why? ...

  5. 【转】IT名企面试:腾讯笔试题(2)

    摘要:想要进入腾讯公司,面试笔试题是一定要有所准备的.那么这里我们总结了一些腾讯笔试题,例如:const的含义及实现机制等问题. 腾讯是国内数一数二的IT企业了.那么每年想要进入腾讯公司的应聘者也是络 ...

  6. 线性表11|单链表小结:腾讯面试题 - 数据结构和算法16

    线性表11|单链表小结:腾讯面试题 让编程改变世界 Change the world by program 静态链表的删除操作 我们的故事还没结束,小C看到小A和2B这样非法的勾当,内心觉得很不爽,一 ...

  7. 程序员求助:腾讯面试题,64匹马8个跑道,多少轮选出最快的四匹

    昨天,有网友私信我,说去阿里面试,彻底的被打击到了.问了为什么网上大量使用ThreadLocal的源码都会加上private static?他被难住了,因为他从来都没有考虑过这个问题.无独有偶,今天笔 ...

  8. java 2017腾讯面试题_腾讯2017刁难面试题,是不是大神就看你会做几题

    原标题:腾讯2017刁难面试题,是不是大神就看你会做几题 一.今日头条2017笔试题(决策问题) 现在有两堆石子,小今与小条玩游戏,2个人都足够聪明,两个人规定:每次每人只能从其中一堆中取走1个或2个 ...

  9. python编辑距离正则匹配_详解一道腾讯面试题:编辑距离

    原标题:详解一道腾讯面试题:编辑距离 来自公众号:labuladong 预计阅读时间:8 分钟 前几天在网上看到一份鹅场的面试题,算法部分大半是动态规划,最后一题就是写一个计算编辑距离的函数,今天就专 ...

  10. 腾讯面试题 你了解ReentrantLock吗?

    腾讯面试题 你了解ReentrantLock吗? ReetrantLock是一个可重入的独占锁,主要有两个特性,一个是支持公平锁和非公平锁,一个是可重入. ReetrantLock实现依赖于AQS(A ...

最新文章

  1. 基于cnn的短文本分类_自然语言理解之(二)短文本多分类TextCNN实践
  2. BZOJ-2748: [HAOI2012]音量调节 (傻逼背包DP)
  3. HCP Anywhere:为HDS内容云锦上添花
  4. php 多组radiobutton,Tkinter多个Radiobutton组
  5. golang的一个简单小爬虫demo学习记录
  6. java多重继承用在什么地方_Java提高篇——Java实现多重继承
  7. Linux内核深入理解定时器和时间管理(7):相关的系统调用
  8. NCBI安装影响因子插件
  9. C++ gbk与utf8互转
  10. 程序员如何改善精神内耗?
  11. extjs 中formPanel提交到action后返回json数据到ext中,但是ext页面不进入sucess也不进入failure
  12. 无盘服务器0x00000124,知识分享电脑故障0x00000124导致蓝屏的原因和解决思路-电脑蓝屏原因...
  13. 站点能源低碳目标网,助力网络碳中和 | 华为发布站点能源十大趋势
  14. 【原创】VBA学习笔记(300)VBA 很多工作表函数都只对1维数组有用,用2维数组上经常报错!
  15. b站网页版倍速无效_看网课讲师太啰嗦太慢?在线视频课程效率低?教你自定义超倍速看
  16. [乐意黎原创]PHP抛PHP Startup:Unable to load dynamic library bcmath,Libmcrypt,mhash,mcrypt等警告及模块动态安装详解
  17. CyberWorld赛博世界是否能成为元宇宙核心力量
  18. VSCode下载很慢解决方法
  19. 关于“IT学子成长指导”专栏及文章目录
  20. 用C语言构建一个素数表

热门文章

  1. mac微软雅黑字体_【字体字重】常见设计稿字体对应字重
  2. oracle有一百个人围一圈报数,案例:Oracle创建表时报session超过最大值 ORA-00018 证明递归ses...
  3. 定期存款单的mysql编写程序_MySQL 调优和使用必读
  4. 【Java】“异常”详解
  5. 第1关:学习-用循环和数组实现输入某年某月某日,判断这一天一年的第几天
  6. 布局类型java_java – 我们可以为所有屏幕大小制作一种布局类型
  7. centos 7 php mysql apache_CentOS 7 搭建 Apache+MySQL+PHP
  8. spring boot+oracle数据库配置成功
  9. 求方程ax2+bx+c的根python_Python,计算 ax^2 + bx + c = 0的根
  10. android的天气和时钟部件,Android的天气和时钟部件