C++ Basics: Exercises

Keywords: less REST

Articles Catalogue

Input does not indicate how many Input, with EOF as the closing flag

C

int a, b;
// Scnf returns the number of variables. If no - 1 is returned, EOF is a predefined constant - 1.
while (scanf("%d %d", &a, &b) != EOF) {  
    // ...
}

C++

int a, b;
while (cin >> a >> b) {
    // ...
}

Input does not indicate how many Input, ending with a special input

C

// Example 1
int a, b;
while (scanf("%d %d", &a, &b) != EOF && (a != 0 && b != 0)) {
    // ...
}

// perhaps
while (scanf("%d %d", &a, &b) != EOF && (a || b)) {
    // ...
}

// Example 2
int n;
while (scanf("%d", &n) != EOF && n != 0) {
    // ...
}

C++

// Example 1
int a, b;
while (cin >> a >> b) {
    if (a == 0 && b == 0)
        break;
    // ...
}

// Example 2
int n;
while (cin >> n && n != 0) {
    // ...
}

Indicates N Input

C

int n;
scanf("%d", &n);

int a, b;
for (int i = 0; i < n; i++) {
    scanf("%d %d", &a, &b);
    // ...
}

C++

int n;
cin >> n;

int a, b;
while(n--) {
    cin >> a >> b;
}

Python3

n = int(input())
for _ in range(n):
    # ...

Indicates that there are N groups of inputs and exits with a particular input

C/C++

int n;
while (cin >> n && n != 0) {
    int a, b;
    for (int i = 0; i < n; i++) {
        cin >> a >> b;
        // ...
    }
}

The input is a whole line (including spaces)

Receiving (C/C++) with char []

const int MAXN = 1000;
char buff[MAXN];

// C
gets(buff);
puts(buff); // output

// C++
cin.getline(buff, MAXN);  // The third parameter defaults to'n'
cin.getline(buff, MAXN, '\n');

Receiving (C++) with string

string s;
getline(cin, s);          // The third parameter defaults to'n'
getline(cin, s, '\n');

Input is multi-line (including spaces)

C++

int n;
cin >> n;
cin.get();  // Otherwise, n is counted in the following getline(), resulting in a smaller set of data

while (n--) {
    string s;
    getline(cin, s);
}

Read from a file

C

FILE *cfin = fopen("in.txt", "r");
FILE *cfout = fopen("out.txt", "w");

int a, b;
// Note to pass in the file pointer
while (fscanf(cfin, "%d %d", &a, &b) != EOF) { // Similarly, replace scanf with fscanf
    fprintf(cfout, "%d\n", a + b);             // Replace printf with fprintf
}

fclose(cfin);
fclose(cfout);

C++

ifstream fin("in.txt");
ofstream fout("out.txt");

int a, b;
while (fin >> a >> b) {
    fout << a + b << endl;
}


fin.close();
fout.close();

Arithmetic Arrangement

array

Next permutation

LeetCode - 31. Next permutation

Topic Description

To achieve the next permutation function, the algorithm needs to rearrange the given number sequence into the next larger permutation in the dictionary order.

If there is no next larger arrangement, the numbers are rearranged into the smallest (ascending) arrangement.

It must be modified in situ, allowing only extra constant space.

Here are some examples where the input is in the left column and the corresponding output is in the right column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

thinking

  • The two adjacent permutations have the longest common prefix, and then find the high and low positions that need to be exchanged.
  • According to the definition of dictionary order, follow the following steps to find the next permutation
  1. Look back and forth for the high hi that needs to be changed, that is, the position of the first descending element
    1 5 8 4 7 6 5 3 1
          ↑
          hi
    
  2. Look back and forth for the low lo that needs to be swapped, that is, the first location larger than nums[hi]
    1 5 8 4 7 6 5 3 1
          ↑     ↑
          hi    lo
    
  3. Exchange nums[lo] and nums[hi]
    1 5 8 4 7 6 5 3 1
          ↓     ↓
    1 5 8 5 7 6 4 3 1
          ↑     ↑
          Hi lo (hi position unchanged)
    
  4. The sequence after inversion of hi, i.e. nums [hi+1:n)
    1 5 8 5 7 6 4 3 1
            ↓ ↓ ↓ ↓ ↓
    1 5 8 5 1 3 4 6 7
          ↑     ↑
          Hi lo (hi position unchanged)
    

