题目要求:
给定一个数组例如nums=[2,3,4,5],n=2345,
求使用nums中的数字,组成一个不大于n(包含等于)的最大的数字。
nums中的数字可以多次使用。
备注:例如nums=[6, 8], n = 300。那么应该返回最大数字为88。
代码:
int getpos(vector<int>& nums, int target) {//二分函数,最后返回的l会指向target在数组中的索引或大于target的第一个数
int l = 0, r = nums.size() - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (nums[mid] < target)l = mid + 1;
else r = mid - 1;
}
return l;
}
int getn(vector<int>& nums, int n) {
string ans;;
string s(to_string(n));//将数转化成字符串方便判断
sort(nums.begin(), nums.end());
int len = s.size();
unordered_set<int>st;//将数组中的数装入哈希表方便判断
for (int num : nums)st.emplace(num);
for (int i = 0; i < len; ++i) {
if (st.count(s[i]-'0')) {//如果一直能从数组中匹配
ans += s[i];
}
else {//无法匹配那么找到数组中是否存在第一个比当前位小的数
int p = getpos(nums, s[i]-'0');
if (p >0) {//有的话,将这一位置为第一个比当前位小的数,然后后面的数取数组最大值
ans = ans.substr(0,i);
ans += char(nums[p-1] + '0');
for (int j = i + 1; j < len; ++j)ans += char(nums.back() + '0');
break;
}
else {//没有的话,不断回退往前找到符合的数
for (int j = i - 1; j >= 0; --j) {
int q = getpos(nums, s[j]-'0');
if(q>0){
ans = ans.substr(0, j);
ans += char(nums[q-1]+'0');
for (int k = j + 1; k < len; ++k)ans += char(nums.back() + '0');
return stoi(ans);
}
if (q == 0 && j == 0) {//在j==0的时候还没找到,那么把第一位去掉,剩下均取数组中最大的数
ans = "";
for(int k=0;k<len-1;++k)ans+= char(nums.back() + '0');
return stoi(ans);
}
}
}
}
}
return stoi(ans);
}
int main()
{
vector<int>vec{1,2,4,9 };
cout << getn(vec, 12049) << endl;//测试1
vector<int>vec1{2,4,9 };
cout << getn(vec1, 12049) << endl;//测试2
cout << getn(vec1, 23121) << endl;//测试3
return 0;
}