阿里面试算法题合集二

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

注意这里求的是机器人走的范围,而不是路径,所以每走一个新的格都要加1

 boolean[][] vis; 
    int m , n , k;
    int max = 1;
    public int movingCount(int m, int n, int k) {
        vis = new boolean[m][n];
        this.m = m;
        this.n = n;
        this.k = k;
        dfs(0,0);
        return max;
    }

    int[][] next = {{0,1},{0,-1},{1,0},{-1,0}};
    public void dfs(int x, int y){
        vis[x][y] = true;
        for(int i=0;i<4;i++){
            int xx = x + next[i][0];
            int yy = y + next[i][1];
            int x_1 = xx / 10;
            int x_0 = xx % 10;
            int y_1 = yy / 10;
            int y_0 = yy % 10;
            if(xx < 0 || xx >=m || yy < 0 || yy >= n || 
            x_0 + x_1 + y_0 + y_1 > k){
                continue;
            }
            if(!vis[xx][yy]){
                dfs(xx,yy);
                max++;
            }
        }
    }

从(0,0) 统计所有访问的点,可以同时进行dfs两个方向,避免已经访问过的点,从上向下进行dfs

boolean[][] vis; 
    int m , n , k;
    // 这道题可以简化为,调用dfs,同时想两个方向进行dfs i+1, j+1
    public int movingCount(int m, int n, int k) {
        vis = new boolean[m][n];
        this.m = m;
        this.n = n;
        this.k = k;
        return dfs(0,0,0,0);
    }

    public int dfs(int x, int y, int s1, int s2){
        if(x >=m || y >= n || s1 + s2 > k || vis[x][y]){
            return 0;
        }
        vis[x][y] = true;
        return 1 + dfs(x+1,y, (x+1) % 10 + (x + 1)/10, s2) + dfs(x,y+1,s1, (y+1)/10 + (y+1)%10);
    }

79.单词搜索

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例:

board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]

给定 word = "ABCCED", 返回 true

 // 采用回溯,
    boolean[][] vis;
    int m,n;
    char[][] board;
    public boolean exist(char[][] board, String word) {
        this.m = board.length;
        this.n = board[0].length;
        this.board = board;
        for(int i=0;i= word.length()){
            return true;
        }
        for(int i=0;i<4;i++){
            int xx = x + next[i][0];
            int yy = y + next[i][1];
            if(xx < 0 || xx >= m || yy < 0 || yy >= n || vis[xx][yy] || word.charAt(k)
        != board[xx][yy]){
                continue;
            }
            vis[xx][yy] = true;
            boolean flag = dfs(word,xx,yy,k+1);
            if(flag){
                return true;
            }
            //这里必须回溯,实质上还是走路径的问题
            vis[xx][yy] = false;
        }
        return false;
    }

38. 分割回文串

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

示例:

