Algorithm 给定一个数字,查找下一个更高的数字,该数字具有唯一的数字0和2

Algorithm 给定一个数字,查找下一个更高的数字,该数字具有唯一的数字0和2,algorithm,Algorithm,这类数字的序列具有唯一的数字,但不包含任何0或2。给您一个编号N,在大于N的序列中查找下一个编号。如果序列中的数字高于10e9,则返回-1 例如:给定2020年,答案是3145,对于1982年,答案是1983,对于9879年,答案是13456 有一个类似的问题:。但是,它们不一样 算法复杂度必须是线性的。时间限制为1秒 我有一个蛮力解决方案,但速度不够快: #include <iostream> #include <vector> using namespace std

这类数字的序列具有唯一的数字,但不包含任何0或2。给您一个编号
N
,在大于
N
的序列中查找下一个编号。如果序列中的数字高于
10e9
,则返回
-1

例如:给定2020年,答案是3145,对于1982年,答案是1983,对于9879年,答案是13456

有一个类似的问题:。但是,它们不一样

算法复杂度必须是线性的。时间限制为1秒

我有一个蛮力解决方案,但速度不够快:

#include <iostream>
#include <vector>

using namespace std;


bool check_year(long year) {
    vector<int> counter(10);

    while(0 < year) {
        counter[year % 10] += 1;
        year = year / 10;
    }

    if(counter[0] > 0 or counter[2] > 0) {
        return false;
    }

    for(int i = 0; i < 10; i++) {
        if(counter[i] > 1) {
            return false;
        }
    }

    return true;
}

