LeetCode刷题 11. 盛最多水的容器、283. 移动零、70. 爬楼梯

盛最多水的容器

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

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

示例:

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

java

解法一、暴力解法

思路分析

  • 在无思路的过程中,写一个暴力方法,不失为一直最有效的方法

复杂度分析:

  • 时间复杂度 O(N^2) ,N 表示数组的长度
  • 空间复杂度 O(1)
class Solution {
    public int maxArea(int[] height) {
        if (height.length<2) {
            return 0;
        }
        int max = 0;
        for (int i =0;i<height.length-1;i++) {
            for (int j=i+1;j<height.length;j++) {
                int writer = (j-i)*Math.min(height[i],height[j]);
                max = Math.max(max,writer);
            }
        }
        return max;

    }
}

 

解法二、双指针法

思路:
     算法流程: 设置双指针 i,j分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res,直到 i == j 时返回 res。

指针移动规则与证明: 每次选定围成水槽两板高度 h[i],h[j]中的短板,向中间收窄 1 格。以下证明:

设每一状态下水槽面积为 S(i, j),(0 <= i < j < n),由于水槽的实际高度由两板中的短板决定,则可得面积公式 S(i, j) = min(h[i], h[j]) × (j - i)。

 在每一个状态下,无论长板或短板收窄 1 格,都会导致水槽 底边宽度 −1:   

        若向内移动短板,水槽的短板 min(h[i], h[j])可能变大,因此水槽面积 S(i, j) 可能增大。
        若向内移动长板,水槽的短板 min(h[i], h[j]) 不变或变小,下个水槽的面积一定小于当前水槽面积。

因此,向内收窄短板可以获取面积最大值。

  • 因此所有消去的状态的面积都 < S(i, j)<S(i,j)。通俗的讲,我们每次向内移动短板,所有的消去状态都不会导致丢失面积最大值 。

时间复杂度 O(N),双指针遍历一次底边宽度 N 。
空间复杂度 O(1),指针使用常数额外空间。

代码:

class Solution {
    public int maxArea(int[] height) {//双指针解法
      int maxArea= 0;
      for (int i =0, j = height.length -1 ; i < j ;) {
         int minHeigth = height[i] <  height[j] ? height[i ++] : height[j --];//巧妙的 移动指针
         int area = minHeigth * (j - i +1);
         maxArea = Math.max(maxArea,area);
      }
      return maxArea;
    }
}

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。

方法一:覆盖的写法

解题思路

  • 遍历数组,无为0的元素移动数组前方,用index下标记录。
  • 遍历结束,对index值后的元素统一设为0
class Solution {
    public void moveZeroes(int[] nums) {
      int index = 0;
      for(int num:nums){
          if(num!=0){
              nums[index++]=num;
          }
      }
      while(index<nums.length){
          nums[index++] = 0;
      }
    }
}

方法二:双指针Java解法

双指针交换数据

class Solution {
    public void moveZeroes(int[] nums) {
      int  j = 0 ;
      for (int i= 0; i < nums.length; i ++) {
        if (nums[i] != 0) {
           if (i != j) {
            int num = nums[j];
            nums[j] = nums[i];
            nums[i] = num;
           }
           j ++ ;
        }
      }
    }
}

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

JAVA

方法一:动态规划

算法

不难发现,这个问题可以被分解为一些包含最优子结构的子问题,即它的最优解可以从其子问题的最优解来有效地构建,我们可以使用动态规划来解决这一问题。

第 ii 阶可以由以下两种方法得到:

在第 (i-1)阶后向上爬一阶。

在第 (i-2) 阶后向上爬 2阶。

所以到达第 ii 阶的方法总数就是到第 (i-1) 阶和第 (i-2)阶的方法数之和。

令 dp[i]dp[i] 表示能到达第 ii 阶的方法总数:

dp[i]=dp[i-1]+dp[i-2]
 

class Solution {
    public int climbStairs(int n) {
     int[] dp = new int[n + 2];
     dp[1] = 1;
     dp[2] = 2;
     for (int i =3 ; i <= n ; i ++) {
        dp[i] =dp[i- 1] + dp[i -2];
     }
     return dp[n];
    }
}

方法二 :斐波那契数

算法

     在上述方法中,我们使用 dpdp 数组,其中 dp[i]=dp[i-1]+dp[i-2]。可以很容易通过分析得出 dp[i] 其实就是第 i 个斐波那契数。

Fib(n)=Fib(n-1)+Fib(n-2)

class Solution {
    public int climbStairs(int n) { //斐波那契数
     if (n==1) return 1;
     if (n==2)  return 2;
     int f1 =1 ,f2 = 2 ,f3  =3;
     for (int i =3; i <=n ; i ++ ) {
         f3 = f2 + f1;
         f1 =f2;
         f2 = f3;  
     }
     return f3;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值