C++

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1) return;
    
        int hi = n - 2;
        // 1. Look back and forth for the ** high ** hi that needs to be changed, that is, the position of the first descending element.
        while (hi >= 0 && nums[hi + 1] <= nums[hi])
            hi--;

        if (hi >= 0) {
            // 2. Look back and forth for the ** low ** lo that needs to be exchanged, that is, the first position larger than nums[hi]
            int lo = n - 1;
            while (lo >= 0 && nums[lo] <= nums[hi])
                lo--;
            // 3. Exchange nums[lo] and nums[hi]
            swap(nums[hi], nums[lo]);
        }

        // 4. Sequence after inversion of hi, i.e. nums [hi+1:n)
        reverse(nums.begin() + hi + 1, nums.end());
        // When i==-1, this operation changes the sequence from the dictionary maximum to the minimum, which is slightly different from the next_permutation provided in STL.
    }
};

The last permutation

LintCode - 51. The last permutation

Problem Description

Given an array of integers to represent permutations, find the last permutation on it.
Arrangements may contain duplicate integers

Example
 Give the permutation [1,3,2,3], on which the last permutation is [1,2,3,3]

Give the permutation [1,2,3,4], on which the last permutation is [4,3,2,1]

thinking

  1. Look for the first ascending position hi from right to left
  2. Look for the first location lo less than nums[hi] from right to left
  3. Exchange nums[lo] and nums[hi]
  4. Position after inversion of hi

C++

class Solution {
public:
    /*
    * @param nums: A list of integers
    * @return: A list of integers that's previous permuation
    */
    vector<int> previousPermuation(vector<int> &nums) {
        int n = nums.size();

        if (n <= 1) return nums;

        int hi = n - 2;
        // 1. Look for the location hi of the first ascending order ** from right to left
        while (hi >= 0 && nums[hi] <= nums[hi + 1])
            hi--;

        if (hi >= 0) {
            int lo = n - 1;
            // 2. Look from right to left for the first location lo less than ** nums[hi]
            while (lo >= 0 && nums[lo] >= nums[hi])
                lo--;
            // 3. Exchange nums[lo] and nums[hi]
            swap(nums[lo], nums[hi]);
        }

        // 4. Position after inversion of hi
        reverse(nums.begin() + hi + 1, nums.end());

        return nums;  // Note that you are asked to return a value here.
    }
};

Implementation provided by STL (next permutation, last permutation) TODO

  • STL provides two functions for generating permutations
    bool next_permutation (BidirectionalIterator first,
                           BidirectionalIterator last);
    
    bool prev_permutation (BidirectionalIterator first,
                           BidirectionalIterator last );
    
  • These two functions are based on lexicographical_compare() to generate the next or last permutation.
  • So before using these two functions, you need to sort the original sequence first.

C++

Kth permutation

LeetCode - 60. The k th permutation

Problem Description

Give the set [1,2,3,... N], all its elements have n! Species arrangement.

List all permutations in order of size and mark them one by one. When n = 3, all permutations are as follows:
"123"
"132"
"213"
"231"
"312"
"321"

Given n n n and k, return the kth permutation.

Explain:
  The range of given n is [1, 9].
  The range of given k is [1, n!].
Example 1:
  Input: n = 3, k = 3
  Output: "213"
Example 2:
  Input: n = 4, k = 9
  Output: "2314"

