Interview Hot Questions: Combination Combination and Combination Sum of Backtracking Algorithms III

What is Backtracking Algorithm?

The backtracking algorithm can also be called the backtracking search algorithm. Backtracking is a "by-product" of recursion. The essence of backtracking is exhaustive , and then select the data we need. Backtracking itself is not a particularly efficient algorithm, but we can optimize it by "pruning" it.

Understand Backtracking Algorithms

The solution of the backtracking algorithm can simulate a tree structure , because the backtracking method solves the process of recursively searching for subsets in the set , the size of the set constitutes the width of the tree, and the depth of the recursion constitutes the depth of the tree .

Backtracking Algorithm Template

  1. Determine the return value and parameters of the backtracking algorithm (generally write the logic first, and then add any parameters needed)
  2. Determine the termination condition of the backtracking function
  3. Determine the traversal process of the backtracking search
void BackTracking(参数)
{
    
    
	if (终止条件)
	{
    
    
		处理结果
		return;
	}
	for (选择:本层集合中的元素(树中节点孩子的数量就是集合的大小))
	{
    
    
		处理节点
		BackTracking(路径,选择列表);//递归
		回溯,撤销处理结果
	}
}

combination

Problem:
Given two integers n and k, return all possible combinations of k numbers in the range [1, n].
You can return answers in any order.
Source: LeetCode Portfolio

insert image description here
Idea 1: For this kind of problem, we can think of it at a glance by using a for loop to cover the loop, such as when k==2

	int n = 4;
	for (int i = 1; i <= n; i++)
	{
    
    
		for (int j = i + 1; j <= n; j++)
		{
    
    
			//处理结果
		}
	}

But if k gets bigger and bigger, we will apply more and more cycles. This violent solution is undoubtedly unrealistic.

Idea 2: As we said before, the tree structure can be used to simulate the process of backtracking and recursion:
for example, the initial set of n=4 k=2
insert image description here
trees is [1,2,3,4], taken from left to right, taken The passed number is no longer taken, and each time an element is selected from the collection, the range of options is gradually narrowed. It can be found from the figure that n is equivalent to the width of the tree, and k is equivalent to the depth of the tree. Let's use the template to write the final code:

class Solution {
    
    
public:
    vector<vector<int>> arr;//存放符合条件的集合
    vector<int> _arr;//用来存放符合条件的单一数据
    void BackTracking(int n, int k, int begin)
    {
    
    
        if (_arr.size() == k)//递归终止条件
        {
    
    
            arr.push_back(_arr);//单一数据存放至总集合里
            return;
        }
        for (int i = begin; i <= n; i++)//控制树的横向遍历
        {
    
    
            _arr.push_back(i);//处理节点
            BackTracking(n, k, i + 1);//递归,控制树的纵向遍历,即深度
            _arr.pop_back();//回溯,撤销处理的节点
        }
    }
    vector<vector<int>> combine(int n, int k) {
    
    
        BackTracking(n, k, 1);
        return arr;
    }
};

pruning optimization

If the following situation occurs:
n=4 k=4
, then in the first layer of for loop, the traversal starting from element 2 is meaningless, because the number satisfying k is not enough, so it can be seen from the figure that the crossed place can be optimized Drop
insert image description here
the optimization process:

  1. The number of selected elements: _arr.size()
  2. Number of elements still needed: k - _arr.size()

Optimized code:

class Solution {
    
    
public:
    vector<int> _arr;
    vector<vector<int>> arr;
    void BackTracking(int n, int k, int begin)
    {
    
    
        if (_arr.size() == k)
        {
    
    
            arr.push_back(_arr);
            return;
        }
        for (int i = begin; i <= n-(k-_arr.size())+1; i++)//剪枝优化
        {
    
    
            _arr.push_back(i);
            BackTracking(n, k, i + 1);
            _arr.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
    
    
        BackTracking(n, k, 1);
        return arr;
    }
};

Portfolio Sum III

Question:
Find all combinations of k numbers whose sum is n, and satisfy the following conditions:

  • Only use numbers 1 to 9
  • Use each number at most once

Returns a list of all possible valid combinations. The list cannot contain the same combination twice, and the combinations may be returned in any order.
Source: LeetCode Portfolio Sum III

insert image description here

Idea: Compared with the previous question, this question is that k is the depth of the tree, and the set is fixed from 1 to 9, that is, the width of the tree is 9. For example:
k=2 only takes two numbers
insert image description here
Code:

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;
    void BackTracking(int k,int n,int begin,int sum)
    {
    
    
        if(_arr.size()==k)//终止条件
        {
    
    
            if(sum==n)//满足题意
            {
    
    
                arr.push_back(_arr);
            }
            return;
        }
        for(int i=begin;i<=9;i++)//横向遍历
        {
    
    
            sum+=i;//收集元素总和
            _arr.push_back(i);//收集元素
            BackTracking(k,n,i+1,sum);//递归,纵向遍历
            sum-=i;//回溯
            _arr.pop_back();//回溯
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
    
    
        BackTracking(k,n,1,0);
        return arr;
    }
};

pruning optimization

If the sum of the elements we select is already greater than n, then the sum we traverse later must also be greater than n, and there is no point in continuing to traverse. In terms of the number of elements, it can continue to be optimized as in the previous question.
insert image description here
Optimized:

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;
    void BackTracking(int k,int n,int begin,int sum)
    {
    
    
        if(sum>n)//剪枝条件
        {
    
    
            return;
        }
        if(_arr.size()==k)
        {
    
    
            if(sum==n)
            {
    
    
                arr.push_back(_arr);
            }
            return;
        }
        for(int i=begin;i<=9-(k-_arr.size())+1;i++)//元素个数的优化
        {
    
    
            sum+=i;
            _arr.push_back(i);
            BackTracking(k,n,i+1,sum);
            sum-=i;
            _arr.pop_back();
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
    
    
        BackTracking(k,n,1,0);
        return arr;
    }
};

Guess you like

Origin blog.csdn.net/DEXTERFUTIAN/article/details/129445750