Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Backtracking Solutions for Combination Sum and Palindrome Partitioning

Notes May 9 3

Combination Sum

Given a collection of distinct integers and a target value, identify all unique combinations where the chosen numbers sum to the target. Each candidate may be used an unlimited number of times.

The solution employs depth-first search with backtracking. First, sort the input array to facilitate pruning. During traversal, maintain a running remainder of the target. If the remainder reaches zero, the current combination is valid. Iterate from the current positino, recursively exploring each candidate while updating the remainder.

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& nums, int target) {
        vector<vector<int>> combinations;
        vector<int> current;
        sort(nums.begin(), nums.end());
        dfs(nums, target, 0, current, combinations);
        return combinations;
    }

private:
    void dfs(vector<int>& nums, int remain, int pos, vector<int>& current, vector<vector<int>>& combinations) {
        if (remain == 0) {
            combinations.push_back(current);
            return;
        }
        for (int i = pos; i < nums.size() && nums[i] <= remain; ++i) {
            current.push_back(nums[i]);
            dfs(nums, remain - nums[i], i, current, combinations);
            current.pop_back();
        }
    }
};

Combination Sum II

Given a collection of integers that may contain duplicates and a target value, find all unique combinations where the chosen numbers sum to the target. Each number may only be used once in each combination.

After sorting the array, traverse using backtracking. To avoid duplicate combinations, skip elements that are identical to the previous element at the same recursion level. This ensures that duplicate values are only considered in subsequent tree branches, not within the same branch level.

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& nums, int target) {
        vector<vector<int>> combinations;
        vector<int> current;
        sort(nums.begin(), nums.end());
        backtrack(nums, target, 0, current, combinations);
        return combinations;
    }

private:
    void backtrack(vector<int>& nums, int remain, int start, vector<int>& current, vector<vector<int>>& combinations) {
        if (remain == 0) {
            combinations.push_back(current);
            return;
        }
        for (int i = start; i < nums.size() && nums[i] <= remain; ++i) {
            if (i > start && nums[i] == nums[i - 1]) continue;
            current.push_back(nums[i]);
            backtrack(nums, remain - nums[i], i + 1, current, combinations);
            current.pop_back();
        }
    }
};

Palindrome Partitioning

Given a string, partition it such that every substring of the partition is a palindrome. Return all possible palindrome partitioning schemes.

The approach treats the partitioning as a tree traversal problem. Starting from each position, expand to find all palindromic substrings beginning at that index. For each valid palindrome found, add it to the current partition and recursively process the remainder of the string.

class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> solutions;
        vector<string> segments;
        backtrack(s, 0, segments, solutions);
        return solutions;
    }

private:
    void backtrack(const string& s, int begin, vector<string>& segments, vector<vector<string>>& solutions) {
        if (begin == s.size()) {
            solutions.push_back(segments);
            return;
        }
        for (int end = begin; end < s.size(); ++end) {
            if (isPalindrome(s, begin, end)) {
                segments.push_back(s.substr(begin, end - begin + 1));
                backtrack(s, end + 1, segments, solutions);
                segments.pop_back();
            }
        }
    }

    bool isPalindrome(const string& s, int left, int right) {
        while (left < right) {
            if (s[left++] != s[right--]) return false;
        }
        return true;
    }
};

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.