Leetcode刷题(十七)

盛最多水的容器(Medium)

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 1
输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:

输入:height = [1,1]
输出:1
提示:

n == height.length
2 <= n <= 105
0 <= height[i] <= 104
Related Topics
贪心
数组
双指针


示例 1:
Leetcode刷题(十七)_第1张图片

思路分析

在看到问题之后的第一个想法就是列举出所有可能的组合,但是这个方法要么时间复杂度很大,要么使用递归使得空间复杂度很大。但我还是尝试了一下

    public static int maxArea(int[] height) {
        int maxArea = 0;

        for (int i = 0; i < height.length - 1; i++) {
            for (int j = i + 1; j < height.length; j++) {
                int area = (j - i) * Math.min(height[i], height[j]);
                maxArea = Math.max(maxArea, area);
            }
        }

        return maxArea;
    }

最后的运行结果就是超过了答题的时间限制。

那么,应该怎么做呢,看到题目中的提示可以知道,这道题需要使用贪心算法,

贪心算法是一种在每一步选择中都采取当前状态下最优(即最有利)的选择,以期望导致全局最优解的算法策略。这种方法在解决某些优化问题时非常有效,但并不总是得到最终的最优解。

贪心算法的基本特点:

  1. 局部最优选择:在每个步骤中,算法都做出在当前看来最好的选择。它不考虑全局的最优解,只关注局部的最优解。
  2. 没有回溯:一旦作出了选择,就不会撤销。这与回溯算法或动态规划不同,后者可能会根据后续的选择调整之前的选择。
  3. 简单高效:通常情况下,贪心算法比其他算法(如动态规划)更简单,且在处理某些问题时更高效。
  4. 不保证最优解:贪心算法不总是能得到全局最优解,它只能保证在某种意义上的局部最优解。

在是否选择使用贪心算法的时候主要考虑两个问题:

  1. 贪心选择性质:检查问题是否允许做出局部最优(贪心)的选择,并且这些局部最优选择能够导致全局最优解。这意味着每一步的最优决策只依赖于当前状态,而不依赖于之前的决策或未来的结果。
  2. 最优子结构:问题的最优解包含其子问题的最优解。即可以通过组合子问题的最优解来构造整个问题的最优解。

在这道题中我们首先要理解题目,由于是盛水的容器,所以容量取决于最短的边以及底部长度,这里我们设定两个指针i 和 j,分别指向最左边和最右边。
问题目标:找到两个点 (i, h[i]) 和 (j, h[j])(其中 i < j),使得它们围成的矩形区域 (j - i) * min(h[i], h[j]) 最大。

贪心策略:初始时,考虑最远的两条线,即在数组的两端。每次移动较短的那条线向内,即如果 h[i] < h[j],则 i 向右移动,反之 j 向左移动。

正确性证明:状态表示:S(i, j) 表示考虑第 i 条线和第 j 条线围成的容器。短板效应:容器的容量由较短的那条线(短板)决定。即容量 C = (j - i) * min(h[i], h[j])。

移动短板的后果:假设在 S(i, j) 中 h[i] < h[j],则移动 i(即考虑 S(i+1, j))。在移动短板后,所有被排除的状态(S(i, j-1), S(i, j-2), …, S(i, i+1))的短板要么和 S(i, j) 一样高,要么更短,且底边更短。

为何不会错过最大值:在 S(i, j-1), S(i, j-2), …, S(i, i+1) 这些状态中,即使有的状态的底边比 S(i, j) 长,但由于短板更短或不变,因此它们的容量不可能超过 S(i, j)。由于 S(i, j) 已经考虑了当前情况下可能的最大容量,排除这些状态不会丢失更大的容量。

贪心的正确性:通过每次只移动短板,我们保证了每一步都尽可能地保持最大容量。因为如果移动了长板,短板不变,则容量一定减小。所以,通过这种方式枚举,我们不会错过任何可能的更大容量状态。

简而言之,该贪心算法的正确性在于它保证了每次操作都在尝试更大的容量,而忽略那些无论如何都不可能超过当前已知最大容量的状态。这种方法有效地缩小了搜索范围,同时确保了不会错过可能的最大容量解。

代码实现

class Solution {
    public int maxArea(int[] height) {
        int i = 0, j = height.length - 1, res = 0;
        while(i < j) {
            res = height[i] < height[j] ? 
                Math.max(res, (j - i) * height[i++]): 
                Math.max(res, (j - i) * height[j--]); 
        }
        return res;
    }
}

个人笔记

在这道题中虽然穷举所有的组合并不是好的方法,但可以了解一下如何使用递归的方式来举出所有的组合方式。

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class CombinationPicker {
    public static void main(String[] args) {
        // 定义一个包含五个元素的数组
        int[] elements = {1, 2, 3, 4, 5};

        // 获取所有可能的组合
        List<int[]> combinations = getAllCombinations(elements, 2);

        // 打印所有组合
        for (int[] combination : combinations) {
            System.out.println("[" + combination[0] + ", " + combination[1] + "]");
        }

        // 随机选取一个组合
        Random random = new Random();
        int[] randomCombination = combinations.get(random.nextInt(combinations.size()));
        System.out.println("Randomly selected combination: [" 
                           + randomCombination[0] + ", " + randomCombination[1] + "]");
    }

    // 方法:生成所有可能的两元素组合
    public static List<int[]> getAllCombinations(int[] elements, int k) {
        List<int[]> combinations = new ArrayList<>();
        combine(elements, new int[k], 0, 0, combinations);
        return combinations;
    }

    // 辅助递归方法:用于生成组合
    private static void combine(int[] elements, int[] data, int start, int index, List<int[]> combinations) {
        if (index == data.length) {
            combinations.add(data.clone());
            return;
        }

        for (int i = start; i <= elements.length - data.length + index; i++) {
            data[index] = elements[i];
            combine(elements, data, i + 1, index + 1, combinations);
        }
    }
}

你可能感兴趣的:(Leetcode刷题实录,leetcode,windows)