面试题:从1, 2, 3, 4, 5五个数字中能找出多少个每位数字都不同的三位数?

前言

前几天看到了一道简单的面试题,从5个数字中找出所有每位数字都不同的三位数的数量并且一一输出。从数学上来讲,算出数量比较简单,只是一个排列的计算。比如这道题的计算方法就是P(5,3) = 60。输出的过程也比较简单,这里提出两种方法:

正文

方法一:

一种通俗易懂的方法。用三个for循环,第一个for循环遍历所有的数字,第二个循环遍历除了第一个数字之外的所有数字,第三个循环遍历除了前两个数字之外的所有数字。然后输出就可以了。具体实现代码如下:

public class Number {

    public static final int []num = {1, 2, 3, 4, 5};
    public static int count = 0;
    public static void main(String[] args) {
        calculate(num);
        System.out.println("总数为" + count);
    }

    public static void calculate(int []arr){
        for(int i=0; i<arr.length; i++)
        {
            for(int j=0; j<arr.length; j++)
            {
                if(j!=i)
                {
                    for(int k=0; k<arr.length; k++)
                    {
                        if(k!=i && k!=j){
                            count++;
                            System.out.println("第" + count + "个数为: " + arr[i] + "" + arr[j] + "" + arr[k]);
                        }
                    }
                }
            }
        }
    }

}

下面是程序的输出

第1个数为: 123
第2个数为: 124
第3个数为: 125
第4个数为: 132
第5个数为: 134
第6个数为: 135
第7个数为: 142
第8个数为: 143
第9个数为: 145
第10个数为: 152
第11个数为: 153
第12个数为: 154
第13个数为: 213
第14个数为: 214
第15个数为: 215
第16个数为: 231
第17个数为: 234
第18个数为: 235
第19个数为: 241
第20个数为: 243
第21个数为: 245
第22个数为: 251
第23个数为: 253
第24个数为: 254
第25个数为: 312
第26个数为: 314
第27个数为: 315
第28个数为: 321
第29个数为: 324
第30个数为: 325
第31个数为: 341
第32个数为: 342
第33个数为: 345
第34个数为: 351
第35个数为: 352
第36个数为: 354
第37个数为: 412
第38个数为: 413
第39个数为: 415
第40个数为: 421
第41个数为: 423
第42个数为: 425
第43个数为: 431
第44个数为: 432
第45个数为: 435
第46个数为: 451
第47个数为: 452
第48个数为: 453
第49个数为: 512
第50个数为: 513
第51个数为: 514
第52个数为: 521
第53个数为: 523
第54个数为: 524
第55个数为: 531
第56个数为: 532
第57个数为: 534
第58个数为: 541
第59个数为: 542
第60个数为: 543
总数为60

这种方式使用了三个for循环,并不是太好。因为假如题目的条件变为从10个不同的数字中找出不同的5位数,那么就需要写五个for循环。要找出的数字位数越多,就需要写越多的循环。总之,这不是一个一般性的解法,对于不同的题目条件,要写出不同的循环数量,不具有统一性。如果从遍历数的角度来看,这是一种“深度优先搜索”策略。

方法二

从题目的条件看,这是一个很典型的遍历树的问题。我们也可以使用“广度优先搜索”算法来解决这道题。下面是代码:

import java.util.Stack;

public class Num {
    public static final Stack<String> stack = new Stack<String>();
    public static final int goalDigits = 3;
    public static final int []num = {1, 2, 3, 4, 5};
    public static int totalNum = 0;

    public static void main(String[] args) {
        for(int i : num){
            numS(i);
        }
        System.out.println("总数为" + totalNum);
    }

    public static void numS(int i){
        stack.push(i + "");
        while(!stack.isEmpty()){
            String iString  = stack.pop();
            if(isGoal(iString)){
                totalNum++;
                System.out.println("第" + totalNum + "个数字为: " + Integer.parseInt(iString));
                continue;
            }
            for(int j : num){
                if(!iString.contains(j + ""))
                    stack.push(iString + j + "");
            }
        }
    }

