【座右铭】1. 想要成为行家,就必须尝试解决大量的问题;
2. 解决大量问题并不代表能解决所有问题,而是表示解决下一个问题的几率变大了
1. 已知一个整数集合T,集合中可以包括0到9之间任意数,集合中数字不重复。现在给出一个整数N,大小按int类型,算法要求是:从上面集合中取出数字所能组成的整数中,比给出的N大的集合里面, 最小的那个整数。比如,整数集合T=『1,2,3』,整数N=300,那么要从集合中取出数字所组成的整数应该是311;再如:T=『1』,N=56,那么要得到的整数应该是111(也就是说集合里面的 数可以取多次);【问题来源于论坛】
第一部分:
思路一: 从小到大遍历[N+1, IntegerMax],找出满足所有数字在集合T中的第一个整数
思路二:对整数N,从N的最高位向最低位扫描,求出满足条件的整数M
1)若Ni位不是最后1位,且在集合T中出现,则Mi=Ni
2)若Ni位是最后1位,或者不在集合T中出现,则
2.1) 若集合T中存在大于Ni且最小的数字a,让Mi=a。然后让余下的位置(比i位要低的位置)都取T中的最小值
2.2) 若集合T中不存在大于Ni的数字,则对Mi-1位进行处理。找出比Mi-1位数字大的且在集合T中的元素,若Mi-1位仍不满足,则继续前进找Mi-2位,直到满足条件为止(最坏情况下多补1个最高位)。然后将余下的位置(比满足条件的位置要低的位置)都取T中的最小值
第二部分:
//java代码,T为集合,len为集合T中元素个数,N为整数
//不考虑异常情况:例如N为负数,或者是整数最大值
public static int greater(int[] T, int len, int N)
{
//初始化集合T
boolean[] set = new boolean[10];
int min = 10;
for(int i=0;i<len;i++)
{
min = (min>T[i])? T[i]:min;
set[T[i]] = true;
}
//初始化Ai
final int IntegerLen = 11;
int[] source = new int[IntegerLen];
int j = 0;
if(N==0)
{
source[j++] = 0;
}else
{
while(N>0)
{
source[j++] = N%10;
N /= 10;
}
}
j--;
int[] target = new int[IntegerLen];
int k = 1; //预留一位
while(j>=0)
{
if(j!=0&&set[source[j]])
{
//若Ni位在集合T中存在,则Mi=Ni
target[k++] = source[j];
j--;
}else
{
//在集合T中选取一个比Ni大且最小的数字
int bigger = -1;
for(int p=source[j]+1;p<10;p++)
{
if(set[p])
{
bigger = p;
break;
}
}
if(bigger!=-1) //找到
{
target[k++] = bigger;
j--;
}else //未找到
{
int dis = k;
k--;
boolean flag = false;
while(!flag)
{
for(int p=target[k]+1;p<10;p++)
{
if(set[p])
{
flag = true;
target[k++] = p;
break;
}
}
if(!flag)
{
k--;
}
}
j += (dis - k);
}
//后面的数都取集合T中的最小值
while(j-->=0)
{
target[k++] = min;
}
}
}
//组成新的数字
int M = target[0];
int position = 0;
while(++position<k)
{
M *= 10;
M += target[position];
}
return M;
}
第三部分: 测试用例
T = {9,2,3}, N = 0: M = 2
T = {1,2,3}, N = 2: M = 3
T = {1,2,3}, N = 4: M = 11
T = {1,2,3}, N = 23: M = 31
T = {1,2,3}, N = 33: M = 111
T = {1,2,3,9}, N = 9999: M = 11111
2. 有这样一种编码:如,N=134,M=f(N)=143,N=020,M=fun(N)=101,其中N和M的位数一样,N,M可以均可以以0开头,N,M的各位数之和要相等,即1+3+4=1+4+3,且M是大于N中最小的一个,现在求这样的序列S,N为一个定值,其中S(0)=N,S(1)=fun(N),S(2)=fun(S(1))。【问题来源于v_JULY_v的博客:http://blog.csdn.net/v_july_v/article/details/6855788】
第一部分:
思路一: 从小到大遍历[N+1, IntegerMax],找出满足数字和相同的第一个整数
思路二:从低位往高位扫描
1)从低位往高位扫描,找出第一位大于0的位数i的数字a,将该位赋值0,将未分配的数字和T加上a-1,即T=T+a-1。将第i-1位(比i位高1位)数字b加1
1.1)若第i-1位的数字b<10,进入第2步
1.2)若第i-1位的数字b=10,则将该位赋值0,且T=T+9;将第i-2位数字c加1。直至找到满足条件的位置(最坏情况下多增加1位),进入第2步
2)将T从最低位向高位分配,直至T=0。分配原则为:小于等于9,全部放在当前配置;大于9,给当前位置放9
第二部分:
//java代码,参数说明:N为整数
//不考虑异常情况:如N负数,或者为0
public static int next(int N)
{
//求出数字和
final int IntegerLen = 10;
int[] source = new int[IntegerLen];
int i = 0, sum = 0;
while(N>0)
{
source[i] = N%10;
sum += source[i];
i++;
N /= 10;
}
//从地位向高位走
int j = 0;
while(source[j]==0)
{
j++;
}
//把高1位的位置加1
int total = source[j]-1;
source[j] = 0;
j++;
while(true)
{
if(source[j]==9)
{
source[j++] = 0;
total += 9;
}else
{
source[j]++;
break;
}
}
//将数从地位向高位分配
int k = 0;
while(total!=0)
{
if(total<=9)
{
source[k] = total;
total = 0;
}else
{
source[k++] = 9;
total -= 9;
}
}
//组合新数字
int M = 0;
for(int p=IntegerLen-1;p>=0;p--)
{
M *= 10;
M += source[p];
}
return M;
}
第三部分:测试用例
N = 1: M = 10
N = 10: M = 100;
N = 20: M = 101;
N = 101: M = 110;
N = 110: M = 200;
N = 99: M = 189