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;
}