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;
}
}
多数元素
给定一个大小为 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;
}
}
盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
思路一
:最基本的思路,双重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 所以往数大的方向移动后的面积永远不会大于不移动的面积!所以只可以往数小的方向移动