阿里测试算法题,Burst Balloons 问题的变形

本文详细解析了一个名为“爆破气球”的算法问题,通过递归的方式计算爆破一系列带有数值的气球可以获得的最大分数。文章以具体的代码示例说明了如何实现这一算法,并解释了其中的关键步骤。
public static void main(String[] args) {
         List<Integer>list=Arrays.asList(4,4,3,1);
         // 循环的次数 C(N+2),3
         System.out.println(count(list));
        
     }
     
     public static int count(List<Integer> list){
         int n = list.size();
         List<Integer>tmplist=new ArrayList<Integer>();
         int sum=0;
         for(int i=0;i<n;i++){
             // 以0为分界线,分成不同的子集,再求这些子集合的和,再全部加起来
             if(list.get(i)!=0)
                 tmplist.add(list.get(i));
             else{
                 int []a=new int[tmplist.size()];
                 for(int j=0;j<tmplist.size();j++){
                     a[j]=tmplist.get(j);
                 }
                 sum+=maxCoins(a);
                 tmplist.clear();
             }
             // 求最后那个子集合的和
             if(i==n-1){
                 int []a=new int[tmplist.size()];
                 for(int j=0;j<tmplist.size();j++){
                     a[j]=tmplist.get(j);
                 }
                 sum+=maxCoins(a);
                 tmplist.clear();
             }
         }
        // System.out.println(sum);
         return sum;
     }
     
     public static int maxCoins(int[] iNums) {
         int[] nums = new int[iNums.length + 2];
         int n = 1;
         // 在集合的头尾加上两个编号为1的气球
         for (int x : iNums) if (x > 0) nums[n++] = x;
         nums[0] = nums[n++] = 1;
         int[][] memo = new int[n][n];
         return burst(memo, nums, 0, n - 1);
     }
     
     static int count = 0;
 
      /**
          * 以 4,4,3,1为例子 
        * 定义:burst(left,right),是计算left~right之间最的大得分,计算的方法是循环 i=1~4 , 递归求right=burst(left,i)
        * left=burst(i,right) 以及temp = nums[left]*nums[i]*nums[right] ,在与上次循环的结果ans比较,
        * 取max(ans,left+temp+right) , 注意这是开区间! (3,5)的最大得分用闭区间表示就是[4]这一个气球的得分!
        * 
        * @param memo :二维数组,存储某范围内的最大得分 例如 (3,5)的值 表示 3~5最大的得分,在递归中都是(left,right)进行计算的
        * @param nums
        * @param left :当前递归时候的最left值
        * @param right:当前递归时候的最right值
        * @return
        *
        * 
        * (1)在第一层递归第一次计算burstLeft的时候,由于 i=left+1,所以burstLeft根本就不存在,可见方法定义,比如3~4的(3,4)不存在任何气球
        * 所以会进入burstRight的递归,接下来每层递归的第一层循环都是这样,即,i=left+1,burstLeft不存在,就会一直往深处递归到right-2
        * 到此时,经过的流程为
        * 1 left:0 i:1 right:5  TEMP:4
          2 left:1 i:2 right:5  TEMP:16
          3 left:2 i:3 right:5  TEMP:12
          4 left:3 i:4 right:5  TEMP:3
        * (2)此时,burstLeft=(left,i):(3,4) ; burstRight=(i,right):(4,5)都不存在
        * ans=nums[3]*nums[4]*nums[5]。把值存入memo[3][5](只有一个气球4,所以肯定是最大值),返回到left等于2的递归。
        * 
        * (3)返回的地点是burstRight=(i,right),其中i=3,right=5; 运行到此刻表示的含义是,当left=2,i=3,right=5
        * TEMP=nums[2]*nums[3]*nums[5] =12 burstLeft=(2,3)=0  burstRight=(3,5)=3 ,算到了一种burst(2,5)
        * 的可能 nums[2]*nums[3]*nums[5]+burstLeft+burstRight=15。
        * 
        * (4)然再 i+1 = 4 < right:5 继续循环,算出TEMP=nums[2]*nums[4]*nums[5] = 4 , 
        * burstLeft=burst(2,4)=12 burstRight=(4,5)=0 所以算的burst(2,5)另外一种可能:
        * nums[2]*nums[4]*nums[5]+burstLeft+burstRight=16。
        * 
        * (5)然后根据max(ans,...)--->15<16, 拿算得burst(2,5)=16。
        * 
        * 
        * 综上所述每次求temp=nums[left]*nums[i]*nums[right]的时候,其实相当于求burst(left,right)中最中最后一步的
        * 计算。比如上例子求先算burst(2,5)中的 nums[2]*nums[4]*nums[5],再算burst(2,4)和burst(4,5),但实际情况是
        * 先完成burst(2,4)(此时的burst(4,5)不存在,没什么用)才可以进行 nums[2]*nums[4]*nums[5]的计算。
        * 由此可以总结出。该算法的循环的i是确定最后射击的那个气球,然后再不断递归求得 (left,i) 和 (i,right)
        * 
        */
     public static int burst(int[][] memo, int[] nums, int left, int right) {
         if (left + 1 == right) return 0;
         if (memo[left][right] > 0) {
            // System.out.println("left: "+left+" right:"+right+" memo[left][right]:"+memo[left][right]);
             return memo[left][right];
         }
         int ans = 0;
         for (int i = left + 1; i < right; ++i){
             int temp = nums[left] * nums[i] * nums[right] ;
            System.out.println(++count+" left:"+left + " i:" + i + " right:"+right +"  TEMP:"+temp);
             int burstLeft =  burst(memo, nums, left, i);
             int burstRight = burst(memo, nums, i, right);
             ans = Math.max(ans , burstLeft+temp+burstRight);
            
         }
         memo[left][right] = ans;
          System.out.println("left: "+left+" right:"+right+" memo[left][right]:"+memo[left][right]);
         return ans;
     }

 

