leetcode热题100-移动零,盛最多的水(和类似题)

移动零

思路一

两层循环,第一个指针指向0,第二个指针指向第一个不为0的数,交换两个指针,时间复杂度为O(n2)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int zero, non_zero;
        for (zero = 0; zero < nums.size(); zero++) {
            //找到第一个0
            if (nums[zero] == 0) {
                for (int non_zero = zero + 1; non_zero < nums.size(); non_zero++) {
                    if (nums[non_zero] != 0) {
                        swap(nums[zero], nums[non_zero]);
                        break;
                    }
                }
            }
        }
        return;
    }
};

思路二

选择用两个指针,快慢指针,开始时都指向第一个0,快指针向后遍历,如果是0则继续,如果不是0则让慢指针赋值为快指针,当快指针遍历完成后,慢指针遍历升序数组,都赋值为0
此时,时间复杂度为O(n)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int fast,slow;
        //找到第一个0
        for(slow=0;slow<nums.size();slow++){
            if(nums[slow]==0)break;
        }
        //快指针赋值给慢指针
        fast=slow+1;
        while(fast<nums.size()){
            if(nums[fast]==0)fast++;
            else {
                nums[slow]=nums[fast];
                slow++;
                fast++;
            }
        }
        //慢指针最后赋值0
        while(slow<nums.size()){
            nums[slow++]=0;
        }
        return;
    }
};

盛最多的水

思路一(超时)

本题可以使用两层循环,分别遍历左边的高度h1和右边的高度h2,找到最大值(h1和h2与x轴围成的面积),时间复杂度O(n2),但是超时了

class Solution {
public:
    int maxArea(vector<int>& height) {
        int max = 0;
        for (int i = 0; i < height.size(); i++) {
            for (int j = i + 1; j < height.size(); j++) {
                if ((min(height[i], height[j]) * (j - i)) > max) {
                    max = min(height[i], height[j]) * (j - i);
                }
            }
        }
        return max;
    }
};

思路二

指路一个大神解析

  • 当前柱子是最两侧的柱子,水的宽度 d 为最大,其他的组合,水的宽度都比这个小。
  • 左边柱子较短,决定了水的高度为 3。如果移动左边的柱子,新的水面高度不确定,一定不会超过右边的柱子高度 7。
  • 如果移动右边的柱子,新的水面高度一定不会超过左边的柱子高度 3,也就是不会超过现在的水面高度。

因此,选择两个指针,分别指向头尾,得到当前面积,将较小的指针移动,得到新的当前面积,直到两个指针相遇,结束遍历,得到最终最大面积,时间复杂度为O(n)

神之一图:

在这里插入图片描述

class Solution {
public:
    int maxArea(vector<int>& height) {
        int max = 0;
        int left = 0, right = height.size()-1;
        while (left != right) {
            int s;
            s=min(height[left],height[right])*(right-left);
            if (s > max)max = s;
            if (height[left] < height[right])left++;
            else right--;
        }
        return max;
    }
};

两数之和Ⅱ

本题和上题可以用类似的方法,指路大神操作
一次排除多个单元格,选择两个指针,分别指向首位A[0]A[n]A为升序

  • 如果A[0]+A[n]>target,说明A[1]+A[n]/A[2]+A[n]…都大于target
  • 如果A[0]+A[n]<target,说明A[0]+A[n-1]/A[0]+A[n-2]…都小于target

以上两种情况都可以排除“神之一图”中的一行或一列

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left=0,right=numbers.size()-1;
        while(left!=right){
            if(numbers[left]+numbers[right]==target){
                return {left+1,right+1};
            }
            if(numbers[left]+numbers[right]<target)left++;
            if(numbers[left]+numbers[right]>target)right--;
        }
        return {left+1,right+1};
    }
};
  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值