thinking

  • Because of the nature of dictionary order, it is not necessary to find the first k-1 sequence.
  • The whole idea is a bit like bucket sorting.
  • Taking {1 234 5} as an example, the fourteenth sequence is found out.
    First, the ordered columns can be placed in the corresponding buckets according to the elements in the first position.
    Before you start, k--, because the computer counts start from zero, and then k=13. (Here's why you need to subtract 1.)
    Round 1: 5 remaining elements, 5 barrels
      Bucket 0: Beginning with 1, the remaining element {2345} 
      Bucket 1: Beginning with 2, the remaining element {1345} 
      Bucket 2: Beginning with 3, the remaining element {1 245} 
      Bucket 3: Starting with 4, the remaining element {1 235}
      Bucket 4: Starting with 5, the remaining element {1 234}
    There are 4! = 24 sequences in each bucket, because they are ordered. Obviously, k=13 elements must be in `13/(4!) = 0 `buckets.
      In other words, the fourteenth element must begin with one.
    Remove 1 from the sequence, change the remaining sequence to {2345}, k = 13%, 24 = 13
    
    Round 2: 4 remaining elements, 4 barrels
      Bucket 0: Beginning with 2, the remaining element {345} 
      Bucket 1: Starting with 3, the remaining element {245} 
      Bucket 2: Starting with 4, the remaining element {235} 
      Bucket 3: Starting with 5, the remaining element {234}
    There are 3! = 6 elements in each bucket. Obviously, the k=13 element should be in the `13/(3!) = 2 `bucket.
      That is, the prefix of the 14th element is 14.
    Remove 4 from the sequence, change the remaining sequence to {235}, k = 13% 6 = 1
    
    Round 3: The remaining three elements, three barrels
      Bucket 0: Beginning with 2, the remaining element {35} 
      Bucket 1: Starting with 3, the remaining element {25} 
      Bucket 2: Starting with 5, the remaining element {35} 
    At this point, there are 2! = 2 elements in each bucket. k=1 element should be in `1/(2!) = 0 `bucket. (If k does not decrease 1 at the beginning, there will be a problem.)
      That is, the prefix of the fourteenth element is 142
     Remove 2 from the sequence, change the remaining sequence to {35}, k = 1% 2 = 1
    
    Round 4: 2 remaining elements, 2 barrels
      Bucket 0: Beginning with 3, the remaining element {5} 
      Bucket 1: Starting with 5, the remaining element {3} 
    At this point, there is 1! = 1 element in each bucket. The k=1 element should be in the `1/(1!)= 1 `bucket.
      That is, the prefix of the fourteenth element is 1425
     Remove 5 from the sequence, change the remaining sequence to {3}, k = 1% - 1 = 0
    
    Round 5: 1 element remaining, 1 barrel
      Bucket 0: Beginning with 3, no residual elements
     At this point, there is 0! = 1 element in each bucket (in fact, there is no element in the bucket at this time).
    The k=0 element should be in the `0/(0!) = 0 `barrel (the last round using the property of 0!= 1 does not require special treatment)
      The 14th element is 14253.
    

C++

class Solution {
public:
    string getPermutation(int n, int k) {

        // nums: {1, 2, 3, ..., n}
        // Change into other characters and store them in the corresponding position in dictionary order.
        vector<int> nums(n + 1, 0);
        for (int i = 0; i < n; i++) // Note: Bucket subscriptions start at 0.
            nums[i] = i + 1;

        // dp: {0!=1, 1!, 2!, ..., n!}
        vector<int> dp(n + 1, 1);  // According to the above deduction, dp[0]=1 can just handle the last round.
        for (int i = 1; i <= n; i++)
            dp[i] = dp[i - 1] * i;

        k--;
        stringstream ss;
        for (int i = 1; i <= n; i++) {  // Starting from 1
            int index = k / dp[n - i];  // Actually, dp[n] = n is not used!
            ss << nums[index];
            nums.erase(nums.begin() + index);  // Note that the processed elements are deleted in each round
            k = k % dp[n - i];
        }

        return ss.str();
    }
};

Full Arrangement (No Repetition)

LeetCode 46. Full Arrangement

Topic Description

Given a sequence without duplicate numbers, all possible permutations are returned.

Examples:

Input: [1, 2, 3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

Thought 1

  • Using the next permutation, sort the arrays first, and then generate the next permutation continuously.

Idea 2

  • Depth-first search
  • It is easy to know that when the elements in the sequence do not repeat, there are different kinds of arrangement of n!
  • Considering the first position, there are n possibilities
  • When the first position is selected, the second position has n-1 possibilities.
  • Because the number of states per search decreases, dfs here is a recursive process

Insert-based Writing

  • More code, but better understanding
class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;
    vector<bool> used;
    int n = 0;

    void dfs(vector<int>& nums, int step) {
        if (tmp.size() == n) {
            ret.push_back(tmp);
            return;
        }

        for (int i = 0; i < n; i++) {   // i starts at 0 each time, because elements can be reused
            if (used[i]) continue;      // But in each round, if you use it, you need to skip it.
                                        // Each round refers to the process of generating an arrangement.
            used[i] = 1;            // Markup usage
            tmp.push_back(nums[i]);
            dfs(nums, step + 1);
            tmp.pop_back();         // To flash back
            used[i] = 0;
        }
    }

public:
    vector<vector<int> > permute(vector<int>& nums) {
        n = nums.size();
        used.resize(n, 0);

        dfs(nums, 0);
        return ret;
    }
};

[Note] Notes on for(i=0;.) and for(i=step;.)

Writing Based on Exchange

  • Exchange-based writing makes the code concise, but I think it's a little hard to understand.
class Solution {
    vector<vector<int> > ret;

    //Void DFS (vector < int > nums, int step) {// value transfer
    void dfs(vector<int>& nums, int step) {   // Reference passing
        if (step >= nums.size()) {
            ret.push_back(nums);
            return;
        }

        for (int i = step; i < nums.size(); i++) { // Note: Here i start with step
            swap(nums[step], nums[i]);
            dfs(nums, step + 1);
            swap(nums[step], nums[i]);  // If nums is a value input, this step is not required; otherwise, it cannot be omitted.
        }
    }

public:
    vector<vector<int> > permute(vector<int>& nums) {
        dfs(nums, 0);
        return ret;
    }
};

Full permutation (repetition)

LeetCode - 47. Full Rank II

Topic Description

Given a sequence of repetitive numbers, all non-repetitive permutations are returned.

Examples:

Input: [1, 1, 2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

Thought 1

  • Remove duplication (not recommended) with set by using the method without duplication

Idea 2

  • First, the original sequence is sorted so that the same elements are adjacent; at this time, only the first same element is processed, and the rest are skipped.

Insert-based Writing

class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;
    vector<bool> used;
    int n = 0;

    void dfs(vector<int>& nums, int step) {
        if (tmp.size() == n) {
            ret.push_back(tmp);
            return;
        }

        for (int i = 0; i < n; i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]))
                continue;  // Here! used[i - 1] is a little hard to understand, it can cooperate with IDE or push the whole process by hand.

            used[i] = 1;
            tmp.push_back(nums[i]);
            dfs(nums, step + 1);
            tmp.pop_back();
            used[i] = 0;
        }
    }

