当前位置:   article > 正文

每日5题Day8 - LeetCode 36 - 40

每日5题Day8 - LeetCode 36 - 40

每一步向前都是向自己的梦想更近一步,坚持不懈,勇往直前!

第一题:36. 有效的数独 - 力扣(LeetCode)

题目要求我们进行判断,我们不需要自己填写,所以要一个标志位,来看当前的值是否在行、列、格中出现过,每当这时候可以考虑使用位掩码。

  1. class Solution {
  2. public boolean isValidSudoku(char[][] board) {
  3. int[] line = new int[9];// 行
  4. int[] col = new int[9];// 列
  5. int[] cell = new int[9];// 9宫格
  6. for (int i = 0; i < 9; i++) {
  7. for (int j = 0; j < 9; j++) {
  8. // 如果当前位置没有数字,不用判断。
  9. if (board[i][j] == '.')
  10. continue;
  11. //使用位掩码来记录数字
  12. int shift = 1 << (board[i][j] - '0');// 确定第几位
  13. int k = (i / 3) * 3 + j / 3;// 9宫格的第几个。
  14. // 如果对应的位置只要有一个被标记过,说明有冲突,直接返回false。
  15. //&与要求两边完全相同才大于0,下面这一步在判断是否有相同数字出现过
  16. if ((col[i] & shift) > 0 || (line[j] & shift) > 0
  17. || (cell[k] & shift) > 0)
  18. return false;
  19. // 把当前位置所在的行,列以及9宫格都标记为该数字已经存在。
  20. //或|只要某一位是1,则都是1,所以不管原来的col[i]等是否为0,
  21. //反正判断的时候还是判断col[i] & shift,所以下面这样写正确
  22. //建议自己手动模拟一下
  23. col[i] |= shift;
  24. line[j] |= shift;
  25. cell[k] |= shift;
  26. }
  27. }
  28. return true;
  29. }
  30. }

第二题:37. 解数独 - 力扣(LeetCode)

  1. class Solution {
  2. //类似于dfs,要找到刚好唯一一组解,可能会涉及到已经放入的值回退的情况
  3. //直接使用空间换时间了,不回退直接判断可不可以放,注意看两层循环那个
  4. //if-for-return的逻辑:如果是'.' 那么能不能放数字,如果放了就继续,否则return false
  5. //再注意看for循环里的逻辑,判断这个数字放进去满足数独不,所以有一个isValidSudoku的判断函数
  6. public void solveSudoku(char[][] board) {
  7. solveSudokuHelper(board);
  8. }
  9. private boolean solveSudokuHelper(char[][] board){
  10. for (int i = 0; i < 9; i++){ // 遍历行
  11. for (int j = 0; j < 9; j++){ // 遍历列
  12. if (board[i][j] != '.'){ // 跳过原始数字
  13. continue;
  14. }
  15. for (char k = '1'; k <= '9'; k++){ // (i, j) 这个位置放k是否合适
  16. if (isValidSudoku(i, j, k, board)){
  17. board[i][j] = k;
  18. if (solveSudokuHelper(board)){ // 如果找到合适一组立刻返回
  19. //注意这个地方的判断,潜逃了两层true的判断
  20. return true;
  21. }
  22. board[i][j] = '.';
  23. }
  24. }
  25. return false;
  26. }
  27. }
  28. return true;
  29. }
  30. private boolean isValidSudoku(int row, int col, char val, char[][] board){
  31. //分别判断行列格里是否存在相同元素
  32. for (int i = 0; i < 9; i++){
  33. if (board[row][i] == val){
  34. return false;
  35. }
  36. }
  37. for (int j = 0; j < 9; j++){
  38. if (board[j][col] == val){
  39. return false;
  40. }
  41. }
  42. int startRow = (row / 3) * 3;
  43. int startCol = (col / 3) * 3;
  44. for (int i = startRow; i < startRow + 3; i++){
  45. for (int j = startCol; j < startCol + 3; j++){
  46. if (board[i][j] == val){
  47. return false;
  48. }
  49. }
  50. }
  51. return true;
  52. }
  53. }

