HashMap
hashmap的原理這裡不再講述,不知道的小夥伴可以看這篇文章。Hash與HashMap
hashmap資料結構的引入能幫助我們將O(n)的時間複雜度降低為O(1)的時間複雜度,代價是使用了O(n)的空間複雜度。這麼一看好像功過參半。但是如果我們原來的時間複雜度是O(n^2),使用了hashmap後時間複雜度變為o(n),而只是空間複雜度變為O(n),那麼還是很划算的。
力扣第一題,兩數之和:
如果我們用單純的二維遍歷做的話
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
第一種方法時間高原因是,對於每一個第一層遍歷的i,我們都需要再次遍歷陣列找到target - i。
如果我們用hashmap將陣列元素值及對應下標存入hashmap裡,我們就可以直接獲得target - i對應下標值,而不需要第二次遍歷。
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
遇到的實際題目是三數之和,給一個陣列和一個目標值,在這個陣列中找到三個數相加為目標值,如果找得到返回true,如果找不到返回false。三數之和就可以使用hashmap將三層迴圈降為兩層迴圈,其他跟兩數之和相似。
動態規劃
基本思想:將待求解的問題分解成若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的解。
某音公司筆試題,力扣原題改編
思路是依次確定是否能到達第i個位置。到達第i個位置的要求是能到達第j個位置(i>j)並能從第j個位置直接跳躍至第i個位置。
public boolean canJump(int[] nums) {
// 邊界判斷
if (nums.length == 1) {
return true;
}
boolean[] dp = new boolean[nums.length];
int i;
// 從第1個下標可以直接到達的地方標記為可到達。
for (i = 0; i < nums[0] + 1 && i < nums.length; i++) {
dp[i] = true;
}
// 其餘標記為不可達
for (; i < nums.length; i++) {
dp[i] = false;
}
// 對於每一個位置i,確定是否能能到達第j個位置(i>j)並能從第j個位置直接跳躍至第i個位置
for (i = nums[0] + 1; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && j + nums[j] >= i) {
dp[i] = true;
break;
}
}
}
return dp[nums.length -1];
}
當然這只是一種思路,這題還有更快更好的方法。
力扣139題:單詞拆分
遇上題相同思路,不過在判斷一個單詞是否在陣列中時使用hashmap判斷即可。
這題也可以使用字典樹來實現,有興趣的小夥伴可以搜尋什麼是字典樹。
貪心演算法
基本思想:貪心演算法並不從整體最優上加以考慮,它所做的選擇只是在某種意義上的區域性最優解。
某公司面試題,力扣原題改編:
看起來很簡單,但是思考起來沒想到最優解。因為買入的天數一定小於賣出的天數,那麼買入天數的價格一定是賣出天數到第一天裡所有價格的最小值。解題思想是依次假設第i天是賣出那天,找第i天的之前最小价格那天價格,維護最大利潤。
public int maxProfit(int[] prices) {
if (prices.length <= 1)
return 0;
int min = prices[0], profit = 0;
for (int i = 0; i < prices.length; i++) {
min = Math.min(min, prices[i]);
profit = Math.max(profit, prices[i] - min);
}
return profit;
}
其他
某音筆試有一道核心是判斷否是雙端佇列的問題,就是一個佇列只能從兩端進。一次放入n個數,給一個陣列判斷是否是雙端佇列。6 3 1 2 4 5 7 8
筆試過程中想複雜了,後邊看到其實就是找到最小數,然後判斷最小數到頭尾是否是遞增序列。其實在學資料結構的時候做過類似的選擇題,但是不需要程式碼實現。對於平常的思想落實到程式碼實現很重要。
應試技巧
在網上看見說演算法題通過率*本題分數為最後得分。對於一些輸出True或False的題不會做可以直接輸出結果,或者輸出最小次數的題也可以直接輸出3或4或5。