算法复盘 ~ 4的幂、多数元素、 盛最多水的容器

4 的幂

给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x

思路一:循环判断即可,最后看结果是否为小数

class Solution {
    public boolean isPowerOfFour(int n) {
        double x = n;
        while(x > 1){
            x /= 4;
        }
        return x == 1 ? true : false;
    }
}

思路二:借鉴2的次幂的做法,判断一个数是否是2的次幂可以采取 n & (n - 1),能这样做的依据是对于2次幂的数,它的二进制显示形式一定是最高为1其他为0

那么对于判断4的次幂的也可以使用同样的思路,例如对于16 二进制为(10000)2,可以发现具备相同的规律。一个数要为4的次幂,那么必须是2的次幂,接着将这个数和

(10101010101010101010101010101010)2进行相与即可

class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0  && (n & 0xaaaaaaaa) == 0;
    }
}

多数元素

169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

思路一:使用哈希表,思路比较明确

class Solution {
    public int majorityElement(int[] nums) {
        Map<Integer, Integer> hash = new HashMap<>();
        for(int temp : nums){
            hash.put(temp, hash.get(temp) == null ? 1 : hash.get(temp) + 1);
        }
        for(int temp : hash.keySet()){
            if(hash.get(temp) > nums.length / 2) return temp;
        }
        return 0;
    }
}

思路二:投票算法,首先随机选取一个数作为候选数,接着遍历数组,当遇到一个数nums[i] 等于该候选数的时候,count + 1,等于该候选数的时候,count–,如果当count小于0那么该候选数一定不是众数

class Solution {
    public int majorityElement(int[] nums) {
        int q = nums[0];
        int count = 1;
        for(int temp : nums){
            if(temp == q) count++;
            else if (-- count <= 0){
                q = temp;
                count = 1;
            }
        }
        return q;

    }
}

盛最多水的容器

11. 盛最多水的容器

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

image-20210531201308018

思路一:最基本的思路,双重for循环暴力破解,超时

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

思路二:题解思路,使用双指针的做法,真的很难想到,先给出简单的理解,后面再给出证明。

使用两个指针i,j分别指向数组的两端,此时的面积为 min(height[i], height[j]) * (j - i),这个时候要求出最大的面积,需要将指针进行移动,那么怎么移动呢?将指针进行移动的过程中,方形的底变下,要想总的面积变大,那么必须在min(height[i], height[j]) 这里下文章,那么指针应该是往数大的一方移动呢?还是往数小的一方移动呢?还是一起移动?

其实可以首先排除一起移动,一起移动对整体的结果影响太大了,很容易漏掉最优解,要想水桶里面装的水更多,那么很显然就是需要将最低的抬高,所以应该是往数小的一方移动(注意:这里说的移动是指对于左边的i来说,i++;对于右边的j来说是j–)

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

下面给出数学证明:

假设当前两个指针指向的值分别为x ,y,那么当前的面积为 min(x, y) * t (t = j - i ),同时可以使x < y,假设移动更大的数y,也就是说移动后的面积为 min(x , y1) * t1

根据上面的假设,一定有t1 < t,那么对于y1 与 y有两种情况:

  • y1 <= y:min(x , y1 ) < min(x , y)
  • y1 > y :min(x, y1) = x = min(x , y) 因为有x < y < y1

可见对于上面两种情况来说,往数更大的方向移动,一定有min(x , y1 ) <= min(x , y),那么又因为t1 < t 所以往数大的方向移动后的面积永远不会大于不移动的面积!所以只可以往数小的方向移动

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值