1444 切披萨的方案数【leetcode每日一题系列】

文章介绍了使用回溯和记忆化搜索算法解决披萨切分问题,通过递归和状态转移判断是否可行,避免重复计算,优化了求解效率。
摘要由CSDN通过智能技术生成

在这里插入图片描述

例子:
在这里插入图片描述

回溯和记忆化搜索

使用暴力回溯的思想来解题,首先是明确如何切西瓜:

每次切完西瓜后,都会剩下一个矩形,与原有型状类似,因此可以采用回溯递归的方式来判断。

采用对角顶点来定义每次处理的不同矩形,矩形的左上角会随着不断的切割发生变化,而右下角会保持不变,因此,只需要传递给方法体左上角的坐标值,就可以知道矩形的形状。

以例1为例:

当选择横向切时,会将上层的披萨送人,因此从 0 0 0 开始时,有两种横着切的方式,分别是:
1.切0-1之间的披萨
2.切1-2之间的披萨

当切完0-1之间的披萨时,披萨分为两块,分别是:

左上角坐标为[0,0],右下角坐标为[1,2]的上层披萨
左上角坐标为[1,0],右下角坐标为[2,2]的下层披萨

这时需要判断两块披萨中是否有苹果,通过遍历可以得到,遍历代码如下:

    public boolean istrue(int i,int j,int k,int l,String[] pizza){
        for(int indexx = i;indexx<k;indexx++){
            for(int indexy = j;indexy<l;indexy++){
                if(pizza[indexx].charAt(indexy)=='A'){
                    return true;
                }
            }
        }
        return false;
    }

当两块披萨中都含有苹果时,才会进行下一步操作,下一步切的矩形左上角坐标根据切的不同方式来定:

若切到0-1之间的坐标,则下一步切的矩形左上角为[1,0]
若切到1-2之间的坐标,则下一步切的矩形左上角为[2,0]

竖着切的方式和横着切类似,下一步就是判断终止条件:

k k k 0 0 0 时,需要切割的次数已经用完,只需要判断剩下的矩形中是否有苹果,若有,则表示这种切披萨的方式可行,返回1;若无,则表示不可行,返回0。

采用上述方式来递归的求值时会出现超时问题,在递归过程中出现较多的重复计算,因此需要进行去重操作。
从题中可以看出,横着切一刀竖着切一刀竖着切一刀横着切一刀所产生的矩形是一样的,因此不需要重复计算,可以使用一个数组 n u m s [ k ] [ i ] [ j ] nums[k][i][j] nums[k][i][j] 来保存前一次产生的结果,从而减少时间复杂度。
详细代码如下:

class Solution {
    public static final int MOD = (int) 1e9 + 7;
    public int ways(String[] pizza, int k) {
        int[][][] nums = new int[k][pizza.length][pizza[0].length()];
        return dfs(k-1,0,0,pizza,nums)%MOD;

    }
    public int dfs(int k, int i, int j,String[] pizza,int[][][] nums){
        if(k==0){
            if(istrue(i,j,pizza.length,pizza[0].length(),pizza)) return 1;
            else return 0;
        }
        if(nums[k][i][j]!=0) return nums[k][i][j];
        int result = 0;
        for(int m=i+1;m<pizza.length;m++){
            if(istrue(i,j,m,pizza[0].length(),pizza)){
                result = (result+dfs(k-1,m,j,pizza,nums))%MOD;
            }
        }
        for(int m=j+1;m<pizza[0].length();m++){
            if(istrue(i,j,pizza.length,m,pizza)){
                result = (result+dfs(k-1,i,m,pizza,nums))%MOD;
            }
        }
        nums[k][i][j] = result;
        return result;
    }
    public boolean istrue(int i,int j,int k,int l,String[] pizza){
        for(int indexx = i;indexx<k;indexx++){
            for(int indexy = j;indexy<l;indexy++){
                if(pizza[indexx].charAt(indexy)=='A'){
                    return true;
                }
            }
        }
        return false;
    }
}

最后结果别忘了 m o d ( 1 e − 9 + 7 ) mod(1e-9+7) mod(1e9+7)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值