    public static boolean isGoal(String s){
        return s.length() == goalDigits;
    }

}

这里用到了一个数据结构,栈(stack)。基本的算法就是,对于数组中的每个元素,都把它当做一个树的根节点(即push,入栈操作),接着把这个子节点pop出来,然后对于数组中的所有其他元素,都当做这个根节点的子节点(push操作)。这时栈内的元素都是两位数。然后再依次把这些节点pop出来,再寻找数组中不与这个两位数相同的所有元素,再继续入栈,以此类推。这样,当栈内所有元素都被pop出来,即栈为空的时候,就是这棵树被遍历完成的时候。我们可以看到,树的数量就是元素的数量。有5个元素,就要遍历5棵树。遍历的时候,如果正好pop出了一个三位数(就是我们的目标之一),我们就可以跳出当前循环。
以下是程序的输出:

第1个数字为: 154
第2个数字为: 153
第3个数字为: 152
第4个数字为: 145
第5个数字为: 143
第6个数字为: 142
第7个数字为: 135
第8个数字为: 134
第9个数字为: 132
第10个数字为: 125
第11个数字为: 124
第12个数字为: 123
第13个数字为: 254
第14个数字为: 253
第15个数字为: 251
第16个数字为: 245
第17个数字为: 243
第18个数字为: 241
第19个数字为: 235
第20个数字为: 234
第21个数字为: 231
第22个数字为: 215
第23个数字为: 214
第24个数字为: 213
第25个数字为: 354
第26个数字为: 352
第27个数字为: 351
第28个数字为: 345
第29个数字为: 342
第30个数字为: 341
第31个数字为: 325
第32个数字为: 324
第33个数字为: 321
第34个数字为: 315
第35个数字为: 314
第36个数字为: 312
第37个数字为: 453
第38个数字为: 452
第39个数字为: 451
第40个数字为: 435
第41个数字为: 432
第42个数字为: 431
第43个数字为: 425
第44个数字为: 423
第45个数字为: 421
第46个数字为: 415
第47个数字为: 413
第48个数字为: 412
第49个数字为: 543
第50个数字为: 542
第51个数字为: 541
第52个数字为: 534
第53个数字为: 532
第54个数字为: 531
第55个数字为: 524
第56个数字为: 523
第57个数字为: 521
第58个数字为: 514
第59个数字为: 513
第60个数字为: 512
总数为60

对于不同的题目条件,我们只要修改goalDigits这个变量就可以了。

当然,深度优先搜索的策略也可以用stack的数据结构实现,实现方式和广度优先搜索差异不大,只是遍历树的方式由横向改为纵向。

时间: 2024-10-02 19:15:37

面试题:从1, 2, 3, 4, 5五个数字中能找出多少个每位数字都不同的三位数?的相关文章

[经典面试题][百度]在由N个正整数的集合S中,找出最大元素C,满足C=A + B

[题目] 在由N个正整数的集合S中,找出最大元素C,满足C=A + B 其中A,B都是集合S中元素,请给出算法描述,代码与时间复杂度分析. [分析] 1,对集合S进行排序(快排),从小到大排序2,让C指向集合最后一个元素(最大元素)3,让i指向S中第一个元素,让j指向C的前一个元素4,如果,A[i]+A[j]==C则return C;5,如果if(A[i]+A[j]<C)则i++;6,如果if(A[i]+A[j]>C)则j--;7,直道i>=j依然没有找到符合条件的元素,则C在S中向前移

微软面试题:写程序找出二叉树的深度

一个树的深度等于max(左子树深度,右子树深度)+1.可以使用递归实现. int DepthOfTree(BiTreeNode* root) { if(NULL == root) { return 0; } return max(DepthOfTree(root->leftChild), DepthOfTree(root->rightChild))+1; } 也可以采用下面的思路: 类似于递归的先序遍历,层层向下计算,每向下计算一层,深度                   就加1,CalTr

