面试题11 旋转数组的最小数字
题目:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
解法:
思路一:
遍历数组查询到反转点,时间复杂度未O(n),空间复杂度O(1);
class Solution {
public int minArray(int[] numbers) {
for(int i=0;i<numbers.length-1;i++){
if(numbers[i]>numbers[i+1]){
return numbers[i+1];
}
}
return numbers[0];
}
}
class Solution:
def minArray(self, numbers: List[int]) -> int:
for i in range(len(numbers)-1):
if numbers[i]>numbers[i+1]:
return numbers[i+1]
return numbers[0]
思路二:
使用二分法查找数组元素,时间复杂度降低至对数级别:
class Solution {
public int minArray(int[] numbers) {
int i=0,j=numbers.length-1;
while(i<j){
int m=(i+j)/2;
if(numbers[m]>numbers[j]) i=m+1;
else if(numbers[m]<numbers[j]) j=m;
else j--;
}
return numbers[i];
}
}
class Solution:
def minArray(self, numbers: List[int]) -> int:
i,j=0,len(numbers)-1
while i<j:
m=(i+j)//2
if numbers[m]<numbers[j]: j=m
elif numbers[m]>numbers[j]: i=m+1
else: j-=1
return numbers[i]
面试题12 矩阵的路径
题目:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
解法:
深度优先搜索(DFS)+ 剪枝
- 递归参数: 当前元素在矩阵 board 中的行列索引 i 和 j ,当前目标字符在 word 中的索引 k 。
- 终止条件:
1.返回 falsefalse : ① 行或列索引越界 或 ② 当前矩阵元素与目标字符不同 或 ③ 当前矩阵元素已访问过 。
2.返回 truetrue : 字符串 word 已全部匹配,即 k = len(word) - 1 。 - 递推工作:
1.标记当前矩阵元素: 将 board[i][j] 值暂存于变量 tmp ,并修改为字符 ‘/’ ,代表此元素已访问过,防止之后搜索时重复访问。
2.搜索下一单元格: 朝当前元素的 上、下、左、右 四个方向开启下层递归,使用 或 连接 (代表只需一条可行路径) ,并记录结果至 res 。
3.还原当前矩阵元素: 将 tmp 暂存值还原至 board[i][j] 元素。 - 回溯返回值: 返回 res ,代表是否搜索到目标字符串。
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;
}
public boolean dfs(char[][] board,char[] words,int i,int j,int k){
if(i<0||i>board.length-1||j<0||j>board[0].length-1||words[k]!=board[i][j]) return false;
if(k==words.length-1) return true;
boolean res;
char tmp=board[i][j];
board[i][j]='/';
res=dfs(board,words,i+1,j,k+1)||dfs(board,words,i-1,j,k+1)|dfs(board,words,i,j+1,k+1)||dfs(board,words,i,j-1,k+1);
board[i][j]=tmp;
return res;
}
}
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
def dfs(i, j, k):
if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
if k == len(word) - 1: return True
tmp, board[i][j] = board[i][j], '/'
res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)
board[i][j] = tmp
return res
for i in range(len(board)):
for j in range(len(board[0])):
if dfs(i, j, 0): return True
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。请问该机器人能够到达多少个格子?
解法一:深度优先遍历
class Solution {
int n,m,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:
def movingCount(self, m: int, n: int, k: int) -> int:
深度优先遍历
def dfs(i,j,si,sj):
if i>=m or j>=n or k<si+sj or (i,j)in visited: return 0
visited.add((i,j))
return 1+dfs(i+1,j,si+1 if (i+1)%10 else si-8,sj)+dfs(i,j+1,si, sj+1 if (j+1)%10 else sj-8)
visited=set()
return dfs(0,0,0,0)
解法二:广度优先遍历
// 广度优先遍历
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;
}
}
# 广度优先遍历
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
queue,visited=[(0,0,0,0)],set()
while queue:
i,j,si,sj=queue.pop(0)
if i>=m or j>=n or k<si+sj or (i,j)in visited:
continue
visited.add((i,j))
queue.append((i+1,j,si+1 if (i+1)%10 else si-8,sj))
queue.append((i,j+1,si, sj+1 if(j+1)%10 else sj-8))
return len(visited)