比n小的最大值

该文章介绍了一个使用C++实现的算法,通过贪心策略和回溯方法,从给定的无重复数字数组中找出比整数n小的最大值。首先对数组排序,然后逐位比较n的每一位,尝试找到相等或更小的数字,如果找不到则回溯并尝试更低的位。最后组合成结果并返回。
摘要由CSDN通过智能技术生成

题目:给定一个包含0-9的若干个不重复数字的数组,如{1,2,5}等,求出比n小的最大值。

核心:贪心+回溯

步骤:

  1. 先排序给的nums数组

  2. 将n转化为string

  3. 遍历n,从高位到低位

  4. 当前位的数值如果可以从nums数组中找到,那么【结果集】的对应位上添加这个数字(比较的位数需要比原来的少最低位,因为要保证小于n);当前位的数值如果从nums数组中找不到,那么就找比当前位小且最大的数字,添加到【结果集】中并且跳出整个循环;当前位的数值如果无法在nums数组中找到比它小的数值,即nums数组的值都比当前位要大,那么最高位舍弃,即收缩一位,跳出整个循环;

  5. 最后拼接数字,【结果集】中非0数字就正常计算,如果是0那就选取nums数组的最大值。

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <unordered_set>
using namespace std;

//主要用来查找相同数字
int findEqualNum(const vector<int>& nums, int target)
{
	int left = 0, right = nums.size() - 1;
	while (left <= right)
	{
		int mid = left + ((right - left) >> 1);
		if (nums[mid] < target)
		{
			left = mid + 1;
		}
		else if (nums[mid] > target)
		{
			right = mid - 1;
		}
		else
		{
			return nums[mid];
		}
	}
	return -1;
}

//查找比target小且最大的数字
int findLessNum(const vector<int>& nums, int target)
{
	int left = 0, right = nums.size() - 1;
	while (left < right)
	{
		int mid = left + ((right - left + 1) >> 1);
		if (nums[mid] < target) left = mid;
		else right = mid - 1;
	}
	//数组中所有的数字都比target大
	if (nums[left] > target && left == 0) return -1;
	return nums[left];
}

int getMaxValue(int n, vector<int>& nums)
{
	if (nums.empty()) return -1;

	sort(nums.begin(), nums.end());
	if (nums[0] >= n) return -1;

	string strN = to_string(n);
	vector<int> res(strN.size());
	for (int i = 0; i < strN.size(); ++i)	
	{
		//当前位能够从提供的数组中找到
		if (i < strN.size() - 1 && findEqualNum(nums, strN[i] - '0') != -1)
		{
			res[i] = (strN[i] - '0');
			continue;
		}
		//当前位找不到相等数字,但是能找到比当前位小且最大的数字
		else if (findLessNum(nums, strN[i] - '0') != -1)
		{
			res[i] = findLessNum(nums, strN[i] - '0');
			break;
		}
		//当前位比所有的数字都小
		else
		{
			//回溯
			for (i--; i >= 0; --i)
			{
				int value = findLessNum(nums, strN[i] - '0');
				if (value != -1)
				{
					res[i] = value;
					break;
				}
				res[i] = 0;
			}

			if (i == -1) res.resize(res.size() - 1);
			break;
		}
	}
	//拼接目标数字
	int target = 0;
	for (int i = 0; i < res.size(); ++i)
	{
		int val = res[i];
		if (val > 0)
		{
			target = target * 10 + val;
		}
		else
		{
			target = target * 10 + nums.back();
		}
	}
	return target;
}

int main()
{
	int n = 999;
	vector<int> nums1{ 1,7,9 };
	cout << getMaxValue(n, nums1) << endl;

	vector<int> nums2{ 1,7,9 };
	cout << getMaxValue(2355, nums2) << endl;

	vector<int> nums3{ 2,7,9 };
	cout << getMaxValue(911, nums3) << endl;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值