public:
    vector<vector<int> > permuteUnique(vector<int>& nums) {
        n = nums.size();
        used.resize(n, 0);
        sort(nums.begin(), nums.end());

        dfs(nums, 0);
        return ret;
    }
};

Writing Based on Exchange

class Solution {
    vector<vector<int> > ret;

    //Void DFS (vector < int > & nums, int step) {// pass reference can not get the correct result
    void dfs(vector<int> nums, int step) {    // Note that ** value transfer ** should be used here
        int n = nums.size();
        if (step >= n - 1) {
            ret.push_back(nums);
            return;
        }

        for (int i = step; i < n; i++) {
            if (i != step && nums[i] == nums[step])
                continue;

            swap(nums[i], nums[step]);
            dfs(nums, step + 1);
            //swap(nums[i], nums[step]); / / referencing with backtracking can not get the correct results.
                                         // The reason for this is that it destroys the order of the remaining arrays.
        }
    }
public:
    vector<vector<int> > permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        dfs(nums, 0);

        return ret;
    }
};

[Note] Time Complexity of Full Sorting

  • In the case of no repetition, the different full arrangement of n elements is n!, so the time complexity of the algorithm is at least O(N!).
  • Therefore, the full permutation algorithm is not able to process large data.

combination

Combination (n chooses k, no repetition)

