Recommended by the author
Knowledge points involved in this article
monotonic stack
topic
Given two arrays of length m and n respectively, their elements are composed of 0-9, representing the numbers in each bit of the two natural numbers. Now select k (k <= m + n) numbers from these two arrays and splice them into a new number. The numbers taken from the same array are required to maintain their relative order in the original array.
Find the maximum number that satisfies this condition. The result is an array of length k representing the maximum number.
Note: Please optimize the time and space complexity of your algorithm as much as possible.
Example 1:
Input:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
Output:
[ 9, 8, 6, 5, 3]
Example 2:
Input:
nums1 = [6, 7]< /span> nums1 = [3, 9]< /span> [9, 8, 9] Output: k = 3 nums2 = [8, 9] Input: Example 3: [ 6, 7, 6, 0, 4] Output: k = 5
nums2 = [6, 0, 4]
monotonic stack
Time complexity: O(k(m+n+max(n,m)*max(n,m))). Enumerating m and n, the time complexity is O(k). For any combination of m and n, the processing is divided into the following four steps: 1. Calculate the maximum lexicographic subsequence v1 of length m of nums1. Second, calculate the maximum lexicographic subsequence v2 of length n in nums2. Third, merge v1 and v2 into cur. Fourth, compare the sizes of cur and vRet.
Corresponding to any m,n only need to consider the maximum dictionary order
Assume that the subsequence composed of elements from nums1 in the final result is not in maximum dictionary order, and is replaced by the maximum dictionary sequence. It also conforms to the meaning of the question, and the dictionary order remains unchanged or becomes larger.
Maximum lexicographic order of length len
vVet[0,i] records the maximum lexicographic subsequence of length i+1. You can think of vRet as a queue. When the new element is larger than the tail element of the queue, replacing the tail element will form a new maximum subsequence. You can always replace the last element of the guide queue to be greater than or equal to the current element or the queue is empty. The problem is that the length of vRet may not be empty. The solution:
If all the remaining numbers are added to the queue after being dequeued, the length of vRet cannot be made greater than or equal to k. | Then don’t leave the team |
If vRet.size()>=k | Then don’t join the team |
merge v1v2
We regard v1 and v2 as queues, and we can only take the head of the queue each time. Take the larger value of the two team leaders each time. If they are equal, then:
Assume that v1 and v2 have the same prefix vPre, and their length is len. Assume that vPre of v1 is followed by c. Assume The d after v2 and vPre. Select v1 or v2, the first len characters can be the same. Select v1, the len+1th character can be c, but not d. Select v2, the len+1th character is d, not c. Obviously, if c is large, choose v1; if d is large, choose v2. Let's consider a special case:
c and d do not exist | v1 and v2 are exactly the same, and the effect of selecting v1 and v2 is the same |
c exists, d does not exist | In order to select c for len+1, select v1 |
d exists, c does not exist | In order to select d for len+1, select v2 |
To sum up the above: Just choose the one with the largest lexicographic order, and use lexicographical_compare to simplify the code.
code
core code
class Solution {
public:
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
vector<int> vRet(k);
for (int len1 = 0; len1 <= min((int)nums1.size(), k); len1++)
{
const int len2 = k - len1;
if (len2 > nums2.size())
{
continue;
}
if (len2 < 0)
{
break;
}
vector<int> v1 = TopMax(nums1, len1);
vector<int> v2 = TopMax(nums2, len2);
vector<int> cur;
int i1 = 0, i2 = 0;
while ((i1 < v1.size()) && (i2 < v2.size()))
{
auto Cmp = [&v1,&v2](int i1,int i2)
{
while((i1<v1.size())&&(i2 < v2.size()))
{
const int iCmp = v1[i1] - v2[i2];
if (iCmp > 0 )
{
return true;;
}
else if (iCmp < 0)
{
return false;
}
i1++;
i2++;
}
return i1 < v1.size();
};
if (Cmp(i1,i2))
{
cur.emplace_back(v1[i1++]);
}
else
{
cur.emplace_back(v2[i2++]);
}
}
cur.insert(cur.end(), v1.begin() + i1, v1.end());
cur.insert(cur.end(), v2.begin() + i2, v2.end());
vRet = max(cur, vRet);
}
return vRet;
}
vector<int> TopMax(const vector<int>& nums, int k)
{
vector<int> ret;
for (int i = 0; i < nums.size(); i++)
{
while (ret.size() && (ret.back() < nums[i]) && (ret.size() + nums.size() - i > k))
{
ret.pop_back();
}
if (ret.size() < k)
{
ret.emplace_back(nums[i]);
}
}
return ret;
}
};
test case
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}
template<class T>
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
int main()
{
vector<int> nums1, nums2;
int k;
{
Solution slu;
nums1 = {
3, 4, 6, 5 };
nums2 = {
9, 1, 2, 5, 8, 3 };
k = 5;
auto res = slu.maxNumber(nums1, nums2, k);
Assert(vector<int>{
9, 8, 6, 5, 3}, res);
}
{
Solution slu;
nums1 = {
6, 7 };
nums2 = {
6, 0, 4 };
k = 5;
auto res = slu.maxNumber(nums1, nums2, k);
Assert(vector<int>{
6, 7, 6, 0, 4}, res);
}
{
Solution slu;
nums1 = {
3, 9 };
nums2 = {
8,9 };
k = 3;
auto res = slu.maxNumber(nums1, nums2, k);
Assert(vector<int>{
9, 8, 9}, res);
}
}
Simplified code
class Solution {
public:
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
vector<int> vRet(k);
for (int len1 = 0; len1 <= min((int)nums1.size(), k); len1++)
{
const int len2 = k - len1;
if (len2 > nums2.size())
{
continue;
}
if (len2 < 0)
{
break;
}
vector<int> v1 = TopMax(nums1, len1);
vector<int> v2 = TopMax(nums2, len2);
vector<int> cur;
auto it1 = v1.begin();
auto it2 = v2.begin();
for (;(it1 != v1.end()) && (it2 != v2.end());)
{
if (lexicographical_compare(it1,v1.end(),it2,v2.end()))
{
cur.emplace_back(*it2++);
}
else
{
cur.emplace_back(*it1++);
}
}
cur.insert(cur.end(), it1, v1.end());
cur.insert(cur.end(), it2, v2.end());
vRet = max(cur, vRet);
}
return vRet;
}
vector<int> TopMax(const vector<int>& nums, int k)
{
vector<int> ret;
for (int i = 0; i < nums.size(); i++)
{
while (ret.size() && (ret.back() < nums[i]) && (ret.size() + nums.size() - i > k))
{
ret.pop_back();
}
if (ret.size() < k)
{
ret.emplace_back(nums[i]);
}
}
return ret;
}
};
March 2023
class Solution {
public:
vector maxNumber(vector& nums1, vector& nums2, int k) {
vector vRet;
for (int iLeft = 0; iLeft <= k; iLeft++)
{
const vector v1 = maxNumber(nums1, iLeft);
const vector v2 = maxNumber(nums2, k - iLeft);
if (v1.size() + v2.size() != k)
{
continue;
}
vector nums;
auto it1 = v1.begin();
auto it2 = v2.begin();
while ((it1 != v1.end() ) && (it2 != v2.end() ))
{
if (*it1 > *it2 )
{
nums.push_back(*it1);
it1++;
}
else if(*it1 < *it2)
{
nums.push_back(*it2);
it2++;
}
else
{
if (Less(it1, v1.end(), it2, v2.end()))
{
nums.push_back(*it2);
it2++;
}
else
{
nums.push_back(*it1);
it1++;
}
}
}
std::copy(it1, v1.end(), std::back_inserter(nums));
std::copy(it2, v2.end(), std::back_inserter(nums));
if ((vRet.size() == 0) || Less(vRet,nums))
{
vRet.swap(nums);
}
}
return vRet;
}
template
bool Less(IT itBegin1, IT itEnd1, IT itBegin2, IT itEnd2)
{
while ((itBegin1 != itEnd1) && (itBegin2 != itEnd2))
{
if (*itBegin1 < *itBegin2)
{
return true;
}
else if (*itBegin1 > *itBegin2)
{
return false;
}
itBegin1++;
itBegin2++;
}
return itBegin1 == itEnd1;
}
bool Less(const vector& v1, const vector& v2)
{
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] < v2[i])
{
return true;
}
else if (v1[i] > v2[i])
{
return false;
}
}
return false;
}
vector maxNumber(const vector& nums, int k)
{
vector ret;
for (int i = 0; i < nums.size(); i++)
{
const int& n = nums[i];
while (ret.size() && (n > ret.back()) && ((ret.size() + nums.size() - i - 1) >= k))
{
ret.pop_back();
}
if (ret.size() < k)
{
ret.push_back(n);
}
}
return ret;
}
};
August 2023
template<class T = int,class _Pr = std::less >
class CTopK
{
public:
CTopK(int k):m_iMinNum(k)
{
}
void Do(vector& m_v,T* begin, int num)
{
for (; num ; begin++,num–)
{
while (m_v.size() && _Pr()( *begin, m_v.back()) && (m_iMinNum - m_v.size()+1 <= num))
{
m_v.pop_back();
}
if (m_v.size() < m_iMinNum)
{
m_v.push_back(*begin);
}
}
}
protected:
const int m_iMinNum;
};
class Solution {
public:
vector maxNumber(vector& nums1, vector& nums2, int k) {
CTopK<int,std::greater> tok(k);
vector<vector> vNums1(k + 1), vNums2(k + 1);
tok.Do(vNums1[k], nums1.data(), nums1.size());
tok.Do(vNums2[k], nums2.data(), nums2.size());
for (int i = k - 1; i >0; i–)
{
CTopK<int, std::greater> tok(i);
tok.Do(vNums1[i], vNums1[i + 1].data(), vNums1[i + 1].size());
tok.Do(vNums2[i], vNums2[i + 1].data(), vNums2[i + 1].size());
}
vector vRet(k);
for (int i = max(0,k-(int)nums2.size()); i <= min(k,(int)nums1.size()); i++)
{
const auto& v1 = vNums1[i];
const auto& v2 = vNums2[k - i];
vector cur;
auto it = v1.begin();
auto ij = v2.begin();
while ((it != v1.end()) || (ij != v2.end()))
{
bool b = lexicographical_compare(it, v1.end(), ij, v2.end());
if (b)
{
cur.emplace_back((ij++));
}
else
{
cur.emplace_back((it++));
}
}
if (cur > vRet)
{
vRet.swap(cur);
}
}
return vRet;
}
};
Further reading
video course
Effective learning: clear goals, timely feedback, stretching zone (appropriate difficulty), you can learn simple courses first, please go to CSDN Academy and listen to the explanation of the Baiyin instructor (that is, I).
https://edu.csdn.net/course/detail/38771
how fast do you want
The battle is about to begin. To share the worries of the boss, please learn C# onboarding training, C++ onboarding training and other courses
https://edu.csdn.net/lecturer/6176
Related
download
If you want to know the learning algorithm from a superior position, please download the doc version of "Xi Que Complete Book of Algorithms"
https://download.csdn.net/download/he_zhidan/88348653
What I want to say to everyone |
---|
It is a good wish to be happy when you hear defects, to find problems early, correct them early, and save money for the boss. |
Zimozi said: Nothing has an end or a beginning, and there is no business and many undertakings. That is what we often say: professional people do professional things. |
If the program is a one-stop process, then the algorithm is its key point |
test environment
Operating system: win7 Development environment: VS2019 C++17
Or operating system: win10 Development environment: VS2022 C++17
Unless otherwise specified, this algorithm is implemented in **C++**.