Articles Catalogue
- Input does not indicate how many Input, with EOF as the closing flag
- Input does not indicate how many Input, ending with a special input
- Indicates N Input
- Indicates that there are N groups of inputs and exits with a particular input
- The input is a whole line (including spaces)
- Input is multi-line (including spaces)
- Read from a file
- Arithmetic Arrangement
- array
- Next permutation
- The last permutation
- Implementation provided by STL (next permutation, last permutation) TODO
- Kth permutation
- Full Arrangement (No Repetition)
- Full permutation (repetition)
- [Note] Time Complexity of Full Sorting
- combination
- Combination (n chooses k, no repetition)
- Combination (n select k, repeat)
- Combination summation (numbers are not duplicated but reusable)
- Combination sum and 2 (there are duplicate numbers but each number can only be used once)
- Combination sum and 3 (number not repeated and specified number)
- [Note]
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
- 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
- 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
- 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)
-
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
- In fact, it is. Next permutation The inverse process
- Look for the first ascending position hi from right to left
- Look for the first location lo less than nums[hi] from right to left
- Exchange nums[lo] and nums[hi]
- 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; } };
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
- Depth-first search with backtracking, similar Full Arrangement (No Repetition)
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; } };
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
- stay Combination summation (numbers are not duplicated but reusable) A slight modification is enough.
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;...)
- for(i=0;.) to be used with the use tag
-
for(i=step;..)
- All combinatorial problems
- Simply put, take {1,234} as an example
-
for(i=0;.) for
1 + {2 3 4} 2 + {1 3 4} ...
- Used is used to mark the beginning of 1, 2, etc.
-
for(i=step;.) for
1 + {2 3 4} 2 + {3 4} ...
- Usually no use tag is required
-
for(i=0;.) for
[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.
- Elements used in permutation problems may also be reused.
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)