LeetCode - 77. Combination

Problem Description

Given two integers n and k, a combination of all possible K numbers in 1... n is returned.

Examples:

Input: n = 4, k = 2
 Output:
  [
    [2,4],
    [3,4],
    [2,3],
    [1,2],
    [1,3],
    [1,4],
  ]

thinking

C++

class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;   // Save intermediate results
    int K;

    void dfs(vector<int>& nums, int step) {
        if (tmp.size() >= K) {
            ret.push_back(tmp);
            return;
        }

        for (int i = step; i < nums.size(); i++) {
            tmp.push_back(nums[i]);  // Nums [i]== i, so direct push(i) here is OK
            dfs(nums, i + 1);
            tmp.pop_back();
        }
    }

public:
    vector<vector<int> > combine(int n, int k) {

        K = k;
        vector<int> nums;
        for (int i = 0; i < n; i++)
            nums.push_back(i + 1);

        dfs(nums, 0);
        return ret;
    }
};

Combination (n select k, repeat)

(Unverified)

  • If no duplication is required in each combination, the duplication can be removed first and then followed by the non-duplication approach.
  • If you don't need to weigh, just follow the non-repetitive approach.

Combination summation (numbers are not duplicated but reusable)

LeetCode - 39. Combination summation

thinking

  • Depth-first search
  • The key is that each number can be reused.

C++

class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;
    int cur = 0;
    int target = 0;

    void dfs(vector<int>& nums, int step) {
        if (cur >= target) {
            if (cur == target)
                ret.push_back(tmp);
            return;
        }

        for (int i = step; i < nums.size(); i++) {
            cur += nums[i];
            tmp.push_back(nums[i]);
            dfs(nums, i);  // Because each array can be reused, it's dfs(i) instead of dfs(i+1)
            cur -= nums[i];
            tmp.pop_back();
        }
    }

public:
    vector<vector<int> > combinationSum(vector<int>& candidates, int target) {
        this->target = target;

        //Sort (candidates. begin (), candidates. end (); // No
        dfs(candidates, 0);

        return ret;
    }
};

[Note] Notes on dfs(step+1), dfs(i+1), dfs(i)

Combination sum and 2 (there are duplicate numbers but each number can only be used once)

LeetCode - 40. Combination summation II

thinking

  • DFS, the key is how to remove duplication

C++

class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;
    int cur = 0;
    int target;

    void dfs(vector<int>& nums, int step) {
        if (cur >= target) {
            if (cur == target)
                ret.push_back(tmp);
            return;
        }

        for (int i = step; i < nums.size(); i++) {
            if (i > step && nums[i] == nums[i - 1]) // Code Note 1
                continue;

            cur += nums[i];
            tmp.push_back(nums[i]);
            dfs(nums, i + 1);       // i+1 instead of i, because it can't be reused
            tmp.pop_back();
            cur -= nums[i];
        }
    }
public:
    vector<vector<int> > combinationSum2(vector<int>& candidates, int target) {
        this->target = target;

        sort(candidates.begin(), candidates.end());  // Because there is duplication, you need to sort first
        dfs(candidates, 0);

        return ret;
    }
};

Code Note 1

