1270 Unique Digit Number

数位不同的数

题目描述

数位不同的数是指所有数位上的数码都不一样的数,比如“123”三个数码1,2,3,都不一样,所以是数位不同的数;但是“1232”中有两个相同的数码2,所以不是。请写一个程序,计算第几个符合条件的数是什么?

输入

每行输入一个整数n(1≤n≤8877691)。

输出

每行输出一个整数,为对应样例的结果。

样例输入

1
10
100
8877691

样例输出

0
9
120
9876543210

这个题还没过,面向超时编程是我了QWQ,前三个自己想的都超时了就很难受

解法一BFS

因为他要求有序的,我就想到了BFS

import java.util.*;
public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        Long res[] = new Long[8877693];
        Queue<Long> q = new ArrayDeque<Long>();
        q.add(0l);
        res[1]=0l;
        int k = 2;
        while (!q.isEmpty()&&k < 8877693) {
            Long t = q.poll();
            HashSet<Integer> set = new HashSet<Integer>();
            Long qq = t;
            while (qq > 0) {
                set.add((int) (qq % 10));
                qq /= 10;
            }
            for (int i = 0; i < 10; i++) {
                Long e = t * 10 + i;
                if (!set.contains(i) && e > 0)
                {q.add(e);
                res[k++] =e;}
            }
        }
        
        while (in.hasNext()) {
            int n = in.nextInt();
            System.out.println(res[n]);

        }
    }

}

解法二BFS

解法二在解法一的基础上新建了一个类,用来存那个数已有的数码,就不用循环求已有的数码了,但还是超时了

import java.util.*;

class Obj {
    Long num;
    TreeSet<Integer> set;

    public Obj(Long num, TreeSet<Integer> set) {
        this.num = num;
        this.set = set;
    }
}

public class Main{
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        Long res[] = new Long[8877693];
        Queue<Obj> q = new ArrayDeque<Obj>();
        TreeSet<Integer> ss = new TreeSet<Integer>(Arrays.asList(0,1, 2, 3, 4, 5, 6, 7, 8, 9));
        Obj o = new Obj(0l, ss);
        q.add(o);
        res[1] = 0l;
        int k = 2;
        while (!q.isEmpty() && k < 8877693) {
            Obj t = q.poll();
            TreeSet<Integer> set = new TreeSet<Integer>(t.set);

            for (Integer i : t.set) {
                Long e = t.num * 10 + i;
                if (e > 0) {
                    set.remove(i);
                    q.add(new Obj(e, (TreeSet<Integer>) set.clone()));
                    res[k++] = e;
                    set.add(i);
                }
            }
        }
    
        while (in.hasNext()) {
            int n = in.nextInt();
            System.out.println(res[n]);

        }
    }

}

解法三DFS+回溯

搜索出所有结果在排序

import java.util.*;

public class  Main {
 static Long res[] = new Long[8877691];
     static int k = 0;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);

        boolean[] visited = new boolean[10];
        for (int i = 0; i < visited.length; i++) {
            visited[i] = true;
            res[k++] = (long) i;
            dfs((long) i, visited);
            visited[i] = false;

        }
        Arrays.sort(res);
        for (int i = 0; i < 100; i++) {
            System.out.println(res[i]);
        }
        while (in.hasNext()) {
            int n = in.nextInt();
            System.out.println(res[n-1]);

        }
    }

    private static void dfs(Long i, boolean[] visited) {
        // TODO Auto-generated method stub
        if (i > 9876543210l)
            return;
        for (int j = 0; j < visited.length; j++) {
            if (!visited[j]) {
                long t = i * 10 + j;
                if (t > 9) {
                    visited[j] = true;
                    res[k++] = t;
                    dfs(t, visited);
                    visited[j] = false;
                }

            }
        }

    }

}

解法四 数位DP

贴一个别人的解法,是本菜狗看不懂的了,以后慢慢啃

#include<stdio.h>
__int64 a[9000000];
int t[9000000];  //不看t的值,t用来标记,记录独特数占了哪些位 也就是用了哪个数
int main()
{
    int i,j;
    int num=1;
    for(i= 1;i<10;i++)
    {
        a[num] = i;
        t[num] =t[num]|(1<<i);
        num++;
    }
    for(i=1;i<num;i++)//num==10 
    {
        for(j=0;j<10;j++)
        { 
            if((1<<j) & ~t[i])//~是按位取反.  
            {
                a[num]=a[i]*10+j;
                t[num]=t[i]|(1<<j);
                num++;
            }
        }
    }
    while(scanf("%d",&i)!=EOF)
        printf("%I64d\n",a[i-1]);
}

posted @ 2021-06-12 15:37  sellun  阅读(326)  评论(0编辑  收藏  举报