2011蓝桥杯【初赛试题】神秘的三位数

神秘的三位数 有这样一个3位数,组成它的3个数字阶乘之和正好等于它本身.即:abc = a! + b! + c! 下面的程序用于搜索这样的3位数.请补全缺失的代码. int JC[] = {1,1,2,6,24,120,720,5040,40320,362880}; //开了一个JC的数组用来存取1至9的阶乘,省去了下面的运算,节省了时间 int i; for(i=100; i<1000; i++) { int sum = 0; int x = i; while(x!=0)//补全的代码(把x的

华为面试题答案找出最大长度子字符串_C 语言

复制代码 代码如下: int findMaxSubstring(char* str){    int maxLength = 0;    int maxStartIndex = 0;    int curLength = 0;    int curStartIndex = 0;    bool isFind = 0;    for(unsigned int i = 0;i<strlen(str);i++)    {        if(str[i] >= 'a' && str[

一些面试题,整理自网络,就不一一帖原址了

腾讯面试题:tcp三次握手的过程,accept发生在三次握手哪个阶段? 答accept发生在三次握手之后. 第一次握手:客户端发送syn包(syn=j)到服务器. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k). 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1). 三次握手完成后,客户端和服务器就建立了tcp连接.这时可以调用accept函数获得此连接.   const的含义及实现机制,比

教你如何迅速秒杀掉:99%的海量数据处理面试题

作者:July 出处:结构之法算法之道blog   前言    一般而言,标题含有"秒杀","99%","史上最全/最强"等词汇的往往都脱不了哗众取宠之嫌,但进一步来讲,如果读者读罢此文,却无任何收获,那么,我也甘愿背负这样的罪名,:-),同时,此文可以看做是对这篇文章:十道海量数据处理面试题与十个方法大总结的一般抽象性总结.     毕竟受文章和理论之限,本文将摒弃绝大部分的细节,只谈方法/模式论,且注重用最通俗最直白的语言阐述相关问题.最后,

经典算法(12) 数组中只出现1次的两个数字(百度面试题)

首先来看题目要求: 在一个数组中除两个数字只出现1次外,其它数字都出现了2次, 要求尽快找 出这两个数字. 考虑下这个题目的简化版--数组中除一个数字只出现1次外,其它数字都成对出现 ,要求尽快找出这个数字.这个题目在之前的<位操作基础篇之位操作全面总结>中的"位操作趣味应用" 中就已经给出解答了.根据异或运算的特点,直接异或一次就可以找出这个数字. 现在数组中有两个 数字只出现1次,直接异或一次只能得到这两个数字的异或结果,但光从这个结果肯定无法得到这个两个数字 .因此我

十七道海量数据处理面试题与Bit-map详解

作者:小桥流水,redfox66,July.   前言     本博客内曾经整理过有关海量数据处理的10道面试题(十道海量数据处理面试题与十个方法大总结),此次除了重复了之前的10道面试题之后,重新多整理了7道.仅作各位参考,不作它用.     同时,程序员编程艺术系列将重新开始创作,第十一章以后的部分题目来源将取自下文中的17道海量数据处理的面试题.因为,我们觉得,下文的每一道面试题都值得重新思考,重新深究与学习.再者,编程艺术系列的前十章也是这么来的.若您有任何问题或建议,欢迎不吝指正.谢谢

数据结构与算法面试题80道

1.把二元查找树转变成排序的双向链表  题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. 要求不能创建任何新的结点,只调整指针的指向.    10  / \  6 14  / \ / \ 4 8 12 16  转换成双向链表 4=6=8=10=12=14=16.    首先我们定义的二元查找树 节点的数据结构如下:  struct BSTreeNode {  int m_nValue; // value of node  BSTreeNode *m_pLeft; // lef