if (i > step && nums[i] == nums[i - 1])
  • Failed to save pictures by external chain (img-ALhj2Fjq-1567509435788)(... / assets/Formula _20180905213339.png]
  • This code does not actually filter [External Link Picture Transfer Failure (img-NPDvI0lz-1567509435789)(... / assets/Formula _20180905213323.png)] - The case of I = step
  • The real duplication is the failure of the external link image transfer (img-2omS85CI-1567509435790)(____________). / assets/Formula _20180905213258.png] and [External Link Picture Transfer Failure (img-ROSXCPSQ-1567509435790)(... / assets/Formula _20180905213158.png], and the purpose of this code is to filter [External Link Picture Transfer Failure (img-rHr5Fpr7-1567509435791)(... / assets/Formula _20180905213158.png] - I > Step

Combination sum and 3 (number not repeated and specified number)

LeetCode - 216. Combination summation III

Problem Description

Find out all combinations of k numbers that add up to n. Only positive integers containing 1 - 9 are allowed in combinations, and there are no duplicate numbers in each combination.

Explain:

All numbers are positive integers.
Unset cannot contain duplicate combinations. 

Example 1:
Input: k = 3, n = 7
 Output: [[1, 2, 4]]

Example 2:
Input: k = 3, n = 9
 Output: [[1,2,6], [1,3,5], [2,3,4]]

thinking

C++

class Solution {
    vector<vector<int> > ret;
    vector<int> tmp;
    int cur = 0;
    int K;

    void dfs(int n, int step) {
        if (cur >= n) {
            if (cur == n && tmp.size() == K)  // Join the result set only when satisfied at the same time
                ret.push_back(tmp);
            return;
        }

        for (int i = step; i <= 9; i++) {

            cur += i;
            tmp.push_back(i);
            dfs(n, i + 1);    // Because the number can't be reused, it's dfs(i+1)
            tmp.pop_back();
            cur -= i;
        }
    }

public:
    vector<vector<int> > combinationSum3(int k, int n) {
        K = k;

        dfs(n, 1);
        return ret;
    }
};

[Note]

Dictionary Preface

  • When dealing with permutation, the next permutation is usually generated according to dictionary order.
  • In a dictionary order, the ascending order of a sequence is the first, and the descending order is the last.

High and Low Positions

  • For any two positions in the sequence, the upper position is near the left and the lower position is near the right.
  • The process of generating permutation is the process of increasing the high position and decreasing the low position.
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1
    

Notes on for(i=0;...) and for(i=step;...)

[Note] Notes on dfs(step+1), dfs(i+1), dfs(i)

(The following are personal summaries, which are not strictly validated)

dfs(step+1) and dfs(i+1)

  • Simply put, dfs(step+1) refers to the step+1 position in the generated tmp sequence; dfs(i+1) refers to the use of the i+1 element in nums
    • stay Arrangement (no repetition) In the problem, dfs(step+1) is used.
    • stay Combination (no duplication) In the problem, dfs(i+1) is used.
    • Relevant code snippets
      // array
      for (int i = step; i < nums.size(); i++) {
          // ...
          dfs(nums, step + 1);
          // ...
      }
      
      // combination
      for (int i = step; i < nums.size(); i++) {
          // ...
          dfs(nums, i + 1);
          // ...
      }
      
  • Taking the non-repetitive set {1 234} as an example, this paper illustrates that:
    • Elements used in permutation problems may also be reused.
      When step = 0, the first position is 1
        All permutations are 1 + {234} 
      When step = 1, the first position is 2
        All permutations of 2 + {134} # 1 appear again in the sequential elements
      ...
      
    • The elements used in combinatorial problems are not used anymore.
      When step = 0, the first position is 1
        All combinations are 1 + {234}
      When step = 1, the first position is 2
        All combinations 2 + {34}# 1 are no longer used
      
    • It is precisely because of this difference that dfs(step+1) should be used in permutation and dfs(i+1) should be used in combination.

dfs(i+1) and dfs(i)

  • stay Combination summation dfs(i) is also used in the problem.
    for (int i = step; i < nums.size(); i++) {
        // ...
        dfs(nums, i);
        // ...
    }
    
    • On the one hand, it is similar to combinatorial problems, where used numbers are no longer used; therefore, i is used instead of step.
    • On the other hand, each number can be reused, so dfs(i) is used instead of dfs(i+1)

Posted by Arsenal Rule on Thu, 05 Sep 2019 01:06:55 -0700