面试题----寻找比一个N位数大的“下”一个数

时间:2022-03-16 19:17:55
  1. 题目描述

写出一个算法,实现如下功能:

给定一个N位数字组成的数,找出比这个数大的由相同数字组成的下一个数

例如:如果数字为 25468, 则结果为25486 如果数字为 21765, 则结果为 25167 如果数字为 54321, 则结果为 54321 (因为没有比这个数大的相同数字组成的值)

2.问题分析

  • 因为N是一个没有范围的数,因此在解决此题时排出用N-位整数作为输入,而是用字符串来处理
  • 若存在有连续数字是相同的应该如何处理?
  • 观察例子可以得到如下思路

一个N数如83557761,从右往左,找到当前位置上的数比它左边的数大为止(相等也要继续),即找到左边第一个7,比5大,得到7761,逆序为1677,然后从左往右找到第一个比5大的数6,交换5和6,即得到83561577。

3.此算法一般性讲解

把N位数分为两部分前i位和后N-i位,其中后N-i位从右往左是不减的(要么递增,要么相等),因此,不管怎样调这N-i,数都不会增大。按前面的分法,第i位一定比第i+1位小,也可能比第i+2位小,以此类推,找到第i+j位数,它比第i位数大,但是第i+j+1位数比第i位数小,交换第i位和第i+j位,然后提取i+1到第i+j-1这部分数字和第i+j+1到第N位的数字,这两部分分别逆序之后交换位置放置即可。结合例子可以理解。

4.代码和注释

 #include<iostream>
#include<string>
#include <algorithm>
using namespace std; int main()
{
string digit;
cin >> digit; int len,i,j;
len = digit.length();
//N<=1直接输出
if(len <= )
{
cout << digit<<endl;
return ;
}
//当digit中有连续的相同数字,在从右到左遍历时仍然继续遍历
for(i=len-;i>=;i--)
if(digit[i]>digit[i-])break; //digit从右到左都是不减的,则不用调整
if(i==)
{
cout << digit<<endl;
return ;
}
//提取前i位
string pre = digit.substr(,i);
//提取后N-i位
string end = digit.substr(i,len-i); reverse(end.begin(), end.end()); //逆序 int index = pre.length();
int num =pre[index-];
for(j=;j<end.length();j++)
if(end[j]>=num)break; //交换第i位和第i+j位
pre[index-] = end[j];
end[j]=num; digit = pre+end;//合并即可 cout<<digit<<endl;
return ;
}