码迷,mamicode.com
首页 > 编程语言 > 详细

[算法专题] 深度优先搜索&回溯剪枝

时间:2015-08-07 23:31:16      阅读:183      评论:0      收藏:0      [点我收藏+]

标签:

1. Palindrome Partitioning

https://leetcode.com/problems/palindrome-partitioning/

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

For example, given s = "aab",
Return

  [
    ["aa","b"],
    ["a","a","b"]
  ]
/**
 * author : Jianxin Zhou
 * email:zhoujx0219@163.com
 * 
 * 该题dfs函数原型如下:
 * void partitionHelper(const string &s, vector<vector<string>> &result, vector<string> &path, int pos)
 * 
 * 以aaba举例。
 * 1. 首先a为回文,然后对aba进行dfs
 * 2. 之后回溯到a时,以aa为回文,然后对ba做dfs
 * 3. 回溯到aa,试图以aab为回文,失败;试图以aaba为回文失败;结束。
 * 
 * 注意:如果能顺利的找到一组回文,那么pos最终会等于s.size(),此时可以push到result。
 *       如果找不到,例如之前的aaba不是回文,那么就会直接退出循环,没有机会执行下一步递归,也就没有pos等于s.size了。
 * 
 * 实际上,此类题与真正的dfs的差别在于,dfs在回溯时,不会进行剪枝操作。而此类题,由于需要求出所有方案,所以需要剪枝。
 *
 */


class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> result;
        vector<string> path;
        partitionHelper(s, result, path, 0);
        return result;
    }
    
private:
    void partitionHelper(const string &s, vector<vector<string>> &result, vector<string> &path, int pos) {
        // base case
        if (pos == s.size()) {
            result.push_back(path);
            return;
        }
        
        for (int i = pos; i < s.size(); i++) {
            if (isPalindrome(s, pos, i)) {
                path.push_back(s.substr(pos, i - pos + 1));
                partitionHelper(s, result, path, i + 1);
                path.pop_back();
            }
        }
    }
    
    bool isPalindrome(const string &s, int start, int end) {
        while (start < end) {
            if (s[start] == s[end]) {
                start++;
                end--;
            } else {
                break;
            }
        }
        
        return start >= end;
    }
};

2. Permutations

https://leetcode.com/problems/permutations/

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].

具体可参加我之前写的文章:[LintCode] Permutations

/**
 * 思路:dfs。
 * 
 * 以123举例,
 * 1. 首先以1作为head,然后对23做dfs
 * 2. 回溯到1, 以2作为head,对13做dfs
 * 3. 最后回溯到2,以3作为head,对12做dfs
 * 
 * 注意:例如以2为head,对其余元素做dfs时,那么2不能再取,因此在进行下一轮dfs时,需要标记2为以访问过
 * 
 */


class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> path;
        
        bool visited[nums.size()];
        for(int i = 0; i < nums.size(); i++) {
            visited[i] = false;
        }
        
        sort(nums.begin(), nums.end());
        dfs(nums, result, path, visited);
        return result;
    }
    
private:
    void dfs(const vector<int> &nums, vector<vector<int>> &result, vector<int> &path, bool visited[]) {
        // base case
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }

        for (int i = 0; i < nums.size(); i++) {
            if (visited[i] == false) {
                path.push_back(nums[i]);
                visited[i] = true;
                dfs(nums, result, path, visited);
                path.pop_back();
                visited[i] = false;
            }
            
        }
    }
};

3. Permutations II

https://leetcode.com/problems/permutations-ii/

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

For example,
[1,1,2] have the following unique permutations:
[1,1,2], [1,2,1], and [2,1,1].

要点在于保证相同的数不在同一位置出现两次以上,可以参见我写的这篇文章:[LintCode] Permutations II

class Solution {
public:
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    vector<vector<int> > permuteUnique(vector<int> &nums) {
        // write your code here
        vector<vector<int>> paths;
        if (nums.empty()) {
            return paths;
        }
         
        sort(nums.begin(), nums.end());
        bool *visited = new bool[nums.size()]();
        vector<int> path;
        permuteUniqueHelper(nums, visited, path, paths);
        return paths;
    }
     
private:
    void permuteUniqueHelper(const vector<int> &nums,
                             bool visited[],
                             vector<int> &path,
                             vector<vector<int>> &paths) {
        if (path.size() == nums.size()) {
            paths.push_back(path);
            return;
        } 
         
        for (int ix = 0; ix < nums.size(); ix++) {
            if (visited[ix] == true || ix > 0 && nums[ix - 1] == nums[ix] && visited[ix - 1] == false) {
                continue;    
            }
             
            visited[ix] = true;
            path.push_back(nums[ix]);
            permuteUniqueHelper(nums, visited, path, paths);
            visited[ix] = false;
            path.pop_back();
        }
    }
};

4 Subsets

https://leetcode.com/problems/subsets/

Given a set of distinct integers, nums, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
/**
 * 思路:找方案,一般都是使用搜索。
 * 
 * 以123为例,在递归还没有开始前,先把空集push到result中,之后:
 * 1. 以1位head,对23做dfs,所以pos需要加1,用于分支限界(1 12 13 123)
 * 2. 回溯到1,以2为head,对3做dfs (2 23)
 * 3. 回溯到3,以3为head,之后循环结束。 (3)
 * 
 * 
 */



class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        // ensure that elements in a subset must be in non-descending order.
        sort(nums.begin(), nums.end());
        
        vector<vector<int>> res;
        vector<int> path;
        dfs(nums, res, path, 0);
        return res;
    }
    
private:
    void dfs(const vector<int> &nums, vector<vector<int>> &res, vector<int> &path, int pos) {
        res.push_back(path);
        
        for (int i = pos; i < nums.size(); i++) {
            path.push_back(nums[i]);
            dfs(nums, res, path, i + 1);
            path.pop_back();
        }
    }
};

5. Subsets II

https://leetcode.com/problems/subsets-ii/

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,2], a solution is:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

同一位置上,前面取过的数,后面就不要再重复取了,当然当i = pos时,这个数必然是第一次取。

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        vector<int> path;
        dfs(nums, res, path, 0);
        return res;
    }
    
private:
    void dfs(const vector<int> &nums, vector<vector<int>> &res, vector<int> &path, int pos) {
        res.push_back(path);
        
        for (int i = pos; i < nums.size(); i++) {
            if (i != pos && nums[i] == nums[i - 1]) {
                continue;
            }
            
            path.push_back(nums[i]);
            dfs(nums, res, path, i + 1);
            path.pop_back();
        }
    }
};

(未完待续)

[算法专题] 深度优先搜索&回溯剪枝

标签:

原文地址:http://www.cnblogs.com/jianxinzhou/p/4712148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!