【每日三题】2022-4-3 LeetCode 37-39

37.解数独

思路:回溯法。首先遍历数组,保存其中已有的数字信息,这些是不可变的。同时记录需要填写的格子。之后每次从需要填写的格子中拿出一个,尝试填写与现有其他格子不冲突的数字,更新状态,并递归尝试填写下一个格子。当所有格子填写完成时,则找到解。若填写下一个格子时,所有数字均冲突,则说明当前格子填写当前值时无解,继续寻找下一个可能的解。

代码:

private boolean[][] rows = new boolean[9][9];
private boolean[][] cols = new boolean[9][9];
private boolean[][][] boxes = new boolean[3][3][9];
private List<int[]> empty = new ArrayList<>();

public void solveSudoku(char[][] board) {
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (board[i][j] == '.') {
                empty.add(new int[]{i, j});
            } else {
                rows[i][board[i][j] - '1'] = true;
                cols[board[i][j] - '1'][j] = true;
                boxes[i / 3][j / 3][board[i][j] - '1'] = true;
            }
        }
    }
    solve(board, 0);
}

private boolean solve(char[][] board, int index) {
    if (index == empty.size()) {
        return true;
    }
    int currentX = empty.get(index)[0], currentY = empty.get(index)[1];
    for (int temp = 0; temp < 9; temp++) {
        if (!rows[currentX][temp] && !cols[temp][currentY] && !boxes[currentX / 3][currentY / 3][temp]) {
            board[currentX][currentY] = (char)('1' + temp);
            rows[currentX][temp] = true;
            cols[temp][currentY] = true;
            boxes[currentX / 3][currentY / 3][temp] = true;
            if (solve(board, index + 1)) {
                return true;
            }
            board[currentX][currentY] = '.';
            rows[currentX][temp] = false;
            cols[temp][currentY] = false;
            boxes[currentX / 3][currentY / 3][temp] = false;
        }
    }
    return false;
}

时间复杂度:O(9n),其中n为数独中空格子的数量

空间复杂度:O(n)

38.外观数列

思路:递归求解。

代码:

public String countAndSay(int n) {
    if (n == 1) {
        return "1";
    }
    String last = countAndSay(n-1);
    StringBuilder sb = new StringBuilder();
    char c = last.charAt(0);
    int count = 1;
    for (int i = 1; i < last.length(); i++) {
        if (last.charAt(i) == c) {
            count ++;
        } else {
            sb.append(count);
            sb.append(c);
            c = last.charAt(i);
            count = 1;
        }
    }
    sb.append(count);
    sb.append(c);
    return sb.toString();
}

时间复杂度:O(n*m),m为1~n中最长外观数列字符串的长度

空间复杂度:O(m)

39.组合总和

思路:回溯法。从index=0开始,考虑放入有可能的个数个candidates[index],然后推进条件。target = 0时,找到一个组合,放入结果中并返回。当index = candidates.length时,说明后续无解,返回。

代码:

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> current = new ArrayList<>();
    combinationSum(candidates, 0, target, res, current);
    return res;
}

private void combinationSum(int[] candidates, int start, int target, List<List<Integer>> res, List<Integer> current) {
    if (target == 0) {
        res.add(new ArrayList<>(current));
        return;
    }
    if (start == candidates.length) {
        return;
    }
    combinationSum(candidates, start + 1, target, res, current);
    int max = target / candidates[start];
    for (int i = 0; i < max; i++) {
        for (int j = 0; j < i + 1; j++) {
            current.add(candidates[start]);
        }
        combinationSum(candidates, start + 1, target - (i + 1) * candidates[start], res, current);
        for (int j = 0; j < i + 1; j++) {
            current.remove(current.size() - 1);
        }
    }
}

时间复杂度:O(S),其中S为所有可行解的元素个数之和

空间复杂度:O(target)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值