【数据结构与算法】leetcode刷题记录(盛水最多的容器+整数转罗马数字) --->双指针遍历+哈希map

盛水最多的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 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
示例 3:

输入:height = [4,3,2,1,4]
输出:16
示例 4:

输入:height = [1,2,1]
输出:2

提示:
    n = height.length
    2 <= n <= 3 * 104
    0 <= height[i] <= 3 * 104

java解决

1.遍历法:

两个循环遍历分别计算每一个柱子之间的容量

找到最大的容量

缺点:时间复杂度高

class Solution {
    public int maxArea(int[] height) {
        int width ;
        int minHeight;
        int maxValue=0;
        for(int i = 0;i<height.length;i++){
            for(int j = i+1;j<height.length;j++){
                if(height[i]<height[j])
                    minHeight = height[i];
                else
                    minHeight = height[j];
                width = j - i;
                if(maxValue<(width*minHeight)){
                    maxValue = width*minHeight;
                }
            }
        }
        return maxValue;
    }
}
//缺点: 时间复杂度高

2.双指针遍历

上面的遍历其实也类似双指针,但是for循环的嵌套相当于固定一个指针,移动另一个指针,所以要找到最大的就必须全部遍历完毕,显然有很多是不用去遍历的,所以双指针可以减少遍历的次数.

思考一下:

在这里插入图片描述

按照上面的图来讲: 首先两个指针 i 和 j 分别在 0 和 length - 1 处 时,这个时候容器的容量等于: i 和 j 之间的距离 (j - i)*他们中最低的柱子. 面积等于 1 * 8 = 8

这时两个指针就要发生移动, 可以想象一下, 定一动一:

1. 定小( i )动大( j ) : 这时不论 j 移动到任何位置, 他们中的高度始终时最低的 i = 1 ; 所以不论 j 移动到任何地方,面积都不会比 8 要大;

2. 定大( j )动小( i ): 这时当指针 i 向后移动后,如果 i 找到了比原来的 i 处的值更大的数 , 那么容器的容量( 面积 )就会不一样, 这样才有可能超过第一次的面积;

3. 同时移动: 同时移动两个指针,虽然面积也有可能会超过第一次面积,但是,这样移动有可能会漏掉很多的面积,如果碰巧漏掉了最大值,结论就会时错误的.

所以,上述结论不难看出, 我们只需要定大的柱子, 移动值稍微小点的柱子, 那么就可以找到所有的更大的面积;

class Solution {
    public int maxArea(int[] height) {
        int maxValue = 0;
        int i = 0;
        int j = height.length - 1;
        while (i < j) {
            int area = (j - i) * Math.min(height[i], height[j]);
            maxValue = Math.max(maxValue, area);
            if (height[i] < height[j])
                i++;
            else
                j--;
        }
        return maxValue;
    }
}

python方案

双指针:

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i = 0
        j = len(height)-1
        maxValue = 0
        while(i<j):
            area = min(height[i],height[j])*(j - i)
            maxValue = max(maxValue,area)
            if(height[i]<height[j]):
                i+=1
            else:
                j-=1
        return maxValue

整数转罗马数字

java解决

罗马数字有自身的规则:

{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
{"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"}

按照上面两个数组中的元素对应: 1000 就是 M , 999 就是 CMXCIX,

整体规则其实并不明朗,因为 1 -> I , 2 -> II 3 ->III , 4 却不是 IIII 而是 IV

所以,把一些特殊的加进去即可,总体上满足,有大的优先大的:

class Solution {
    int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    String[] flag = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
    public String intToRoman(int num) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.length && num >= 0; i++) {
            while (values[i] <= num) {
                num -= values[i];
                sb.append(flag[i]);
            }
        }
        return sb.toString();
    }
}

python

同上,不过,python有dict字典可以使用,所以方便我们建立哈希表:

class Solution:
    def intToRoman(self, num: int) -> str:
        hashmap = {1000:'M', 900:'CM', 500:'D', 400:'CD', 100:'C', 90:'XC', 50:'L', 40:'XL', 10:'X', 9:'IX', 5:'V', 4:'IV', 1:'I'}
        s1 = ''
        for key in hashmap:
            if num // key != 0:
                count = num // key
                s1 += hashmap[key] * count 
                num %= key
        return s1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值