LeetCode 36 | 37 | 39 | 40 | 46 | 47 . (回溯)

本文解析了多个经典的回溯算法题目,包括有效数独验证、数独求解、组合总和及其变化等,提供了详细的代码实现及思路分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于回溯,推荐一个视频:(斯坦福的关于回溯的现场教学三个例子,老师课堂手写代码)

https://www.youtube.com/watch?v=78t_yHuGg-0&t=741s&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk&index=18

https://www.youtube.com/watch?v=J_odcqzHGqw&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk&index=18

https://www.youtube.com/watch?v=5v6zdfkImms&index=19&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk

36Valid Sudoku

这道题是让你判断现有的数字是不是合法的,也就是说只需要去判断数字,不用去判断空的部分。(其实是数独解法的判断部分)

36题的解析:

9个数组来记录每行的重复情况,用数组下标来表示该数,比如 row[ 2 ] [ 3 ],表示第二行数字3的情况,如果 row[2][3] = 0,说明第三行已记录的没有3; 如果row[2][3] = 1,说明第三行已记录的已经有3,表示重复,直接return false就可以了。(注意下标,2应该是第三行,因为从0开始),为了对应的从0开始,所以数字也是要 board[ i ] [ j ] - '0' - 1

9个数组来计算每列的重复情况,参照上面。

9个数组来计算每隔cubic的重复情况,cubic的计算方法应该是:( i / 3 ) * 3 + ( j / 3 ), 如下图:


当然也可以不选用数组,用个哈希表就可以,哈希表的查找或者增加的操作可以用来判断是不是重复。

Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:

  1. Each row must contain the digits 1-9 without repetition.
  2. Each column must contain the digits 1-9 without repetition.
  3. Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.


A partially filled sudoku which is valid.

The Sudoku board could be partially filled, where empty cells are filled with the character '.'.

Example 1:

Input:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: true

Example 2:

Input:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being 
    modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.

Note:

  • A Sudoku board (partially filled) could be valid but is not necessarily solvable.
  • Only the filled cells need to be validated according to the mentioned rules.
  • The given board contain only digits 1-9 and the character '.'.
  • The given board size is always 9x9.

  bool isValidSudoku(vector<vector<char>>& board) {
        int row[9][9] = {0};  
        int col[9][9] = {0};
        int cubic[9][9] = {0};
        
        for(int i = 0; i < board.size(); i++){
            for(int j = 0; j < board.size(); j++){
                int num = board[i][j] - '0' -1;
                if(board[i][j] != '.'){
                    if(row[i][num] || col[j][num] || cubic[3 * (i/3) + j /3][num])
                        return false;
                    row[i][num] = col[j][num] = cubic[3 * (i/3) + j /3][num] = 1;
                   
                }
            }
        }
        return true;
    }

37Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.


A sudoku puzzle...


...and its solution numbers marked in red.

Note:

  • The given board contain only digits 1-9 and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9.

AC代码:

class Solution {
public:
    
    void solveSudoku(vector<vector<char>>& board) {
        solve(board);
    }
    
    bool solve(vector<vector<char> > & board){
        for(int i = 0; i < board.size(); i++){
            for(int j = 0;j < board.size(); j++){
                if(board[i][j] == '.'){
                    for(int k = '1'; k <= '9'; k++){
                        if(isValid(board,i,j,k)){
                            board[i][j] = k;
                            if (solve(board))
                                return true;
                            board[i][j] = '.';  //回撤
                        }
                    }
                    return false;   // 9 个数都不行就返回false
                }
            }
        }
        return true;  //最后成功的返回true
    }
    
    //只需要判断一行 一列 一个cubic
    bool isValid(vector<vector<char>>& board, int rowNum, int colNum, char num){

        for(int i = 0; i < 9; i++){
            if(board[rowNum][i] == num)  return false;   
            if(board[i][colNum] == num)  return false;
        }
        
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++)
                if( board[i + rowNum - rowNum%3][j + colNum - colNum%3] == num)
                    return false;
        }
        
        return true;
    }
};

39Combination Sum

Given a set of candidate numbers (candidates(without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Example 2:

Input: candidates = [2,3,5], target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

AC代码:

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        vector <vector <int> > res;
        vector<int> sol;
        search(candidates, 0, target, res, sol);
        return res;
    }
    
    void search(vector<int> & candidates, int begin, int target, vector<vector<int>> &res, vector<int> &sol){
        if(target == 0){
            res.push_back(sol);
            return;
        }
        for(int i = begin; i < candidates.size(); i++){
            if(target > 0){  
                sol.push_back(candidates[i]);
                search(candidates, i, target - candidates[i], res, sol);
                sol.pop_back();  //回溯
            }else   return;  //因为已经有序,后面的都不用再找了
        }
    }
};

40Combination Sum II

这道题就是把上一题稍微变一下,只加了两行,也就是:

对相同的 i 进行搜索的时候直接跳过就好,以防发生重复。

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]

AC代码:

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> res;
        sort(candidates.begin(), candidates.end());
        vector<int > sol;
        backTracking(candidates, 0, target, res, sol);
        return res;
    }
    
   void backTracking(vector<int> & candidates, int begin, int target, vector<vector<int>> &res, vector<int> & sol){
        if(target == 0){
            res.push_back(sol);
            return;
        }
        for(int i = begin; i < candidates.size(); i ++){
            if(candidates[i] <= target ){
                sol.push_back(candidates[i]);
                backTracking(candidates, i + 1, target - candidates[i], res, sol);
                sol.pop_back();
            }else
                return;
            while(candidates[i] == candidates[i+1])  //加了这两行,以防重复
                i++;
        }
    }
};

46Permutations

Given a collection of distinct integers, return all possible permutations.

Example:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

AC代码:

vector<vector<int>> permute(vector<int>& nums) {
        vector<vector <int> > res;
        vector<int> sol;
        backTracking(res, sol, nums);
        return res;
    }
    
    void backTracking(vector<vector<int> > &res, vector <int> & sol, vector<int> & nums){
        if(sol.size() >= nums.size()){
            res.push_back(sol);
            return;
        }
        for(int i = 0; i < nums.size(); i++){
            if(!Exist(sol, nums[i])){
                sol.push_back(nums[i]);
                //print(sol);
                backTracking(res, sol, nums);
                sol.pop_back();
            }
        }
    }
    /*
     *在C++的vector中,没有类似java的contains这个操作,所以要自己去判断一下
     */
    bool Exist(vector<int> & sol, int num){
        vector<int>:: iterator it = sol.begin();
        while(it != sol.end()){
            if(*it == num)  return true;
            it++;
        }
        return false;
    }

47Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector< vector<int> > res;
        if(nums.size() == 0)
            return res;
        sort(nums.begin(), nums.end());
        vector<int > sol;
        vector<bool> used(nums.size(), false);
        backTracking(res, sol, nums, used);
        return res;
    }
    
    void backTracking(vector<vector<int> > & res, vector<int> & sol, vector<int > & nums, vector<bool> & used){
        if(sol.size() == nums.size()){
            res.push_back(sol);
            return;
        }
        //choose => explore => unchoose
        int preNum = nums[0]-1;
        for(int i = 0; i < nums.size(); i++){
            if(used[i] || (nums[i] == preNum)) continue;
            preNum = nums[i];
            sol.push_back(nums[i]);
            used[i] = true;
            backTracking(res, sol, nums,used);
            sol.pop_back();
            used[i] = false;
        }
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值