Java算法 盛最多水的容器(经典面试题)、三数之和(经典面试题)

小王的Java刷题日记Day6

记录刷题过程,作为笔记和分享,坚持每天刷题,每天进步,编程语言为Java。

题目一:盛最多水的容器(经典面试题)

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

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

例如:

输入:[1,8,6,2,5,4,8,3,7]
输出:49 

思路:双指针法    时间复杂度O(n)

设两指针 ij ,指向的水槽板高度分别为 h[i] , h[j] ,此状态下水槽面积为 S(i,j)。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :S(i,j)=min(h[i],h[j])×(j−i)。

那么接下来就要解释一下解题的思路了:

1、首先,我们知道容纳水的高度由短板决定,那么此时我们通过对比左右两板的长度,也就是高度,让短的移动。

2、头尾都设置指针,不断向内移动。那么此时它的底是在不断减小的,我们只有让高变大才有可能总面积变大。所以我们要移动短板,每次移动后都要进行比较,不断让短板内移。

3、在内移的过程中比较每次变化的面积,并将最大的记录下来。

class Solution {
    public int maxArea(int[] height) {
        int i=0,j=height.length-1,res=0;
        while(i<j){
            if(height[i]<height[j]){         //直到头尾指针相遇
                res=Math.max(res, (j - i) * height[i++]);
            }
            else{
                res=Math.max(res, (j - i) * height[j--]);
            } 
        }
        return res;
    }
}

题目二: 三数之和(经典面试题)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

例如:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

思路:排序,双指针法     时间复杂度O(n^2)

1、先进行排序,排序后我们固定一个数,让头尾指针指着其他两个数去移动,等相遇后我们再让固定的数向前移动。

2、

当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 3 个元素都大于 0 ,在此固定指针 k 之后不可能再找到结果了。

3、

当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。

4、

i,j 分设在数组索引 (k,len(nums))(k, len(nums))(k,len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动:

当s < 0时,i += 1并跳过所有重复的nums[i];
当s > 0时,j -= 1并跳过所有重复的nums[j];
当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。

class Solution {

    public List<List<Integer>> threeSum(int[] nums) {

        Arrays.sort(nums); // 对数组进行排序

        List<List<Integer>> res = new ArrayList<>(); // 存储结果的列表

        for(int k = 0; k < nums.length - 2; k++){ // 遍历数组,k表示三元组的第一个元素

            if(nums[k] > 0) break; // 如果当前元素大于0,后面的元素都会大于0,直接结束循环

            if(k > 0 && nums[k] == nums[k - 1]) continue; // 当前元素与上一个元素相同,避免重复计算,继续下一次循环

            int i = k + 1, j = nums.length - 1; // i为三元组的第二个元素,j为三元组的第三个元素

            while(i < j){ // 使用双指针法找到满足条件的三元组

                int sum = nums[k] + nums[i] + nums[j]; // 计算三个元素的和

                if(sum < 0){ // 如果和小于0,移动左指针,使得和增大

                    while(i < j && nums[i] == nums[++i]); // 跳过重复的元素

                } else if (sum > 0) { // 如果和大于0,移动右指针,使得和减小

                    while(i < j && nums[j] == nums[--j]); // 跳过重复的元素

                } else { // 如果和等于0,找到一个满足条件的三元组

                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j]))); // 将三元组加入结果列表

                    while(i < j && nums[i] == nums[++i]); // 跳过重复的元素

                    while(i < j && nums[j] == nums[--j]); // 跳过重复的元素

                }

            }

        }

        return res; // 返回结果列表

    }

}

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值