剑指offer[11、12、13]

面试题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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值