输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]

 // 采用回溯, s.substring(i) s.substring(i,len), 如果分割的两个正好都是回文添加结果集,否则递归
    public List> partition(String s) {
        List> res = new ArrayList<>();
        if(s == null || s.length() == 0){
            return res;
        }
        backTrack(0,s,new LinkedList(),res);
        return res;
    }

    public void backTrack(int j,String s,LinkedList list,List>  res){
        
        if(j == s.length()){
            res.add(new ArrayList<>(list));
            return;
        }
        for(int i=j;i

47. 全排列2

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

数组中有相同的数,可以使用canSwap 进行判断是否相同

List> res = new ArrayList<>();
    public List> permuteUnique(int[] nums) {
        if(nums == null || nums.length == 0){
            return res;
        }
        permutition(nums,0);
        return res;
    }

    public void permutition(int[] nums, int cur){
        if(cur == nums.length){
            List list = new ArrayList<>();
            for(int i=0;i

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

// 没有重复数的全排列
    List> res = new ArrayList<>();
    public List> permute(int[] nums) {
        if(nums == null || nums.length == 0){
            return res;
        }
        permutition(nums,0);
        return res;
    }

    public void permutition(int[] nums, int cur){
        if(cur == nums.length){
            List list = new ArrayList<>();
            for(int x: nums){
                list.add(x);
            }
            res.add(list);
            return;
        }else{
            for(int i=cur;i

39. 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]

 List> res = new ArrayList<>();
    public List> combinationSum(int[] candidates, int target) {
        if(candidates == null || candidates.length == 0){
            return res;
        }
        Arrays.sort(candidates);
        combination(candidates,target,0,new Stack());
        return res;
    }

    public void combination(int[] num,int target, int cur, Stack stack){
        if(target == 0){
            res.add(new ArrayList<>(stack));
            return;
        }
        for(int i=cur;i= 0;i++){
            stack.add(num[i]);
            // 这里传i, 数组里面的数可以重复使用
            combination(num,target-num[i],i,stack);
            stack.pop();
        }
    }

40. 组合总和2

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

// 数组中有重复的数,和排列一样进行筛选
    List> res = new ArrayList<>();
    public List> combinationSum2(int[] candidates, int target) {
        if(candidates == null || candidates.length == 0){
            return res;
        }
        Arrays.sort(candidates);
        combination(0,candidates,target,new LinkedList());
        return res;
    }

    public void combination(int cur, int[] candidates, int target, LinkedList list ){
        if(target == 0){
            res.add(new ArrayList<>(list));
            return;
        }

        for(int i=cur;i=0 ; i++){
            if(check(candidates,cur,i)){
                list.add(candidates[i]);
                // 这里 i + 1 是数组里面的数不可以重复使用 combination(i+1,candidates,target-candidates[i],list);
                list.removeLast();
            }
        }

    }

    public boolean check(int[] nums, int cur, int end){
        for(int i=cur;i

90. 子集2

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

 Set> set = new HashSet<>();
    public List> subsetsWithDup(int[] nums) {
        List> res = new ArrayList<>();
        if(nums == null || nums.length == 0){
            return res;
        }
        Arrays.sort(nums);
        int len = nums.length;
        int max = 1 << len;
        for(int i=0;i list = new ArrayList<>();
            for(int j=0;j> j) & 1) == 1){
                    list.add(nums[j]);
                }
            }
            set.add(list);
        }
        for(List l : set){
            res.add(l);
        }
        return res;
    }

/// 子集

 List> res = new ArrayList<>();
    public List> subsetsWithDup(int[] nums) {
        if(nums == null || nums.length == 0){
            return res;
        }
        Arrays.sort(nums);
        subsets(0,nums,new LinkedList());
        return res;
    }

    public void subsets(int cur, int[] nums, LinkedList list){
        res.add(new ArrayList<>(list));
        for(int i=cur;i cur && nums[i] == nums[i-1]){
                continue;
            }
            list.add(nums[i]);
            subsets(i+1,nums,list);
            list.removeLast();
        }
    }

78. 子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

 public List> subsets(int[] nums) {
        List> res = new ArrayList<>();
        if(nums == null || nums.length == 0){
            return res;
        }
        int len = nums.length;
        int max = 1 << len;
        for(int i=0;i list = new ArrayList<>();
            for(int j=0;j> j) & 1) == 1){
                    list.add(nums[j]);
                }
            }
            res.add(list);
        }
        return res;
    }

子集就是组合

 List> res = new ArrayList<>();
    public List> subsets(int[] nums) {
        if(nums == null || nums.length == 0){
            return res;
        }
        subsets(0,nums,new LinkedList());
        return res;
    }

    public void subsets(int cur, int[] nums, LinkedList list){
        res.add(new ArrayList<>(list));
        for(int i = cur;i

494. 目标和

给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例:

输入:nums: [1, 1, 1, 1, 1], S: 3
输出:5

int count = 0;
    public int findTargetSumWays(int[] nums, int S) {
        findTarget(0,nums,S,0);
        return count;
    }

    public void findTarget(int cur, int[] nums, int S,int sum){
        if(cur == nums.length){
            if(sum == S)
            count++;
            return;
        }
        findTarget(cur+1,nums,S, sum-nums[cur]);
        findTarget(cur+1,nums,S, sum+nums[cur]);
    }

你可能感兴趣的:(阿里面试算法题合集二)