• LeetCode刷题(6)


    分治问题

    分治问题由“分”(divide)和“治”(conquer)两部分组成,通过把原问题分为子问题,再将子问题进行处理合并,从而实现对原问题的求解。
    另外,自上而下的分治可以和memoization 结合,避免重复遍历相同的子问题。如果方便推导,也可以换用自下而上的动态规划方法求解。

    241. DifferentWays to Add Parentheses (Medium)

    问题说明
    给你一个由数字和运算符组成的字符串 expression ,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以按任意顺序 返回答案。

    输入输出样例
    示例 1:

    输入:expression = “2-1-1”
    输出:[0,2]
    解释:
    ((2-1)-1) = 0
    (2-(1-1)) = 2

    示例 2:

    输入:expression = “23-45”
    输出:[-34,-14,-10,-10,10]
    解释:
    (2*(3-(45))) = -34
    ((2
    3)-(45)) = -14
    ((2
    (3-4))5) = -10
    (2
    ((3-4)5)) = -10
    (((2
    3)-4)*5) = 10

    思路
    对于一个表达式,可以将其按照符号分成两个部分。对两个部分分别求解值,之后再将两部分求解的值进行加减乘的操作。注意边界条件:如果一个表达式中没有符号,则直接将其加到结果中。

    代码

    class Solution {
        public List<Integer> diffWaysToCompute(String expression) {
            LinkedList<Integer> result = new LinkedList<>();
            for(int i=0;i<expression.length();i++){
                char c = expression.charAt(i);
                if(c=='+'||c=='-'||c=='*'){
                    List<Integer> left_result = diffWaysToCompute(expression.substring(0,i)); //[0,i)
                    List<Integer> right_result = diffWaysToCompute(expression.substring(i+1));//[i+1,length)
                    for(int left:left_result){
                        for(int right:right_result){
                            if(c == '+')result.add(left+right);
                            if(c == '*')result.add(left*right);
                            if(c == '-')result.add(left-right);
                        }
                    }
                }
                
            }
            //如果expression中只有数字
            if(result.isEmpty())result.add(Integer.valueOf(expression));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    932. Beautiful Array (Medium)

    问题描述
    对于某些固定的 N,如果数组 A 是整数 1, 2, …, N 组成的排列,使得:
    对于每个 i < j,都不存在 k 满足 i < k < j 使得 A[k] * 2 = A[i] + A[j]。
    那么数组 A 是漂亮数组。
    给定 N,返回任意漂亮数组 A(保证存在一个)。

    输入输出样例
    示例 1:

    输入:4
    输出:[2,1,4,3]

    示例 2:

    输入:5
    输出:[3,1,2,5,4]

    思路
    根据题意只要不满足A[k] * 2 = A[i] + A[j]即为漂亮数组,也就是说对于【1-n】可能存在很多种。这里我们只要找到每个n的其中一种即可。要不满足上述等式,只需要A[i]和A[j]一个为偶数一个为奇数即可。

    对于n个数,从1开始,奇数有(n+1)/2个,偶数有n/2个
    (n+1)/2个数组成的漂亮数组为left
    n/2个数组成的漂亮数组为right
    left*2-1依旧是漂亮数组(包括1 3 5 7…)奇漂亮数组
    right*2也依旧是漂亮数组(包括2 4 6 8…)偶漂亮数组
    left*2-1right*2左右拼在一起(奇漂亮数组与偶漂亮数组合并是漂亮数组),正好包含了n个数,且是漂亮数组。

    代码

    class Solution {
        public int[] beautifulArray(int n) {
            if(n==1) return new int[]{1};
            int[] left = beautifulArray((n+1)/2);
            int[] right = beautifulArray(n/2);
            int[] result = new int[n];
            int k = 0;
            for(int c:left){
                result[k++]=c*2-1;
            }
            for(int c:right){
                result[k++]=c*2;
            }
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    312. Burst Balloons (Hard)

    问题描述
    有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。

    现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。

    求所能获得硬币的最大数量。

    输入输出样例

    示例 1:

    输入:nums = [3,1,5,8]
    输出:167
    解释:
    nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
    coins = 315 + 358 + 138 + 181 = 167

    示例 2:

    输入:nums = [1,5]
    输出:10

    思路
    借鉴LeetCode@狗大王
    这个区间的气球长这样:
    在这里插入图片描述
    假设这个区间是个开区间,最左边索引 i,最右边索引 j,这里说 “开区间” 的意思是只能戳爆 i 和 j 之间的气球。
    DP思路是这样的,就先别管前面是怎么戳的,只要管这个区间最后一个被戳破的是哪个气球,这最后一个被戳爆的气球就是 k。假设最后一个被戳爆的气球是粉色的,k 就是粉色气球的索引:
    在这里插入图片描述
    由于是最后一个被戳破,开区间首尾只剩 i 和 j 了。所以DP的状态转移方程是只和 i 和 j 位置的数字有关。
    假设 dp[i][j] 表示开区间 (i,j) 内你能拿到的最多金币,在 (i,j) 开区间得到的金币可以由dp[i][k]dp[k][j]进行转移,此时戳破k得到的金币数量为:
    dp[i][k]+val[i] * val[k] * val[j]+dp[k][j]
    (i,j) 开区间可以选的 k 是有多个的,从可选的k中选择最大的值来更新dp[i][j]

    代码

    class Solution {
        public int maxCoins(int[] nums) {
            int n = nums.length;
            // 创建一个辅助数组,并在首尾各添加1,方便处理边界情况
            int[] temp = new int[n+2];
            temp[0] = 1;
            temp[n+1] = 1;
            for(int i=0; i<n; i++){
                temp[i+1] = nums[i];
            }
            int m = n+2; //表示扩充后数组长度
            int[][] dp = new int[m][m];
            // len表示开区间长度
            for(int len=2; len<m; len++){ //遍历每一个区间长度
                // i表示开区间左端点
                for(int i=0; i<m-len; i++){ //区间向右滑动
                    range_best(i,i+len,temp,dp); //在当前区间中找到获得最多金币
                }
            }
            return dp[0][m-1];
        }
    
    	//在(i,j)开区间中获得的最多的金币
        private void range_best(int i,int j,int[]nums,int[][]dp){
            int max = 0;
            for(int k=i+1;k<j;k++){ //k是区间(i,j)开区间内
                int left = dp[i][k];
                int right = dp[k][j];
                max = Math.max(max,left+right+nums[i]*nums[k]*nums[j]);
            }
            dp[i][j]= max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    【微服务】Spring Cloud中如何使用Eureka
    Spring反序列化JNDI分析
    Python编程实例-Matplotlib实时数据可视化
    判断是不是二叉搜索树
    python基础语法(五)
    mysql查询最近7天 每天销售额 统计销售额
    java毕业设计宠物收养管理系统Mybatis+系统+数据库+调试部署
    动态内存管理
    2022全国水下机器人大赛国际线上赛来啦!“水下感知赛、通信赛”等你来战!
    python类对象
  • 原文地址:https://blog.csdn.net/ha_lee/article/details/126003391