Greedy Algorithms-Maximum Problem: Greedy Method, Binary Sorting and Pointer

Keywords: C++ REST

Question:

Give a set of non-negative integers and rearrange them to form the largest integer.

Example:

Given [1, 20, 23, 4, 8], the integer with the largest return combination should be 8423201.

Challenge:

Time complexity: O(nlogn)

Sources of the problem:

  http://www.lintcode.com/zh-cn/problem/largest-number/

 

Train of thought:

Two ideas:

1:

1. Store all bits of all elements in vector in two-dimensional array in element order; //O(Cn)

2. Compare the size of the first place of all elements in vecotr. Take an example, that is, compare the size of 1, 2, 2, 4 and 8, and sort and record their positions. Binary sort can be used for ranking; / Time complexity is O(nlogn)

3. Based on the previous step, do the second ranking, do not participate in the ranking without the second ranking, record the position after the ranking; / Time complexity is O(nlogn)

4. Repeat the above process until no element exists and no bit is involved in the sorting; //Total time complexity is O(nlogn)

5. Output based on recorded location.

Two:

1. Find the maximum value of all elements of vector, confirm whether it is in the same order of magnitude as the int limit, proceed step 2 if not, and proceed step 3 if it is in; //O(n)

2. If the maximum value and the int limit are not in the same order of magnitude, then all the remaining numbers are raised to the order of magnitude where the maximum value is located, and then directly binary sorting is performed to record their positions and output them according to their positions; //O(nlogn)

3. If the maximum value and the int limit are in the same order of magnitude, then the elements of the order of magnitude in all the elements of vector are counted, and their positions are recorded by binary sorting; //O(nlogn)

4. Divide the elements sorted in the previous step by 10 and decrease in order; //O(n)

5. Raise the remaining elements in vector to the order of magnitude of the previous step, sort all elements, record their positions, and output them according to their positions; //O(nlogn)

 

In fact, the above two ideas can be summed up as the same idea, all elements in the same order of magnitude, but the difference is that one is the descending operation, the other is the ascending operation.

Degradation operations require sorting of each element, so the relative constant C is larger. And because additional element bit information needs to be recorded, the spatial complexity will be relatively large.

So this paper adopts the incremental operation. One of the most notable points of incremental operation is that it can not exceed the int limit, so when the existing elements and the int limit are in the same order of magnitude, we first need to operate on these elements, and then upgrade the rest of the elements.

 

