做对了一个类似竞争的问题,但需要帮助来提高效率

Did a competitive-like problem right but need help on improving its efficiency

本文关键字:问题 提高效率 帮助 竞争 一个      更新时间:2023-10-16

问题很简单。我得到 N - 一个数字中的位数,然后是一个数字的 N 位。我需要只做一个数字开关并获得尽可能高的数字。我确实做对了问题(如给出正确的数字(,但它将达到 1 秒的时间限制 afaik。如何提高程序的效率,使其在 N <= 10^6 的情况下达到 1 秒的时间限制。堆栈溢出的新功能,所以告诉我我是否做错了什么 提出问题,以便我可以解决它。谢谢。这是我的解决方案:

主要:

int n;
cin >> n;
int a[n+1];
for(int i=0;i<n;++i)
cin >> a[i];
int maxofarray1;
bool changeHappened=false;
bool thereAreTwoSame=false;
for(int i=0;i<n;++i) //changing the two digits to make the highest number if possible
{
maxofarray1=maxofarray(a,i+1,n);
if(a[i]<maxofarray1)
{
int temp=a[a[n]];
a[a[n]]=a[i];
a[i]=temp;
changeHappened = true;
break;
}
}
for(int i=0;i<n;++i) //need to check if there are two of the same digit so I can change 
//those two making the number the same instead of making it lower
for(int j=i+1;j<n;++j)
if(a[i]==a[j])
{
thereAreTwoSame=true;
break;
}
if(!changeHappened) //if the change has not been yet made, either leaving the number as is 
//(changing two same numbers) or changing the last two to do as little "damage" to the number
{
if(!thereAreTwoSame)
{
int temp=a[n-1];
a[n-1]=a[n-2];
a[n-2]=temp;
}
}
for(int i=0;i<n;++i)
cout << a[i] << " ";
return 0;

最大阵列:

int maxofarray(int a[], int i,int n) //finding the maximum of the array from i to n
{
int max1=0;
int maxind;
for(int j=i;j<n;++j)
{
if(max1<a[j])
{
max1=a[j];
maxind=j;
}
}
a[n]=maxind; //can't return both the index and maximum (without complicating with structs) 
//so I add it as the last element
return max1;
}

代码中的问题是复杂性。我没有完全理解你的算法,但嵌套循环是一个危险信号。与其试图改进代码的零碎部分,不如重新考虑您的整体策略。

让我们首先假设数字9确实出现在数字中。考虑数字是

9...9 c ...9...

其中9...9是全部9的前导数字(可能没有(。我们不能通过交换其中一个来使数字更大。

c是第一个数字!=9,即我们可以放置一个9以获得更大的数字的地方。9是将数字放在这个地方时使数字最大的数字。

最后,...9...表示数字9的最后一次出现,数字表示酸涩。之后9没有其他9出现。当我们通过替换c来增加数字时,替换该9的数字会变小,因此我们必须选择最后一个。

对于一般情况,只需要多走一小步。下面是一个粗略的草图:

std::array<size_t,10> first_non_appearance;
std::array<size_t,10> last_appearance;
size_t n;
std::cin >> n;
std::vector<int> number(n);
for (size_t i=0;i <n;++i) {
std::cin >> a[i];
for (int d=0;d<10;++d) {
// keep track of first and last appearance of each digit
}
}
size_t first = 0;
size_t second = 0;
for (int d=0;d<10;++d) {
// determine biggest digit that appeared and use that
}
std:swap( a[first],a[last] );

它不完整,可能需要处理特殊情况(例如只有一位数字的数字(,但我希望它有所帮助。

PS:您使用的是可变长度数组(int a[n+1];(,这不是标准C++。在C++中,当您只在运行时知道大小时,您应该使用std::vector(当大小已知时,应该使用std::array(。

VLA(可变长度数组(不是标准的。因此,您可能希望使用 STL 数据类型,而不是使用此非标准功能。 给定 N 相当大,您还可以避免堆栈溢出,因为 VLA 是在堆栈上分配的。长度可变的 STL 容器在堆上分配。

然后,正如您自己指出的那样,记住每个数字最后一次出现的索引是有意义的,避免一遍又一遍地搜索掉期候选索引。

你的实现思路基本上是,替换左边的第一个数字,右边有一个更大的替换。

我是这样做的:

static void BigSwap(std::string& digits)
{
int64_t fromRight[10];
size_t ndigitsFound = 0;
for (size_t i = 0; i < 10; i++)
fromRight[i] = -1;
size_t i = digits.size() - 1;
while (ndigitsFound < 10 && i > 0)
{
if (-1 == fromRight[digits[i] - '0'])
{
fromRight[digits[i] - '0'] = static_cast<int64_t>(i);
ndigitsFound++;
}
i--;
}
for (size_t j = 0; j < digits.size(); j++)
{
char d = digits[j] - '0';
for (char k = 9; k > d; k--)
{
if (fromRight[k] != -1 && static_cast<size_t>(fromRight[k]) > j)
{
auto temp = digits[j];
digits[j] = k + '0';
digits[fromRight[k]] = temp;
return;
}
}
}
}