tags:


1. BackTracking #

Created Monday 22 June 2020

What is backtracking #

e.g There are 10 bags with some items. Print the name on the bag if a ball exists in the bag.

General backtracking algorithm (DFS tree) #

Backtracking constructs a tree of partial decisions, where each node represents a partial decision, and leaves represent valid/invalid decisions.

This means backtracking is a DFS traveral.

Note:

Backtrack maid #

  1. We Consider all possibilities.
  2. We traverse instead of storing.
  3. Define a decision space (array of bools/integers etc). It should be linear fixed size.
  4. We maintain read/write mapping between decision space and app’s data structure. Linear (array) is the simplest to advance and backtrack.
  5. On each decision position, generate valid possibilities.
  6. Since decision space is shared, we have to do forward (write) and backward (reset) operations for each candidate decision, so the next candidate is unhindered.
  7. Backtracking enumerates all possible decision sequences. Cycles are avoided because each path is uniquely represented by its decisions.

Note (non trivial):

Common backtracking problems #

The common thing in all backtracking problems is the “decision you make”.

  1. All subsets - decision is a boolean array of size “alphabet-size”.
  2. All permutations - decision is a int array of size “alphabet-size”.
  3. All paths from source to target in a graph - decision is a int array of size V.

Note:

Subsets #

class Solution {
public:
    vector<vector<int>> helper(vector<int>& nums, vector<bool>& decisions,
                               int start) {
        // act if decision actionable
        if (start == nums.size()) {
            // now take the elements and return
            vector<int> retval;
            for (int i = 0; i < nums.size(); i++) {
                if (decisions[i]) {
                    retval.push_back(nums[i]);
                }
            }
            return {retval};
        }

        // intermediate (decision not ready)
        // generate next steps
        vector<bool> candidates{false, true};
        vector<vector<int>> retval;

        for (auto candidate : candidates) {
            bool temp = decisions[start]; // store for cancellation
            decisions[start] = candidate; // make move
            auto outputs = helper(nums, decisions, start + 1); // go down
            for (auto output : outputs) {
                retval.push_back(output);
            }
            decisions[start] = temp; // cancel move (backtrack)
        }

        return retval; // all outputs
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        vector<bool> decisions(nums.size(), false);
        return helper(nums, decisions, 0);
    }
};

Permuations #

class Solution {
public:
    vector<vector<int>> helper(vector<int>& nums, vector<int>& decisions, int start) {
        // CHATGPT-COMMENT-HERE
        /*
            pruning logic would come here, if we think the current decision won't lead to useful ones
            we'll return here itself
        */
        if (start == nums.size()) 
        // CHATGPT-COMMENT-HERE if the problem allows, explicit deduplication would go in here
        return {decisions};

        vector<vector<int>> retval;
        // candidates (choose the next one from one of the existing), by replacement
        for (int i = start; i < nums.size(); i++) {
            // select the current element as the start
            int curr = decisions[start];
            int replacer = decisions[i];

            // swap
            decisions[start] = replacer;
            decisions[i] = curr;

            auto outputs = helper(nums, decisions, start + 1);
            for(auto output: outputs) {
                retval.push_back(output);
            }

            // reverse
            decisions[start] = curr;
            decisions[i] = replacer;
        }

        return retval;
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<int> decisions (nums.begin(), nums.end()); // deliberate
        return helper(nums, decisions, 0);
    }
};