Code:

  1 class Solution {
  2 public:
  3     /*
  4      * @param nums: A list of non negative integers
  5      * @return: A string
  6      */
  7     string largestNumber(vector<int> &nums) {
  8         // write your code here
  9         vector<int> order_nums = nums;
 10         vector<int> sort_nums = nums;
 11         vector<int> sitea = nums;
 12         vector<int> siteb = nums;
 13         vector<int> overnum, oversite;
 14         int MaxN = nums.size();
 15         int IntMax = 1 << 31;//Achieve the int limit
 16         int NumMax = 0;
 17         int Nlevel = 0;
 18         int gain = 1;
 19         int Ilevel = 0;
 20         int Tmp = -1;
 21         string out = "";
 22         if (MaxN <= 1) {//Simple exception and case handling
 23             if (MaxN){
 24                 return to_string(nums[0]);
 25             }
 26             return "";
 27         }
 28         for (int i = 0; i < MaxN; i++) {//Finding the Maximum, Time Complexity O(n)
 29             sitea[i] = 0;
 30             if (NumMax < nums[i]) {
 31                 NumMax = nums[i];
 32             }
 33         }// O(n)
 34         Tmp = NumMax / 10;//Reduced magnitude of maximum recorded value
 35         if (!NumMax) {//Simple case handling
 36             return "0";
 37         }
 38         while (NumMax) {//Get the maximum magnitude
 39             Nlevel++;
 40             NumMax /= 10;
 41         }// O(c)
 42         while(IntMax) {//Getting the limit order of int
 43             Ilevel++;
 44             IntMax /= 10;
 45         }
 46         if (Nlevel == Ilevel) {//Is the maximum magnitude consistent with the int limit magnitude
 47             gain *= pow(10, Nlevel - 2);//Minimum value after escalation
 48             for (int i = 0; i < MaxN; i++) {//Get all numbers in the same order of magnitude as the maximum magnitude
 49                 if(order_nums[i] >= gain) {
 50                     overnum.insert(overnum.end(), order_nums[i]);
 51                     oversite.insert(oversite.end(), i);
 52                 }
 53             }
 54             vector<int> oversort = overnum;
 55             vector<int> sortsite = oversite;
 56             vector<int> storesite = oversite;
 57             twosort(oversort, overnum, sortsite, oversite, 0, overnum.size() - 1, (overnum.size() - 1) / 2);//Sort all numbers in the same order of magnitude as the maximum magnitude and record their positions
 58             for (int i = 0; i < oversort.size(); i++) {//All the numbers in the same order of magnitude as the maximum magnitudeDegradation operation
 59                 nums[storesite[i]] = oversort[i];
 60                 order_nums[storesite[i]] = sort_nums[storesite[i]] = Tmp--;
 61             }
 62         }
 63         else {
 64             gain *= pow(10, Nlevel - 1);//Minimum value after escalation
 65         }
 66         for (int i = 0; i < MaxN; i++) {//Incremental operation based on gain value
 67             siteb[i] = i;
 68             order_nums[i] = gainnum(order_nums[i], gain, order_nums[i]);
 69             //cout << order_nums[i] << " " << gain << endl;
 70         }// O(cn)
 71         twosort(order_nums, sort_nums, sitea, siteb, 0, MaxN - 1, (MaxN - 1) / 2);//Sort all numbers and record their positions
 72         for (int i = 0 ;i < MaxN; i++) {//Output all values according to location
 73             out += to_string(nums[sitea[i]]);
 74         }
 75         return out;
 76     }
 77 
 78     int gainnum(int num, const int gain,const int ori) {//The incremental function judges whether num has reached the corresponding magnitude according to the incoming gain value, and judges whether num is zero.
 79         if (num >= gain || !num) {
 80             //cout << num << endl;
 81             return num;
 82         }
 83         //cout << num << endl;
 84         return gainnum(num * 10 + ori, gain, ori);//Ensure that the num number after the escalation operation is 1... 1 times the original num number
 85     }
 86 
 87     int twosort(vector<int> &nums, vector<int> &sort, vector<int> &sitea, vector<int> &siteb, const int start, const int end, int mid) {//Binary sorting algorithm and record location at the same time
 88         if (start >= end) {//When the starting position of an array is greater than or equal to the end position, it can be considered sorted
 89             return 0;
 90         }
 91         int fr = start, bc = end, MidNum = nums[mid], tmp =start;
 92         for (int i = start; i <= end; i++) {
 93             if (nums[i] > MidNum) {//In general, the value is placed in the front segment of the array.
 94                 sort[fr] = nums[i];
 95                 sitea[fr] = siteb[i];
 96                 fr++;
 97             }
 98             else if (nums[i] < MidNum) {//Small puts the value behind the array
 99                 sort[bc] = nums[i];
100                 sitea[bc] = siteb[i];
101                 bc--;
102             }
103             else {//Equal to skip
104                 continue;
105             }
106         }//O(n)
107         tmp = fr;
108         for(int i = start; i <= end; i++) {//Parallel placement of equivalence in the middle of the front and rear segments
109             if (nums[i] == MidNum) {
110                 sort[tmp] = nums[i];
111                 sitea[tmp] = siteb[i];
112                 tmp++;
113             }
114         }//O(n)
115         if ((bc == end && tmp <= bc)) {//When all elements are larger than the last value of the array and the size of the preceding + equivalence case is within the range of the array, the sorting is considered complete.
116             nums = sort;
117             siteb = sitea;
118             return 0;
119         }
120         nums = sort;
121         siteb = sitea;//Assign arrays and positions to another array and location for the next round of sorting
122         twosort(nums, sort, sitea, siteb, start, fr - 1, (start + fr - 1) / 2);//Preceding sorting
123         twosort(nums, sort, sitea, siteb, tmp, end, (tmp + end) / 2);//Backend sorting
124         return 0;
125     }//O(nlogn)
126 };

 

Greedy Law:

This topic is a very simple application of greedy method. If the first method is used, it can be clearly seen that each step is looking for the maximum of the current position until it reaches the peak (that is, there is no next position). Although the second method has only two-step sorting at most, it also adopts the same idea: find the maximum of the same order of magnitude, and then sort the output.

 

Binary Sort & Pointer:

The main idea of binary sorting is to arrange the number of values larger than the middle position on the front/back segment of the array and smaller than the other segment. When there are multiple values equal to the middle position value, it is recommended to insert the confirmed middle position in the front and back segments in parallel without changing its order.

Repetition of the call itself completes the arrangement of the entire array.

However, it should be noted that when a function passes a parameter, it is a copy of the parameter, not the parameter itself, so when twosort passes out the sorted value and its corresponding location, it needs to take its address to pass in.

That is, int twosort (vector < int > & nums, vector < int > & sort, vector < int > & sitea, vector < int > & siteb, const int start, const int end, int mid)

In this paper, vector vectors are used instead of arrays because the array passes in the first address of the array, but to assign, the assignment operation such as siteb=sitea can not be carried out directly, which will only point the siteb's pointer to the location of the sitea's pointer, i.e. & Sitea [0].

If you want to use arrays and assign arrays, you need to use the for loop to assign them. Although the time complexity is unchanged in the case of n, the code will be redundant.

This problem can be avoided by using vector vectors. Although the address of vectors is the same as that of twosort, when it is operated, it is not for the address, but only for the value to be changed, and the vectors can be operated (vector < int >) a = b, so the code will be concise and clear.

 

Although the title is not difficult, the recognition of greed and binary sorting is a step, no longer just reading books and reading code.

Posted by fiddler80 on Thu, 23 May 2019 15:48:40 -0700