[Backtracking] [leetcode] letter combination iterator

topic:

Please design an iterator class, including the following:

A constructor, the input parameters include: an ordered and unique character string characters (the string only contains lowercase English letters) and a number combinationLength.
The function next() returns the next letter combination whose length is combinationLength in lexicographic order.
The function hasNext() returns True only when there is the next letter combination with the length of combinationLength; otherwise, it returns False.
 

Example:

CombinationIterator iterator = new CombinationIterator("abc", 2); // Create iterator

iterator.next(); // return "ab"
iterator.hasNext(); // return true
iterator.next(); // return "ac"
iterator.hasNext(); // return true
iterator.next(); // return "bc"
iterator.hasNext(); // return false
 

prompt:

  • 1 <= combinationLength <= characters.length <= 15
  • Each group of test data contains up to 10^4 function calls.
  • The title guarantees that the next letter combination exists every time the function next is called.

source:

1286. Monogram Iterator

Problem-solving idea 1: Backtracking

The combination of the question and the number of k is the same, but all the combinations of this question are not output at once but output one by one, so first use the backtracking method to put all the combinations into a queue, and return the head of the line element when calling next. can.

This idea occupies a lot of space, but there is a limit on the number of calls in the prompt, we might as well use it.

  • Recursive termination condition: the size of the path meets the length requirement
  • Pruning condition: When the result exceeds 10,000 || When the remaining elements are insufficient

class CombinationIterator {
public:
    queue<string> result;
    string path;
    CombinationIterator(string characters, int combinationLength) {
        back(characters, 0, combinationLength);
    }
    
    string next() {
        string r = result.front();
        result.pop();
        return r;
    }
    
    bool hasNext() {
        return !result.empty();
    }

    void back(const string& characters, int start, int len) {
        if (path.size() == len) {
            result.push(path);
            return;
        }
        for (int i = start; i < characters.size(); i++) {
            if (result.size() > 10000 || characters.size() - i + path.size() + 1 < len) break; // 剪枝
            path.push_back(characters[i]);
            back(characters, i+1, len);
            path.resize(path.size() - 1);
        }
    }
};

Problem-solving idea 2: N-ary

The length of the character set is N, and each character has a subscript. The subscript forms an N-base number. When N is entered, 1 is added. Note that the number after entering 1 cannot be changed to 0, but is changed to increment and continuous .

For example, the length of the character set abcdefg is 7, and the output length is 3. The first output result must be the characters abc corresponding to the subscripts 0,1,2, and then the subscripts are accumulated, and when the end of the subscript reaches 7, it will move forward.

The second number is carried from 1 to 2. The third number cannot be 0 but 2+1, that is, all numbers starting from the carry number should be an increasing continuous sequence, here it is 2, 3. The blue departments in the figure below are the next set of numbers after the carry.

Define an array path, record the subscripts of the output characters, initial [0,1,2,...,combinationLength-1], define a pointer top to point to the last element of path, and accumulate path[top].

When path[top] reaches the maximum length N, accumulate path[top-1], and judge whether the length of path[top-1] reaches N-1, if it reaches N-1, accumulate path[top-2], and judge Whether its length reaches N-2,. . . , And cyclically judge until the end.

When top reaches -1, all combinations have been completed.

class CombinationIterator {
public:
    vector<int> path;
    string input;
    int len;
    int top;
    CombinationIterator(string characters, int combinationLength) {
        input = characters;
        len = combinationLength;
        for (int i = 0; i < len; i++) {
            path.push_back(i);
        }
        top = len - 1;
    }
    
    string next() {
        string result(len, 'a');
        for (int i = 0; i < len; i++) {
            result[i] = input[path[i]];
        }
        add();
        return result;
    }

    void add() {
        top = len - 1;
        path[top]++;
        int max = input.size();
        while (top >= 0 && path[top] == max) { // 进位后满则一直进位
            top--;
            max--;
            if (top < 0) return;
            path[top]++;
        }
        // 调整以top开头的序列连续递增
        for (int i = top + 1; i < len; i++) {
            path[i] = path[i-1] + 1;
        }
    }
    
    bool hasNext() {
        return top >= 0;
    }
};

 

Guess you like

Origin blog.csdn.net/hbuxiaoshe/article/details/114937858