以4,4,3,1为例子
 定义:burst(left,right),是计算left~right之间最的大得分,计算的方法是循环 i=1~4 , 递归求right=burst(left,i)
      * left=burst(i,right) 以及temp = nums[left]*nums[i]*nums[right] ,在与上次循环的结果ans比较,
      * 取max(ans,left+temp+right) , 注意这是开区间! (3,5)的最大得分用闭区间表示就是[4]这一个气球的得分!
      * 
      * @param memo :二维数组,存储某范围内的最大得分 例如 (3,5)的值 表示 3~5最大的得分,在递归中都是(left,right)进行计算的
      * @param nums
      * @param left :当前递归时候的最left值
      * @param right:当前递归时候的最right值
      * @return
      * 以4,4,3,1为例子
      * 
      * (1)在第一层递归第一次计算burstLeft的时候,由于 i=left+1,所以burstLeft根本就不存在,可见方法定义,比如3~4的(3,4)不存在任何气球
      * 所以会进入burstRight的递归,接下来每层递归的第一层循环都是这样,即,i=left+1,burstLeft不存在,就会一直往深处递归到right-2
      * 到此时,经过的流程为
      * 1 left:0 i:1 right:5  TEMP:4
        2 left:1 i:2 right:5  TEMP:16
        3 left:2 i:3 right:5  TEMP:12
        4 left:3 i:4 right:5  TEMP:3
      * (2)此时,burstLeft=(left,i):(3,4) ; burstRight=(i,right):(4,5)都不存在,
      * ans=nums[3]*nums[4]*nums[5]。把值存入memo[3][5](只有一个气球4,所以肯定是最大值),返回到left等于2的递归。
      * 
      * (3)返回的地点是burstRight=(i,right),其中i=3,right=5; 运行到此刻表示的含义是,当left=2,i=3,right=5
      * TEMP=nums[2]*nums[3]*nums[5] =12 burstLeft=(2,3)=0  burstRight=(3,5)=3 ,算到了一种burst(2,5)
      * 的可能 nums[2]*nums[3]*nums[5]+burstLeft+burstRight=15。
      * 
      * (4)然再 i+1 = 4 < right:5 继续循环,算出TEMP=nums[2]*nums[4]*nums[5] = 4 , 
      * burstLeft=burst(2,4)=12 burstRight=(4,5)=0 所以算的burst(2,5)另外一种可能:
      * nums[2]*nums[4]*nums[5]+burstLeft+burstRight=16。
      * 
      * (5)然后根据max(ans,...)--->15<16, 拿算得burst(2,5)=16。
      * 
      * 
      * 综上所述每次求temp=nums[left]*nums[i]*nums[right]的时候,其实相当于先求burst(left,right)中最中最后一步的
      * 计算。比如上例子求先算burst(2,5)中的 nums[2]*nums[4]*nums[5],再算burst(2,4)和burst(4,5),但实际情况是
      * 先完成burst(2,4)(此时的burst(4,5)不存在,没什么用)才可以进行 nums[2]*nums[4]*nums[5]的计算。
      * 由此可以总结出。该算法的流程是,循环i确定最后射击的那个气球,然后再不断递归求得 (left,i) 和 (i,right)

转载于:https://www.cnblogs.com/liujiaa/p/7985895.html

该数据集通过合成方式模拟了多种发动机在运行过程中的传感器监测数据,旨在构建一个用于机械系统故障检测的基准资源,特别适用于汽车领域的诊断分析。数据按固定时间间隔采集,涵盖了发动机性能指标、异常状态以及工作模式等多维度信息。 时间戳:数据类型为日期时间,记录了每个数据点的采集时刻。序列起始于2024年1224日10:00,并以5分钟为间隔持续生成,体现了对发动机运行状态的连续监测。 温度(摄氏度):以浮点数形式记录发动机的温度读数。其数值范围通常处于60至120摄氏度之间,反映了发动机在常规工况下的典型温度区间。 转速(转/分钟):以浮点数表示发动机曲轴的旋转速度。该参数在1000至4000转/分钟的范围内随机生成,符合多数发动机在正常运转时的转速特征。 燃油效率(公里/升):浮点型变量,用于衡量发动机的燃料利用效能,即每升燃料所能支持的行驶里程。其取值范围设定在15至30公里/升之间。 振动_X、振动_Y、振动_Z:这三个浮点数列分别记录了发动机在三维空间坐标系中各轴向的振动强度。测量值标准化至0到1的标度,较高的数值通常暗示存在异常振动,可能与潜在的机械故障相关。 扭矩(牛·米):以浮点数表征发动机输出的旋转力矩,数值区间为50至200牛·米,体现了发动机的负载能力。 功率输出(千瓦):浮点型变量,描述发动机单位时间内做功的速率,取值范围为20至100千瓦。 故障状态:整型分类变量,用于标识发动机的异常程度,共分为四个等级:0代表正常状态,1表示轻微故障,2对应中等故障,3指示严重故障。该列作为分类任务的目标变量,支持基于传感器数据预测故障等级。 运行模式:字符串类型变量,描述发动机当前的工作状态,主要包括:怠速(发动机运转但无负载)、巡航(发动机在常规负载下平稳运行)、重载(发动机承受高负荷或高压工况)。 数据集整体包含1000条记录,每条记录对应特定时刻的发动机性能快照。其中故障状态涵盖从正常到严重故障的四级分类,有助于训练模型实现故障预测与诊断。所有数据均为合成生成,旨在模拟真实的发动机性能变化与典型故障场景,所包含的温度、转速、燃油效率、振动、扭矩及功率输出等关键传感指标,均为影响发动机故障判定的重要因素。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值