Combination and Permutation 4 - Real Problem

1. Letter Combinations of a Phone Number - Leetcode 17

phonenumber

Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given as the above image.

Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.

利用通用模板:

vector<string> letterCombinations(string digits) {
  // DFS,深搜解法!!
  if (digits.empty()) return vector<string>();
  const string hash[10] = {" ",   "'",   "abc",  "def", "ghi",
                           "jkl", "mno", "pqrs", "tuv", "wxyz"};
  vector<string> res;
  letterCombinationsCore(digits, res, "", hash, 0);
  return res;
}
void letterCombinationsCore(string digits, vector<string> &res, string path,
                            const string *hash, int start) {
  if (start == digits.size()) {  //收敛条件,处理完了
    res.push_back(path);
    return;
  }
  //处理start,这里和模板有些许区别。循环处理start中代表的各个字母
  for (int i = 0; i < hash[digits[start] - '0'].size(); i++) {
    letterCombinationsCore(digits, res, path + hash[digits[start] - '0'][i],
                           hash, start + 1);
  }
}

增量构造法,简洁代码:时间复杂度O(n^3),空间复杂度O(1),BFS广搜解法

vector<string> letterCombinations(string digits) {
  if (digits.empty()) return vector<string>();
  const string hash[10] = {" ",   "'",   "abc",  "def", "ghi",
                           "jkl", "mno", "pqrs", "tuv", "wxyz"};
  //迭代法就OK  但是res里,必须是有至少1个值的,不能从0开始
  vector<string> res(1, "");                 //若times=0, 应该返回[""]!!
  for (int i = 0; i < digits.size(); i++) {  //还剩几个数字没处理
    vector<string> copyRes(res);
    res.clear();                              //每次都,只存入最新的!!
    for (int k = 0; k < copyRes.size(); k++)  //循环之前的每一个
      //每一个新的数字,代表的每个字母加进去
      for (int j = 0; j < hash[digits[i] - '0'].size(); j++)
        res.push_back(copyRes[k] + hash[digits[i]-'0'][j]);
  }
  return res;
}

2. Palindrome Partitioning - Leetcode 131

Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.  注意区别,不是DP ==> 是DFS
For example, given s = "aab",
Return
  [
    ["aa","b"],
    ["a","a","b"]
  ]

通用模板:

//一个长度为 n 的字符串,有n-1个地方可以砍断,每个地方可断可不断,因此复杂度为O(2^n)
vector<vector<string>> partition(string s) {
  vector<vector<string>> res;
  vector<string> path;
  partitionCore(res, path, s, 0);
  return res;
}
void partitionCore(vector<vector<string>> &res, vector<string> &path, string s,
                   int start) {
  if (start == s.size()) {
    res.push_back(path);
    return;
  }
  for (int i = start; i < s.size(); i++) {  //从start开始往后切
    if (isPalindrome(s.substr(start, i - start + 1))) {
      path.push_back(s.substr(start, i - start + 1));
      partitionCore(res, path, s, i + 1);
      path.pop_back();
    }
  }
}
// 可以优化加速:借鉴DP思想,用二维数组存i到j是否为回文
bool isPalindrome(string s) {
  if (s.size() <= 1) return true;
  int i = 0, j = s.size() - 1;
  while (i <= j) {
    if (s[i] != s[j]) return false;
        i++;    j--;
    }
    return true;
}

3. N Queens

Placing n queens on an n×n chessboard, and the queens can't be in the same row, column, diagonal line.Given an integer n, return all distinct solutions.
Each solution contains a distinct board configuration of the N-queens' placement, where 'Q' and '.' each indicate a queen and an empty space respectively.

return all distinct solutions -> DFS:

void printQ(vector<vector<string>> &results, vector<vector<int>> &positions) {
    for(auto pos: positions) {
        vector<string> res;
        for(int i = 0; i < pos.size(); i++) {
            // string line {};
            // for(int j = 0; j < pos.size(); j++) {
            //     if(j == pos[i]) line += "Q";
            //     else line += ".";
            // }
            string line(pos.size(), '.');  // 注意string的这种初始化方式,类似vector!
            line[pos[i]] = 'Q';
            res.push_back(line);
        }
        results.push_back(res);
    }
}
bool canput(vector<int> &path, int pos) {
    for(int i = 0; i < path.size(); i++) {
        if(pos == path[i] || abs(pos - path[i]) == path.size() - i) {
            return false;
        }
    }
    return true;
}
void dfs(vector<vector<int>> &positions, vector<int> &path, int row, int N) {
    if(row == N) {
        positions.push_back(path);
        return;
    }
    // 第row行,从0位置开始放
    for(int i = 0; i < N; i++) {
        if(!canput(path, i)) continue;  // 这种continue方式代码缩进更少
        path.push_back(i);
        dfs(positions, path, row + 1, N);
        path.pop_back();
    }
}
vector<vector<string>> solveNQueens(int n) {
    // DFS
    vector<vector<int>> positions;
    vector<int> path;
    dfs(positions, path, 0, n);  // 从第0行开始
    vector<vector<string>> result;
    printQ(result, positions);
    return result;
}

4. Word Ladder

find the shortest transformation sequence from start to end, output the length of the sequence

find the shortest path -> BFS:

int ladderLength(string &start, string &end, unordered_set<string> &dict) {
    // 最短长度,那就是BFS啦
    unordered_set<string> visited;
    queue<string> q;
    q.push(start);
    visited.insert(start);
    int shortest = 2;
    while(!q.empty()) {
        // 把上一轮的都pop出来
        for(int i = q.size(); i > 0; i--) {
            string cur = q.front();
            q.pop();
            for(char c = 'a'; c <= 'z'; c++) {
                for(int l = 0; l < cur.size(); l++) {
                    string nextcur = cur;
                    nextcur[l] = c;
                    // 先判断,如果对了,就退出了。因为end不在dict里
                    if(nextcur == end) return shortest;
                    // 是它自己,或者dict里没有,就continue
                    if(nextcur == cur || dict.find(nextcur) == dict.end()) continue;
                    if(visited.find(nextcur) != visited.end()) continue;  // !!别忘了,如果放过了,否则死循环
                    q.push(nextcur);
                    visited.insert(nextcur);
                }
            }
        }
        shortest++;
    }
    return 0;
}
// 拓展:找出所有从start到end的最短转换序列
// 那么需要在BFS过程中,记录图的边map<string, vector<string>> next_word_dict;然后用DFS找distance为最短的path
// 剪枝:用距离,比如存unordered_map<string, int> distance(代替之前的visited),保证distance是一个越来越近的状态
Loading Disqus comments...
Table of Contents