文章目录
50 实现 pow(x, n) ,即计算 x 的 n 次幂函数
https://leetcode-cn.com/problems/powx-n/
可以提出暴力和调用库函数的思路,但是不要写~
思路一:快速幂 + 递归
class Solution {
// N 全是 >= 0 的值(做逻辑复杂的处理的时候,
// 可以先将逻辑转换为统一的,这样就很好处理)
private double helper(double x, long N) {
if (N == 0) {
return 1.0;
}
double result = 0;
// 偶数
if (N % 2 == 0) {
result = helper(x * x, N / 2);
} else {
result = helper(x * x, N / 2) * x;
}
return result;
}
public double myPow(double x, int n) {
long N = n;
return N > 0 ? helper(x, N) : 1.0 / helper(x, -N);
}
}
- 时间:O(logN)
- 空间:O(logN)
思路二:快速幂 + 迭代 + 位运算
class Solution {
public double myPow(double x, int n) {
long N = n;
return N >= 0 ? helper(x, N) : 1.0 / helper(x, -N);
}
public double helper(double x, long N) {
double result = 1.0;
// 贡献的初始值为 x
double x_contribute = x;
// 在对 N 进行二进制拆分的同时计算答案
while (N > 0) {
if ((N & 1) == 1) {
// 如果 N 二进制表示的最低位为 1,那么需要计入贡献
result *= x_contribute;
}
// 将贡献不断地平方
x_contribute *= x_contribute;
// 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
N = N >> 1; //左乘右除
}
return result;
}
}
- 时间:O(logN)
- 空间:O(1)
169 求众数题目(剑指 Offer 39. 数组中出现次数超过一半的数字、169. 多数元素)
https://leetcode-cn.com/problems/majority-element/
思路:
- Hash 表存储<数组元素,出现次数>。复杂度:时间O(n) 空间O(n)
其实我感觉这种解法就很优雅了~
- sort () 排序 复杂度:时间O(nlogN) 空间O(1)
- 分治:如果数 a 是数组 nums 的众数,如果我们将 nums 分成两部分,那么 a 必定是至少一部分的众数。
这样以来,我们就可以使用分治法解决这个问题:将数组分成左右两部分,分别求出左半部分的众数 a1 以及右半部分的众数 a2,随后在 a1 和 a2 中选出正确的众数。
使用经典的分治算法递归求解,直到所有的子问题都是长度为 1 的数组。长度为 1 的子数组中唯一的数显然是众数,直接返回即可。如果回溯后某区间的长度大于 1,我们必须将左右子区间的值合并。如果它们的众数相同,那么显然这一段区间的众数是它们相同的值。否则,我们需要比较两个众数在整个区间内出现的次数来决定该区间的众数。
时间O(nlogN) 空间O(nlogN) - Boyer-Moore 投票算法:如果我们把众数记为 +1+1,把其他数记为 -1−1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。O(n) 空间O(1)
// 1. 哈希的做法
class Solution {
public int majorityElement(int[] nums) {
if (nums == null) {
return -1;
}
// <数组元素,出现次数>
HashMap<Integer, Integer> countMap = new HashMap<Integer, Integer>();
int result = 0;
for (int i = 0; i < nums.length; i++) {
if (!countMap.containsKey(nums[i])) {
countMap.put(nums[i], 1);
} else {
countMap.put(nums[i], countMap.get(nums[i]) + 1);
}
//判断出现次数,返回 数组元素
if (countMap.get(nums[i]) > (nums.length >> 1)) {
result = nums[i];
}
}
return result;
}
}
//2. 排序的做法
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
//这里注意:因为存在众数,所以其中间的一个数就是所求的结果
return nums[nums.length / 2];
}
}
//3. 分治
class Solution {
private int calCount(int[] nums, int num, int start, int end) {
int count = 0;
for (int i = start; i <= end; i++) {
if (num == nums[i]) {
count++;
}
}
return count;
}
private int helper(int[] nums, int start, int end) {
// 只有一个元素了
if (start == end) {
return nums[start];
}
int mid = (end - start) / 2 + start;
int left = helper(nums, start, mid);
int right = helper(nums, mid + 1, end);
if (left == right) {
return left;
}
int leftCount = calCount(nums, left, start, end);
int rightCount = calCount(nums, right, start, end);
return leftCount > rightCount ? left : right;
}
public int majorityElement(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
}
//4. Boyer-Moore 投票算法
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;
for (int num : nums) {
// 一旦相互抵消,那么就保存一下值
if (count == 0) {
candidate = num;
}
//相同就投一票,不相同就减一票
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
}