【LeetCode】Sama的个人记录_29

 

 

【Q410】(hd) 分割数组的最大值
 
给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。
 
注意: 数组长度 n 满足以下条件: 1 ≤ n ≤ 1000 1 ≤ m ≤ min(50, n)
 
示例:
   输入: nums = [7,2,5,10,8] m = 2
   输出: 18

class Solution {
     
    /**
     *【动态规划】
     *
     * dp[i][j]的含义是:将数组的前 ii 个数分割为 jj 段所能得到的最大连续子数组和的最小值
     * 动态转移方程根据dp[i][j]的含义也不难写出:dp[i][j] = Math.max(dp[k][j - 1], sub[i] - sub[k])  (k可变,尝试更新dp[i][j]的最小值)
     * (使用了前缀和优化)
     *
     * 难点在于边界的处理。用if【判断进行暴力处理也可以,但是"dp[0][0] = 0 else Integer.MAX_VALUE"初始化后,边界问题被巧妙解决。
     */
    public int splitArray(int[] nums, int m) {
     
        int len = nums.length;

        // 前缀和数组
        int[] sub = new int[len + 1];
        for(int i = 1; i < len + 1; i++){
     
            sub[i] = sub[i - 1] + nums[i - 1];
        }

        // 初始化dp
        int[][] dp = new int[len + 1][m + 1];
        for(int i = 0; i < len + 1; i++){
     
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        }
        dp[0][0] = 0;

        // 动态规划
        for(int i = 1; i < len + 1; i++){
     
            for(int j = 1; j < Math.min(m + 1, i + 1); j++){
             // 因为dp表的形状比较特殊,所以要这样写
                for(int k = 0; k < i; k++){
     
                    dp[i][j] = Math.min(dp[i][j], Math.max(dp[k][j - 1], sub[i] - sub[k]));
                }
            }
        }

        return dp[len][m];
    }
}
class Solution {
     
	/*
	* 【二分模板题】
	* 
	* 标准的模板题,将问题分割为两个独立的问题———— 值二分 + 判断某个值是否符合
	* 
	* 值二分部分不必所说,可以说是模板了:res写在check为true的下面,保证res一直符合。再次基础上,值不断二分,逼近left==right
	* 			(还有一个老生常谈的小逻辑:因为mid是向下取整,每次不符合时。left = mid+1保证不出现死循环)
	* 
	* check部分使用的是【贪心】,假设最大值已知,如果分割的份数 <= 预期,则该值符合
	*/
    public int splitArray(int[] nums, int m) {
     
        int left = 0;
        int right = 0;
        for(int n : nums){
     
            right += n;
            left = Math.max(left, n);
        }

        int res = right;
        while(left < right){
     
            int mid = (right - left) / 2 + left;
            if(check(nums, m, mid)){
     
                res = mid;
                right = mid;
            }else{
     
                left = mid + 1;
            }
        }

        return res;
    }

    private boolean check(int[] nums, int m, int max){
     
        int count = 1;
        int sum = 0;
        for(int i = 0; i < nums.length; i++){
     
            if(sum + nums[i] > max){
     
                count++;
                sum = nums[i];
            }else{
     
                sum += nums[i];
            }
        }
        return count <= m;
    }
}

 

 

【Q343】(md) 整数拆分
 
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
 
示例 1:
   输入: 2
   输出: 1
   解释: 2 = 1 + 1, 1 × 1 = 1。
 
示例 2:
   输入: 10
   输出: 36
   解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
 
说明: 你可以假设 n 不小于 2且不大于 58。

class Solution {
     
    /**
     *【贪心】
     * 因为 2 + 3 < 2 * 3,因此贪心取3就好了
     * 但是 1 + 3 > 1 * 3,因此贪心到最后余1是不行的———余4时就直接取4,不再贪心出3
     *
     * 例如:8 ———— 贪心3, 3 + 3 + 2,res = 3*3*2 = 18
     *      10 ————— 贪心3,3 + 3+ 4(余4则取4不再贪心),res = 3*3*4 = 36
     */
    public int integerBreak(int n) {
     
        if(n < 4){
     
            return n - 1;
        }
        int res = 1;
        while(n > 4){
     
            n -= 3;
            res *= 3;
        }
        return res * n;
    }
}

 

 

【Q_interview_08_03】(md) 魔术索引
 
在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。
 
示例1:
输入:nums = [0, 2, 3, 4, 5]
输出:0
 
示例2:
输入:nums = [1, 1, 1]
输出:1
 
提示: nums长度在[1, 1000000]之间

class Solution {
     
    /**
     *【跳跃法】
     * 
     * 核心思路就是 index = nums[index]
     * 唯一需要注意的是,nums[index]可能是负数,这是将index++就可以了,跳跃的话就数组越界了
     */
    public int findMagicIndex(int[] nums) {
     
        int res = -1;
        int i = 0;

        while(i < nums.length){
     
            if(nums[i] < 0){
     
                i++;
                continue;
            }
            if(nums[i] == i){
     
                res = i;
                break;
            }
            i = nums[i];
        }

        return res;
    }
}
补充 :
如果该题改为"没有重复元素"的话,二分法明显效率更高
"存在重复元素"导致根据mid无法断定出目标index是在左部分还是右部分,无法"减治",自然无法二分

 
 

 

 

 

 

 

 

 

 

 
 

 

 

Qs from https://leetcode-cn.com
♥ loli suki
♠ end

你可能感兴趣的:(Leetcode,算法,leetcode)