![](http://static.javashuo.com/static/loading.gif)
點擊關注咱們獲取更多面試編程題css
![](http://static.javashuo.com/static/loading.gif)
劍指 Offer 面試題11-15java
劍指 Offer 上面的編程題目愈來愈受大廠面試官喜好,熟練地掌握裏面的題目是很是有必要的,尤爲是那些想進大廠的程序員。程序員
![](http://static.javashuo.com/static/loading.gif)
11面試
面試題11-旋轉數組中的最小數字算法
把一個數組最開始的若干個元素搬到數組的末尾,咱們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1編程
輸入:[3,4,5,1,2]輸出:1
解答狀況json
尋找旋轉數組的最小元素即爲尋找 右排序數組 的首個元素 nums[x] ,稱 x 爲 旋轉點 。swift
1 暴力解法-循環遍歷數組
逐個遍歷取最小值,顯然解決這道題有點不合適微信
2 二分法查找
看下二分查找的標準代碼
public int search(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) return mid; if (target < nums[mid]) right = mid - 1; else left = mid + 1; } return -1;}
對比二分查找,咱們能夠寫出以下代碼
public int minArray(int[] numbers) { int left = 0, right = numbers.length - 1; while (left < right) { //找出left和right中間值的索引 int mid = left + (right - left) / 2; if (numbers[mid] > numbers[right]) { //若是中間值大於最右邊的值,說明旋轉以後最小的 //數字確定在mid的右邊,好比[3, 4, 5, 6, 7, 1, 2] left = mid + 1; } else if (numbers[mid] < numbers[right]) { //若是中間值小於最右邊的值,說明旋轉以後最小的 //數字確定在mid的前面,好比[6, 7, 1, 2, 3, 4, 5], //注意這裏mid是不能減1的,好比[3,1,3],咱們這裏只是 //證實了numbers[mid]比numbers[right]小,但有可能 //numbers[mid]是最小的,因此咱們不能把它給排除掉 right = mid; } else { //若是中間值等於最後一個元素的值,咱們是無法肯定最小值是 // 在mid的前面仍是後面,但咱們能夠縮小查找範圍,讓right // 減1,由於即便right指向的是最小值,但由於他的值和mid // 指向的同樣,咱們這裏並無排除mid,因此結果是不會有影響的。 //好比[3,1,3,3,3,3,3]和[3,3,3,3,3,1,3],中間的值 //等於最右邊的值,但咱們無法肯定最小值是在左邊仍是右邊 right--; } } return numbers[left];}
12
面試題12-矩陣中的路徑
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串全部字符的路徑。路徑能夠從矩陣中的任意一格開始,每一步能夠在矩陣中向左、右、上、下移動一格。若是一條路徑通過了矩陣的某一格,那麼該路徑不能再次進入該格子。例如,在下面的3×4的矩陣中包含一條字符串「bfce」的路徑(路徑中的字母用加粗標出)。
例如,給出
[["a","b","c","e"], ["s","f","c","s"], ["a","d","e","e"]]
但矩陣中不包含字符串「abfb」的路徑,由於字符串的第一個字符b佔據了矩陣中的第一行第二個格子以後,路徑不能再次進入這個格子。
解答狀況
本問題是典型的矩陣搜索問題,可以使用 深度優先搜索(DFS)+ 剪枝 解決。
算法原理:
深度優先搜索:能夠理解爲暴力法遍歷矩陣中全部字符串可能性。DFS 經過遞歸,先朝一個方向搜到底,再回溯至上個節點,沿另外一個方向搜索,以此類推。
剪枝:在搜索中,遇到 這條路不可能和目標字符串匹配成功 的狀況(例如:此矩陣元素和目標字符不一樣、此元素已被訪問),則應當即返回,稱之爲 可行性剪枝 。
算法剖析:
遞歸參數:當前元素在矩陣 board 中的行列索引 i 和 j ,當前目標字符在 word 中的索引 k 。
終止條件:
返回 false :① 行或列索引越界 或 ② 當前矩陣元素與目標字符不一樣 或 ③ 當前矩陣元素已訪問過 (③ 可合併至 ② ) 。
返回 true :字符串 word 已所有匹配,即 k = len(word) - 1 。
遞推工做:
標記當前矩陣元素:將 board[i][j] 值暫存於變量 tmp ,並修改成字符 '/' ,表明此元素已訪問過,防止以後搜索時重複訪問。
搜索下一單元格:朝當前元素的 上、下、左、右 四個方向開啓下層遞歸,使用 或 鏈接 (表明只需一條可行路徑) ,並記錄結果至 res 。
還原當前矩陣元素:將 tmp 暫存值還原至 board[i][j] 元素。
回溯返回值:返回 res ,表明是否搜索到目標字符串
圖解中,從每一個節點 DFS 的順序爲:下、上、右、左。
-
時間複雜度 O(3^K*MN):最差狀況下,須要遍歷矩陣中長度爲 K 字符串的全部方案,時間複雜度爲 O(3^K);矩陣中共有 MN 個起點,時間複雜度爲 O(MN) 。
-
方案數計算:設字符串長度爲 K ,搜索中每一個字符有上、下、左、右四個方向能夠選擇,捨棄回頭(上個字符)的方向,剩下 33 種選擇,所以方案數的複雜度爲 O(3^K)。
-
空間複雜度 O(K) :搜索過程當中的遞歸深度不超過 K ,所以系統因函數調用累計使用的棧空間佔用 O(K) (由於函數返回後,系統調用的棧空間會釋放)。最壞狀況下 K = MN ,遞歸深度爲 MN ,此時系統棧使用 O(MN) 的額外空間。
class Solution { public boolean exist(char[][] board, String word) { char[] words = word.toCharArray(); for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[0].length; j++) { if(dfs(board, words, i, j, 0)) return true; } } return false; } boolean dfs(char[][] board, char[] word, int i, int j, int k) { if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false; if(k == word.length - 1) return true; char tmp = board[i][j]; board[i][j] = '/'; boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1); board[i][j] = tmp; return res; }}
13
面試題13-機器人的運動範圍
地上有一個m行n列的方格,從座標 [0,0] 到座標 [m-1,n-1] 。一個機器人從座標 [0, 0] 的格子開始移動,它每次能夠向左、右、上、下移動一格(不能移動到方格外),也不能進入行座標和列座標的數位之和大於k的格子。例如,當k爲18時,機器人可以進入方格 [35, 37] ,由於3+5+3+7=18。但它不能進入方格 [35, 38],由於3+5+3+8=19。請問該機器人可以到達多少個格子?
解答狀況
代碼以下:
class Solution { int m, n, k; boolean[][] visited; public int movingCount(int m, int n, int k) { this.m = m; this.n = n; this.k = k; this.visited = new boolean[m][n]; return dfs(0, 0, 0, 0); } public int dfs(int i, int j, int si, int sj) { if(i >= m || j >= n || k < si + sj || visited[i][j]) return 0; visited[i][j] = true; return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj) + dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8); }}
代碼以下:
class Solution { public int movingCount(int m, int n, int k) { boolean[][] visited = new boolean[m][n]; int res = 0; Queue<int[]> queue= new LinkedList<int[]>(); queue.add(new int[] { 0, 0, 0, 0 }); while(queue.size() > 0) { int[] x = queue.poll(); int i = x[0], j = x[1], si = x[2], sj = x[3]; if(i >= m || j >= n || k < si + sj || visited[i][j]) continue; visited[i][j] = true; res ++; queue.add(new int[] { i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj }); queue.add(new int[] { i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8 }); } return res; }}
14
面試題14 剪繩子
用兩個棧實現一個隊列。隊列的聲明以下,請實現它的兩個函數 appendTail 和 deleteHead ,分別完成在隊列尾部插入整數和在隊列頭部刪除整數的功能。(若隊列中沒有元素,deleteHead 操做返回 -1 )
解答狀況
第1種解法以下:
代碼以下:
class Solution { public int cuttingRope(int n) { if(n <= 3) return n - 1; int a = n / 3, b = n % 3; if(b == 0) return (int)Math.pow(3, a); if(b == 1) return (int)Math.pow(3, a - 1) * 4; return (int)Math.pow(3, a) * 2; }}
第2種解法以下:
代碼以下:
class Solution { public int cuttingRope(int n) { int[] dp = new int[n + 1]; for (int i = 2; i <= n; i++) { for (int j = 1; j < i; j++) { dp[i]= Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j])); } } return dp[n]; }}
第3種解法以下:函數級值
class Solution { public int cuttingRope(int n) { if (n <= 3) { return n - 1; } int quotient = n / 3; int remainder = n % 3; if (remainder == 0) { return (int) Math.pow(3, quotient); } else if (remainder == 1) { return (int) Math.pow(3, quotient - 1) * 4; } else { return (int) Math.pow(3, quotient) * 2; } }}
15
面試題15 二進制中1的個數
請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。所以,若是輸入 9,則該函數輸出 2。
輸入:00000000000000000000000000001011 輸出:3 解釋:輸入的二進制串 00000000000000000000000000001011 中,共有三位爲 '1'。 |
解答狀況
代碼以下:
public class Solution { public int hammingWeight(int n) { int res = 0; while(n != 0) { res += n & 1; n >>>= 1; } return res; }}
代碼以下:
public class Solution { public int hammingWeight(int n) { int res = 0; while(n != 0) { res++; n &= n - 1; } return res; }}
END
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - Java學習進階手冊(javastudyup)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。