【算法】输出栈的所有合法输出序列

题目

今天做了一家公司的笔试题,然后第五道题是给了一个栈,然后要把abcde入栈和出栈,顺序随意。
第一小题是给定几个顺序判断是不是合法,这个题简单,判断条件就是每个字母后面比自己小的字母必须降序排列。
第二小题对我来说有一定难度,就是要输出所有的合法输出序列,这个题可能对于经常搞算法的大佬来说不值一提,但是我当时还是想了十分钟才有思路的,而且最后因为牛客网笔试没法调试附带了好几个bug交卷的。

代码和运行结果

交完卷以后因为感觉笔试时候写的代码可能有问题,就寻思再研究一波,然后就把代码重新写了一遍,先粘代码和运行结果,然后说一下我的思路。我的解法不局限“abcde”,可以是大于0的任意长度的字符串。

    public static void main(String[] arg) {
    	//调用示例,字符串长度可以是大于0的任意长度,不一定非得是5
        String str="abcde";
        System.out.println("输入字符串:"+str+"\n输出结果:");
        StackAlg.function(str,0,  new Stack<String>(),"");
    }

    /**
     * 输出栈的所有合法输出序列
     * @param str 要往栈里面加的字符串,例如"abcde”
     * @param count 代表字符串入栈到第几位,默认传0
     * @param stack 传入一个空栈
     * @param res 传入一个“”,用于记录输出
     */
    public static void function(String str, int count, Stack<String> stack, String res) {
        //每次递归先入栈一个
        stack.push(str.substring(count, count + 1));
        count++;
        //入栈完判断,如果全部入栈过了就把剩余的全部出栈,输出结果
        if (count == str.length()) {
            StringBuilder resBuilder = new StringBuilder(res);
            for (int i = 0; stack.size() > 0; ) {
                resBuilder.append(stack.pop());
            }
            res = resBuilder.toString();
            System.out.println(res);
            return;
        }
        //没有全部入栈,把已经入栈的元素分情况输出(n个元素就是n+1种情况,0-n),然后再递归
        for (int i = 0; i <= stack.size(); i++) {
            StringBuilder res1 = new StringBuilder(res);
            Stack<String> stack1 = (Stack<String>) stack.clone();
            for (int j = 0; j < i; j++) {
                res1.append(stack1.pop());
            }
            function(str, count, stack1, res1.toString());
        }

因为之前java写的最多,就用java写的,粘一些运行结果。

输入字符串:a
输出结果:
a

输入字符串:ab
输出结果:
ba
ab

输入字符串:abc
输出结果:
cba
bca
bac
acb
abc

输入字符串:abcd
输出结果:
dcba
cdba
cbda
cbad
bdca
bcda
bcad
badc
bacd
adcb
acdb
acbd
abdc
abcd

输入字符串:abcde
输出结果:
edcba
decba
dceba
dcbea
dcbae
cedba
cdeba
cdbea
cdbae
cbeda
cbdea
cbdae
cbaed
cbade
bedca
bdeca
bdcea
bdcae
bceda
bcdea
bcdae
bcaed
bcade
baedc
badec
badce
baced
bacde
aedcb
adecb
adceb
adcbe
acedb
acdeb
acdbe
acbed
acbde
abedc
abdec
abdce
abced
abcde

思路

先说最重要的,就是我不确定我的思路和算法对不对,因为我没有在力扣上面找到这道题(有人知道可以告我一波),所以没法提交代码验证。我只是看了一下前四次的结果感觉没问题所以就想分享一波,如果有大佬发现我哪里有问题欢迎指出。
这道题刚刚看上去很头大,因为出栈情况不管是时机还是次数都不确定,可以有各种情况,所以感觉很混乱。但是仔细想想会发现,虽然出栈很乱但是入栈是固定的n(n是字符串长度,即可入栈元素数量)次,而出栈就可以看作是附加在入栈之后的操作,只不过有时候次数多(多到全部出栈),有时候次数少(少到一个都不出栈)。
这个时候就发现其实可以把过程分成n次,每次分为三步。

第一步

入栈一次。

第二步

判断是不是全部入栈过了,因为如果全部入栈过了以后,剩下的操作就只能是把栈中剩余的元素全部出栈了。所以到这个时候结果已经确定了,全部出栈并且输出这次的结果。

第三步

如果全部入栈就没有第三步了,到了第三步以后的情况必然是还有一些元素没有入过栈,栈中有k个元素,k至少是1(第一步入的)。
这个时候能做的事情就只有出栈了,很显然出栈只有k+1中情况,就是出栈0-k次。到了这一步就很好写了,做一个二重循环处理这个情况。外重循环是遍历所有可能的情况,因为每种不同的情况其实就已经代表不同的输出了,所以每次都要用现有的栈stack去clone一个新的栈stack1,还要用现有的输出字符串res生成一个新的字符串res1。内重循环就是为了循环出栈,出k个循环k次,不出循环0次。
因为每一次外重循环都意味着一种新的结果,而且还有元素没有入栈。因为每次都是同样的三步,所以可以轻松想到用递归解决问题。这时就把stack1和res1以及传入的str和count一起开始新的递归。

根据上述分析可以发现递归次数就是总共的元素数量,递归n次以后就会在第二步把所有结果输出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值