1. 题目
- 实现pow(x,n),即计算x的n次幂函数
- 求众数,给定一个大小为n的数组,找到其中的众数。众数是指出现次数大于 n/2 的元素。
2. 基本知识
2.1 二叉树遍历
- 前序遍历:根-左-右
- 中序遍历:左-根-右
- 后序遍历:左-右-根
前序顺序:A-B-D-E-C-F-G
中序遍历:D-B-E-A-F-C-G
后序遍历:D-E-B-F-G-C-A
2.2 递归
递归,就是在运行的过程中调用自己
构成递归的条件:
- 子问题和原始问题是同样的问题,并且会更简单
- 不能无限循环,必须有一个终止条件
示例:
// n的阶乘:1*2*3*...*(n-1)*n
public int Factorial(int n){
if (n <=1) {
return 1;
}
return n*Factorial(n-1);
}
2.3 分治
将复杂问题分为两个或者多个子问题,直至问题能够简单求解,最后复杂问题是这些简单问题解的合并。一般使用递归来实现。
3. 算法题解题
3.1 实现pow(x,n),即计算x的n次幂函数
解法1:暴力解法
循环n次,每次乘以x。
时间复杂度为O(n),空间复杂度也为O(1)
double myPow(double x, int n){
int N = n;
// n小于0的情况为(1/x)的 -n次幂,例子:pow(2,-2)结果为:pow(1/2,2)
if (n < 0){
N = -n;
x = 1/x;
}
double ans = 1;
for (int i = 0; i < N; i++) {
ans = ans * x;
}
return ans;
}
解法2: 递归
xn可以拆解为两个x(n/2),同理一直拆解下去,知道n为1时返回1.需要注意的是奇数情况下,返回值为int,则n/2等同于(n-1)/2,所以需要多乘以x。
此解法时间复杂度为O(logn),空间复杂度为:O(1)
double myPow(double x, int n){
int N = n;
// n小于0的情况为(1/x)的 -n次幂,例子:pow(2,-2)结果为:pow(1/2,2)
if (n < 0){
N = -n;
x = 1/x;
}
return fastPow(x,N);
}
private double fastPow(double x, int n) {
if (n == 0) return 1;
double half = fastPow(x,n/2);
if (n%2 == 0){
//偶数
return half*half;
}else{
//奇数情况下,返回值为int,则n/2等同于(n-1)/2
return half * half * x;
}
}
解法3:循环
此解法位置暂时预留
3.2 求众数,给定一个大小为n的数组,找到其中的众数
解法1:暴力解法
两层循环,分别对同一个元素的个数进行累加,得到众数
时间复杂度为O(n2),空间复杂度也为O(1)
public int majorityElement(int[] nums){
int majorityCount = nums.length/2;
for (int number :nums) {
int count = 0;
for (int ele :nums) {
if (number == ele) {
count += 1;
}
}
if (count > majorityCount) return number;
}
return -1;
}
解法2:哈希表
使用hash表存储元素及其对应的出现次数,然后,遍历hash表,将出现次数大于n/2的元素返回。
此解法时间复杂度:O(n),空间复杂度O(n)
public int majorityElement(int[] nums){
int majorityCount = nums.length/2;
HashMap<Integer, Integer> countMap = getCountNums(nums);
Map.Entry<Integer, Integer> majorityEntry = null;
for (Map.Entry<Integer, Integer> entry :countMap.entrySet()) {
if(entry.getValue() > majorityCount){
majorityEntry = entry;
}
}
if (majorityEntry == null) return -1;
return majorityEntry.getKey();
}
/**
* 用hashMap存儲key和出现的次数
* @param nums
* @return
*/
private HashMap<Integer, Integer> getCountNums(int[] nums) {
HashMap<Integer, Integer> majorMap = new HashMap<>();
for (int number :nums) {
if (majorMap.containsKey(number)){
majorMap.put(number, majorMap.get(number) + 1);
}else{
majorMap.put(number, 1);
}
}
return majorMap;
}
解法3 排序
此解法时间复杂度O(1),空间复杂度O(1)
/**
* 因为众数要个数大于n/2,所以排序后的n/2处必定是众数元素
* @param nums
* @return
*/
public int majorityElemet(int[] nums){
Arrays.sort(nums);
return nums[nums.length/2];
}
算法4 分治
如果把数组一分为二,求出左边的众数和右边的众数,如果两边得到的众数一样,则直接返回,如果不一样,则在当前的子数组中算出该数的个数,然后左右众数的个数比较,谁个数多就返回谁。
public int majorityElement(int[] nums){
return majorityElementEach(nums, 0, nums.length -1);
}
private int majorityElementEach(int[] nums, int le, int ri) {
// 只有一个元素了,直接返回
if (le == ri)
return nums[le];
int mid = (ri - le)/2 + le;
// 从中分开,分别计算左右的众数
int left = majorityElementEach(nums, le, mid);
int right = majorityElementEach(nums,mid+1, ri);
// 如果左右都有相同的众数,则返回
if (left == right) return left;
// 分别计算left和right的个数
int leftCount = countInRange(nums,left,le,ri);
int rightCount = countInRange(nums,right,le,ri);
return leftCount > rightCount ? leftCount : rightCount;
}
private int countInRange(int[] nums, int num, int le, int ri) {
int count = 0;
for (int i = le; i < ri - le; i++) {
if (nums[i] == num){
count ++;
}
}
return count;
}