面試題11. 旋轉數組的最小數字
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1。
示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:0
排序數組的查找問題首先考慮使用二分法解決,將遍歷的線性級別時間複雜度降低至 對數級別
class Solution {
public:
int minArray(vector<int>& numbers) {
int n = numbers.size();
int left = 0, right = n - 1,mid;
while(left < right){
mid = (left + right)>>1;
//這裏用除2超出了時間限制了,隨後想到除2相當於二進制右移一位,比除法更快【乘2也如此】
if(numbers[mid] > numbers[right]) left = mid + 1;
else if(numbers[mid] == numbers[right]) right --;
else right = mid;
}
return numbers[left];
}
};
當然也可以排序後直接返回num[0]
int minArray(vector<int>& numbers) {
sort(numbers.begin(),numbers.end());
return numbers[0];
}
面試題12. 矩陣中的路徑
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格子。例如,在下面的3×4的矩陣中包含一條字符串“bfce”的路徑(路徑中的字母用加粗標出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩陣中不包含字符串“abfb”的路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入這個格子。
示例 1:
輸入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
輸出:true
示例 2:
輸入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
輸出:false
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
可以用回溯法【DFS】
由於遞歸特性,路徑可以被看成一個棧。當在矩陣中定位了路徑中前n個字符的位置之後,在與第n個字符對應的格子的周圍都沒有找到第n+1個字符,這時候只好在路徑上回到第n-1個字符,重新定位第n個字符。
class Solution {
public:
int rows,cols;
bool exist(vector<vector<char>>& board, string word) {
rows = board.size();
cols = board[0].size();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (board[i][j] == word[0]) {
if (dfs(board,word,i,j,1))
return true;
}
}
}
return false;
}
int x[4] = {0,0,-1,1};
int y[4] = {-1,1,0,0};
//進行上下左右移動,如下移:x+x下標,y+y下標.對於二維數組中的移動都可以這麼做
bool dfs(vector<vector<char>>& board,string word,int i,int j,int num) {
if (num == word.size())
return true;
char tmp = board[i][j];
board[i][j] = '.'; //標記被遍歷過了
for (int k = 0; k < 4; k++) {
int d_x = x[k] + i;
int d_y = y[k] + j;
if (d_x>=0&&d_x<rows&&d_y>=0&&d_y<cols&&word[num]==board[d_x][d_y]) {
if (dfs(board,word,d_x,d_y,num + 1))
return true;
}
}
board[i][j] = tmp;//如果周圍字符不匹配則還原被標記字符
return false;
}
};
面試題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。請問該機器人能夠到達多少個格子?
示例 1:
輸入:m = 2, n = 3, k = 1
輸出:3
示例 2:
輸入:m = 3, n = 1, k = 0
輸出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
廣度優先解法:
class Solution {
public:
int movingCount(int m, int n, int k) {
vector<vector<int>> visited(m, vector<int>(n, 0));
queue<pair<int, int>> q;
q.push({0, 0});
int res = 0;
visited[0][0] = 1;
while (!q.empty()) {
auto front = q.front(); q.pop();
int x = front.first;
int y = front.second;
res += 1;
for (auto d : directions) {
int new_x = x + d.first;
int new_y = y + d.second;
if (new_x < 0 || new_x >= m || new_y < 0 || new_y >= n
|| visited[new_x][new_y] == 1 ||
sumDigit(new_x, new_y) > k) {
continue;
}
q.push({new_x, new_y});
visited[new_x][new_y] = 1;
}
}
return res;
}
int sumDigit(int i, int j) {
int sum = 0;
while (i > 0) {
sum += i % 10;
i /= 10;
}
while (j > 0) {
sum += j % 10;
j /= 10;
}
return sum;
}
private:
vector<pair<int, int>> directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
};
回溯(深度優先
class Solution {
public:
void DFS(int m, int n, int k, int &res, int row, int col, vector<vector<int>> &vis, vector<vector<int>> &huisu){
huisu[row][col]=1;
//統計合法的且沒有訪問過的格子。
if(vis[row][col]==0){
res++;
vis[row][col]=1;
}
int i, j;
vector<vector<int>> offset={{-1,0},{1,0},{0,-1},{0,1}};
for(i=0;i<offset.size();i++){
int x=row+offset[i][0];
int y=col+offset[i][1];
if(x<0||x>=m||y<0||y>=n||!sumDigit(x,y,k)||vis[x][y]==1){
continue;
}
else{
DFS(m, n, k, res, x, y, vis, huisu);
}
}
huisu[row][col]=0;
}
bool sumDigit(int x, int y, int k){
int sum=0;
while(x>0){
sum+=x%10;
x=x/10;
}
while(y>0){
sum+=y%10;
y=y/10;
}
return sum>k?false:true;
}
int movingCount(int m, int n, int k) {
int res=0;
vector<vector<int>> vis(m, vector<int>(n,0));
//把已經走過的合法格子標記爲1,使得res不重複記錄合法的格子
vector<vector<int>> huisu(m, vector<int>(n,0));
//在DFS中,z某條路徑走過的格子標記爲1,避免下一次重複走回歷史的格子。
DFS(m, n, k, res, 0, 0, vis, huisu);
return res;
}
};
對於矩陣搜索,常用深度優先搜索,因爲其較爲直觀