第三题:38. 外观数列 - 力扣(LeetCode)

  1. public class Solution {
  2. // countAndSay 方法用于生成一个特定的字符串序列。
  3. // 序列的第 n 项是通过将第 n-1 项字符串中的连续相同字符进行计数和描述来生成的。
  4. public static String countAndSay(int n) {
  5. // 递归出口:如果 n 为 1,则返回字符串 "1",这是序列的第一项。
  6. if (n == 1) {
  7. return "1";
  8. }
  9. // 递归调用:如果 n 大于 1,则先递归调用 countAndSay(n - 1) 生成第 n-1 项,
  10. // 然后调用 transfer 方法将第 n-1 项转换为第 n 项。
  11. return transfer(countAndSay(n - 1));
  12. }
  13. // transfer 方法接受一个字符串 s 作为输入,并生成下一个字符串。
  14. // 它通过计数 s 中连续出现的相同字符,并将计数和字符拼接起来形成新的字符串。
  15. public static String transfer(String s) {
  16. StringBuilder sb = new StringBuilder(); // 使用 StringBuilder 来构建最终的字符串。
  17. int count = 1; // 初始化计数器,用于计数连续相同字符的数量。
  18. int length = s.length(); // 获取输入字符串的长度。
  19. int i;
  20. char temp = s.charAt(0); // 初始化临时变量 temp 为字符串的第一个字符。
  21. // 遍历输入字符串 s。
  22. for (i = 1; i <= length; i++) {
  23. // 如果当前字符 temp 与 s.charAt(i) 相同,继续计数。
  24. while (i < length && temp == s.charAt(i)) {
  25. count++; // 连续字符计数加 1。
  26. i++; // 移动到下一个字符。
  27. }
  28. // 如果 i < length,说明找到了不同的字符,更新 temp。
  29. if (i < length) {
  30. temp = s.charAt(i);
  31. }
  32. // 将当前字符的计数和字符本身添加到 StringBuilder 中。
  33. sb.append(count); // 添加计数。
  34. sb.append(s.charAt(i - 1)); // 添加字符本身。
  35. // 重置计数器,为下一个字符的计数做准备。
  36. count = 1;
  37. }
  38. // 返回构建好的字符串。
  39. return sb.toString();
  40. }
  41. }

第四题:39. 组合总和 - 力扣(LeetCode)

  1. class Solution {
  2. List<List<Integer>> res = new ArrayList<>();
  3. List<Integer> path = new ArrayList<>();
  4. public List<List<Integer>> combinationSum(int[] candidates, int target) {
  5. //为了避免排列的重复情况出现,所以我们先进行排序
  6. Arrays.sort(candidates);
  7. traversal(0, target, candidates);
  8. return res;
  9. }
  10. private void traversal(int start, int target, int[] candidates){
  11. //把满足条件的提出来
  12. if(target == 0){
  13. res.add(new ArrayList<>(path));
  14. return;
  15. }
  16. for(int i = start; i < candidates.length; i++){
  17. //对于每一个candidate进行遍历,因为我们升序排列了,所以一旦选过了,
  18. //就不会再回去,就避免了排列情况的发生,实际上变为了组合
  19. if(target - candidates[i] >= 0){
  20. path.add(candidates[i]);
  21. traversal(i, target - candidates[i], candidates);
  22. //记得回溯
  23. path.remove(path.size() - 1);
  24. }else{
  25. //注意给一个边界条件,如果不满足了就退出
  26. break;
  27. }
  28. }
  29. }
  30. }

 第五题:40. 组合总和 II - 力扣(LeetCode)

  1. class Solution {
  2. public List<List<Integer>> combinationSum2(int[] candidates, int target) {
  3. Arrays.sort(candidates); // 对数组进行排序
  4. List<List<Integer>> res = new ArrayList<>();
  5. //因为每个候选人数字只能出现一次,所以我们与上一题不同的地方是要多加入一个标记数组
  6. backtrack(candidates, target, 0, new ArrayList<>(), res, new boolean[candidates.length]);
  7. return res;
  8. }
  9. private void backtrack(int[] candidates, int target, int start, List<Integer> path, List<List<Integer>> res, boolean[] used) {
  10. if (target == 0) {
  11. res.add(new ArrayList<>(path)); // 找到一种组合
  12. return;
  13. }
  14. for (int i = start; i < candidates.length; i++) {
  15. // 本质来说,这题有重复元素的排列导致的结果重复的问题,必须去重
  16. // 跳过重复的元素,注意这种去重的方式(避免上一行提到的情况)
  17. if (i > start && candidates[i] == candidates[i - 1]) {
  18. continue;
  19. }
  20. // 如果当前元素大于剩余目标,直接返回
  21. //注意边界条件
  22. if (candidates[i] > target) {
  23. break;
  24. }
  25. // 使用当前元素
  26. if (!used[i]) {
  27. used[i] = true; // 标记为已使用
  28. path.add(candidates[i]); // 添加到路径
  29. backtrack(candidates, target - candidates[i], i + 1, path, res, used); // 递归调用
  30. path.remove(path.size() - 1); // 回溯,移除当前元素
  31. used[i] = false; // 重置为未使用
  32. }
  33. }
  34. }
  35. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/615494
推荐阅读
相关标签
  

闽ICP备14008679号