int main() {
    int year;
    cin >> year;

    for(long i = year; i < 10e9; i++) {
        if(check_year(i)) {
            cout << i << endl;
            return 0;
        }
    }

    cout << -1 << endl;

    return 0;
}
#包括
#包括
使用名称空间std;
布尔检查年(长年){
向量计数器(10);
而(0<年){
计数器[年份%10]+=1;
年份=年份/10;
}
如果(计数器[0]>0或计数器[2]>0){
返回false;
}
对于(int i=0;i<10;i++){
如果(计数器[i]>1){
返回false;
}
}
返回true;
}
int main(){
国际年;
cin>>年;
对于(长i=年;i<10e9;i++){
如果(检查年份(i)){

我从Reddit那里得到了一个答案:

可以使用dp:define a function在O(9*1024*2*10)中求解 “布尔F(整数i,位掩码d,布尔F)”作为是否为 (i+1)可以使用仍然未使用的数字(已定义)创建数字 通过d)中的未设置位,该值也大于相应的 如果f为false,则为目标编号的后缀(否则为任何此类编号)。 实际上,得到答案意味着只需将最小数字x存储在 每个位置i使得F(i+1,d | 2x,F |(x>目标[i]))为 正确。复发也很简单(在代码中):

#包括
使用名称空间std;
#定义int long long
#定义INF 1000000000000
INTA[10];
int d;
整数ndigits(整数x)
{
int ans=0;
while(x)
{
ans++;
x=x/10;
}
返回ans;
}
内部fxp(内部a、内部b)
{
如果(b==0)返回1;
如果(b==1)返回a;
如果(b%2)返回a*fxp(a*a,b/2);
返回fxp(a*a,b/2);
}
int是_set1(int i,int d)
{
if(d&fxp(2,i))返回1;
返回0;
}
int set1(int i,int d)
{
d=d | fxp(2,i);
返回d;
}
int dp[10][1024][2];;
intf(inti,intd,intf)
{
如果(i>8)返回INF;
如果(dp[i][d][f]!=-1)返回dp[i][d][f];
如果(i==0)
{
int start=(f)?0:a[i]+1;int j;
对于(j=start;ja[i]);
_打印(i-1,set1(x,d),tf);
}
#未定义整数
int main()
#定义int long long
{

对于(inti=0;i我认为不需要动态规划

对于带有
d_i
数字的数字(
d_0
位于左侧)

  • out
    为带有
    e_i
    数字的数字
  • used
    已经使用的一组数字(基本上用0和2初始化)
对于我来说,从0开始,我们可以

  • 尝试将
    d_i
    升级到可用
    e_i
    e_i>d_i
    且未在
    中使用
    )。 如果可以,我们可以自由选择
    e_j(j>i)
    .Idem将
    out
    的末尾填入尚未使用的递增数字
    • 如果
      dui
      是来自
      eku(k
      的一个复制品,则将其升级。如果我们不能,则中止
    • d_i
      保持不变(
      e_i==d_i
      )并转到
      i+1
总之,我们要么将第i位向上并返回数字,要么向前

这将进行8次测试(输入数字的每个数字一次)

const无效=99999999
const concat=(s,d)=>s==0?d:parseInt(“”+s+d,10)
常量添加=(已使用,d)=>新集合([…已使用])。添加(d)
const tryUp=(used,d)=>Array.from({length:10-(d+1)},(u,i)=>i+d+1).find(d=>!used.has(d))
常量填充=(输出,已使用,n)=>{
让last=-1
for(设i=0;i0)),out,used,i)
:错
如果(!okFwd&&!up&&!specialCase){
返回无效
}
const take=up?fillUp(concat(out,up),add(used,up),digits.length-i-1):无效
const fwd=okFwd?nextMin(数字,concat(out,d),add(used,d),i+1):无效
return Math.min(specialCase?specialCase:take,fwd)
}
const minYear=s=>{
常量数字=s.split(“”).map(d=>parseInt(d))
const used=新集合([0,2])
const min=nextMin(数字,0,已用,0)
返回最小值!==无效?最小值:-1
}
console.log(minYear('2020'))
console.log(minYear('1982'))
console.log(minYear('9879'))
console.log(minYear('999'))
console.log(minYear('9999999'))

console.log(minYear('55666'))
a)您没有显示当前的解决方案,也没有说明存在什么问题b)n和n是相同的,或者n算什么?按
O(n)
我的意思是线性时间复杂度,
n
n
是不一样的。但是线性是什么?你的问题一次只涉及一个数字,所以就输入的大小而言它不是线性的,如果它的数字有唯一的数字,那么它最多只能有八个数字长,所以即使它是“线性的数字数”,也就是e和O(8)一样,那么n是什么?好吧,现在我明白了,我错了:
n
n
是一样的,但是常数
c
必须是1/10。@PeteKirkham我更新了问题并提供了时间限制。时间是1秒。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 1000000000000
int a[10];
int d;

int ndigits(int x)
{
  int ans = 0;
  while(x)
  {
      ans++;
      x = x/10;
  }
  return ans;
}

int fxp(int a, int b)
{
  if(b == 0) return 1;
  if(b == 1) return a;
  if(b%2) return a*fxp(a*a, b/2);
  return fxp(a*a, b/2);
}


int is_set1(int i, int d)
{
  if(d&fxp(2,i)) return 1;
  return 0;
}


int set1(int i, int d)
{
  d = d|fxp(2,i);
  return d;
}


int dp[10][1024][2];

int F(int i, int d, int f)
{
  if(i > 8) return INF;
  if(dp[i][d][f] != -1) return dp[i][d][f];

  if(i == 0)
  {
      int start = (f)?0:a[i] + 1; int j;
      for(j = start; j <= 9; j++)
          if(!is_set1(j, d) && j != 2 && j != 0) break;
      if(j == 10) { dp[i][d][f] = INF; return INF; };
      dp[i][d][f] = j; return j;
  }

  dp[i][d][f] = INF;
  int start = (f)?0:a[i];
  for(int x=start; x<=9; x++)
  {
      if(!is_set1(x, d) && x!=2 && x!=0)
      {
          int tf = ( f | (x > a[i]) );
          int t = F(i-1, set1(x, d), tf);
          if(t != INF) dp[i][d][f] = min(dp[i][d][f], x);
      }
  }
  return dp[i][d][f];
}

void the_print(int i, int d, int f)
{
  int x = dp[i][d][f];
  printf("%lld", x);
  if(i == 0) return; 

  int tf = (f | ( x > a[i]) );
  the_print(i-1, set1(x, d), tf);
}




#undef int
int main()
#define int long long
{

  for(int i=0; i<10; i++)
      for(int j=0; j<1024; j++)
          for(int k = 0; k<2; k++)
              dp[i][j][k] = -1;

  int z;
  scanf("%lld", &z);
  if(z == 0)
  {
      printf("1\n"); return 0;
  }
  for(int i=0; i<10; i++)
      a[i] = 0;
  int t = z, j = 0;
  while(t)
  {
      a[j] = t%10;
      t = t/10; 
      j++;
  }

  int b = F(ndigits(z)-1, 0, 0);
  if(b != INF)
  {
      the_print(ndigits(z)-1, 0, 0);
      printf("\n");
      return 0;
  }

  b = F(ndigits(z), 0, 0);
  if(b == INF)
      printf("-1");
  else
  {
      the_print(ndigits(z), 0, 0);
  }
  printf("\n");
  return 0;
}
e.g
used = {3}
d_0 = 2
we can up d_0 to e_0 = 4 (since 3 is used)

used = {7,8,9}
d_0 = 6
we can't up d_0 since the only digits greater than 6 are already used (7,8,9)

e.g
used = {7}
d_2 = 7
d_2 is a dupe since used, we must up it. e_2 = 8