活跃农民
- 积分
- 427
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2018-8-4
- 最后登录
- 1970-1-1
|
3.19 做题
388. Longest Absolute File Path. 这个题目的思路是这样,首先要把文件/文件夹的名字从给定字符串中提取出来,这时就需要使用“\n”来分割给定字符串、生成一个String Array;然后发现即使这么做以后,Array中的每一个String仍然有“\t”,那么这个“\t”就代表了当前文件/文件夹的级别,没有\t就说明是dir,有几个\t就说明这处在第几层;那么这里实际上是需要进行定位,对于每一个文件/文件夹都要定位它的父文件夹、父父文件夹这样,那这当然不是在这个Array中单纯往前找就可以找到的,因此这里使用了一个Stack作为辅助;Stack存储的,就是当前这个文件/文件夹所存在的目录路径的从一开始的整体长度,而stack的每一个元素都是一个文件/文件夹的绝对路径长度;维护stack的方法就是(stack有一个0元素作为最下面的元素),每一次遍历到一个array中的string后,先检查它拥有的tab个数,然后算出它的层级,如果这个string的层级比stack的size要小,那就说明现在这个string代表的文件/文件夹相对于stack存储的最上面的那个数字代表的文件/文件夹后退了,那么stack就应该持续地poll,也就是相当于后退的操作,知道stack的size和当前string的层级相同,这就意味着stack顶的数字代表的文件夹,就是当前string代表的文件/文件夹的父文件夹;那么这时只需要获取到当前string的长度,加上stack顶的长度,再减去当前string的tab数量,再加1(表示中间的/分隔符),就表示当前string代表的文件/文件夹的绝对路径长度了;那么如果当前string拥有"."的话,就说明这是个文件,那就可以和全局最大进行比较更新了
394. Decode String. 这是一个String的解码题,给定一个编码好的String,编码的方式就是这样k[encoded_string],也就是比如可能给定的String是这样“3 [ 2 a b [ a b 3 [ a b c 4 [ a b ] ] 2 [ a ] a b c d ] 5 [ a b ] e f ] g h”,意思就是说,k代表后面的括号内圈定的字符串的重复次数,很容易理解;那么具体在做的时候,肯定是需要从左到右遍历给定字符串的每一个字符的,那么就会遇到四种情况,也就是数字、左括号、字符、右括号;当遇到数字时,就进行统计这个数字到底数值为多少即可,比如现在是325[ab]的话,扫描到了3,那么统计方式就应该是k = k * 10 + c - ‘0’;如果遇到的是字母的话,那当然就应该有一个StringBuilder去append这一串字母;问题在于左括号和右括号分别代表什么;左括号就代表,当前统计完毕了一个数字,而这个数字之前可能还会有已经构建完毕的StringBuilder,因为括号可能是一层套一层,从左到右并不一定是左右括号交替出现的,就比如这种情况“3 [ a b c 4 [ a b ] ] ”,从左到右的话,先是构建abc,然后计数了4,然后紧接着又出现了一个左括号;而左括号的后面,就需要开始构建新的StringBuilder,当染也有可能需要重新开始计数,这就比如这种情况“2 a b [ a b 3 [ a b c 4 [ a b ] ] 2 [ a ] a b c d ]”,第一个左括号后面首先要构建ab,然后计数3;那么遇到左括号的话,既然前后都可能会有构建StringBuilder的需求和计数的需求,那就应该把左括号之前构建好的StringBuilder和计数完毕的数字,各自放到一个Stack当中先保存下来,然后把全局的StringBuilder和全局的计数归零,用来构建左括号后面的需求;而如果遇到右括号的时候,简单来看就意味着一个StringBuilder构建完毕了,但同样也意味着,这组括号结束了而它前面的k应该生效了,也就是说decode string的过程中,现在应该根据k去重复构建这个String了;那么就比如对于这种情况来说“2 a b [ a b 3 [ a b c 4 [ a b ] ] 2 [ a ] a b c d ]”,当遇到的是4 [ a b ]的这个右括号,现在全局计数是0,而全局StringBuilder则是ab,而这组括号的左括号之前的4和abc都已经被放到各自的stack当中了,因此就应该从stack中把4和abc拿出来,首先根据4重复ab,然后再把重复获取到的string给append到abc的后面;也就是说遇到右括号,就说明现在应该完成一组构建了,也就是decode的过程;在这个题目中,需要维护的是一个全局的计数和全局的StringBuilder,全局计数其实无所谓,因此计数完毕以后,往后走肯定是直接左括号(否则就失去了计数的意义),因此计数完毕后肯定就直接加到stack当中了;但是对于全局StringBuilder来说,当构建完毕一个以后,它后面可能遇到的是数字,也可能遇到的是右括号;如果遇到数字的话,意味着马上要遇到左括号,那么也会驾到stack中;而如果遇到的是右括号,就意味着这个StringBuilder需要重复然后加到从stack中取出的StringBuilder后面,这时,当加完以后,这个全局的StringBuilder应该保存的就是这个加完的结果,那么这时再往后的话,对于一个右括号来说,后面可能是数字、可能是字母、也可能仍然是右括号;如果是数字的话,这个全局的StringBuilder也就不要动了,直接等着数字后面的左括号、然后一起加到stack中即可;如果是字母,那这组字母肯定不需要重复,那直接加到这个全局SB后面就可以;如果仍然是右括号的话,就说明有一组括号结束了,那么这个全局的StringBuilder就又要重复k次,然后加到stack中当前的最顶的StringBuilder后面;也就是说这个题目,遇到左括号加到stack中,遇到右括号从stack中拿出,就像是recursion的往下走和往上返的过程,因为括号都是完美对称的,所以一个全局的StringBuilder,按照上面的方式,肯定会最终存储所有decode后的String的
224. Basic Calculator. 这个题目和之前的decode string一样,要理解遍历给定String过程中,遇到什么样的字符需要做什么样的事情,同时要搞清楚全局维护的都应该是哪些变量;这里全局维护了一个sign、一个res、一个num、以及一个stack,res是全局结果,num是每一次统计到的数字、sign是当前应该计算的是+还是-;如果遇到数字,那么就更新num;如果遇到+或-的运算符号,那么就说明前面的数字扫描完了,扫描完了就要加到结果当中去,而当前的sign(注意不是现在扫描到的符号)正好就一定是扫描完的数字的前面的符号,因此用这个sign乘扫描完的数字,就可以加到结果中去了,然后再根据现在扫描到的符号更新sign,同时num归零;如果遇到括号的话就应该注意;如果是左括号,那么左括号前面一定是符号,也就是说现在的num已经归零,而sign存储着这个符号,res则存储着现在已经获取到的结果;而左括号后面一定是一个独立的表达式,也就是先是数字然后又是符号,那么sign现在存储的符号肯定不能直接作用于这个左括号后面的数字,而是作用于这组括号整体的,res也是,不能直接用sign和这个数字相乘;因此出现左括号就意味着要另起炉灶,重新开始计数num、获取sign、加和res了,那么现在已经有的sign和res就要放到stack当中进行存储,先放res再放sign,然后进行重制;那么左括号后面的数字和符号处理方式和之前的一样,接下来就会遇到右括号;遇到右括号就意味着这一组括号内部的表达式扫描完毕了,而右括号前面的一定是数字,因此这个num就应该乘它前面的sign然后加到res当中去,这样这组括号内部的表达式的值就处理完毕了,然后要做的就是把这个值也就是当前的res和这组括号之前的加起来,也就是说,要重新获取到这组括号之前的符号和res,也就是已经存储到stack当中的,因此先poll出来之前的sign,再poll出来之前的res,用prev_sign乘当前的res,再加到prev_res上即可;那么最后结束循环时,可能还是会遇到一个扫描的数字,因此在最后获取到num,再乘sign加到res即可,最后返回res
227. Basic Calculator II. 这个题目是给定一个表示四则运算的表达式String,没有括号;注意的就是calculator的符号滞后性,即每当扫描到一个符号的时候,当前的sign变量总是存储着前一个符号、而num变量总是存储着当前扫描到符号的前一个数字,滞后性就是说,每当扫描到一个符号,应该运算的总是前一个符号和前一个数字,运算完毕后,再把num归零、用sign记录当前符号;另外calculator的stack,这里应该存储的就是每次运算完毕的数字,也就是每次遇到符号时进行计算前一个数字和符号的结果需要offer到stack当中;具体来说,每当扫描到数字时,那就加到num里面去;每当扫描到符号时,就说明前面扫描的num已经构建完毕,同时当前的sign变量存储的是构建完毕的num之前的那个符号,那么如果是+或-的话,直接把当前构建的num乘1或-1,添加到stack中;而如果是*或/的话,考虑到运算优先级,这里就不仅仅需要当前的num和当前的sign了,还需要这个sign更前面的那个数字,也就是之前被offer到stack中的那个prev_num,因此就要把这个prev_num给poll出来,和当前的num进行*或/运算,获取到结果之后再offer进stack中;注意如果当前扫描到最后一个的时候,最后一个一定是num,而且前面还有一个符号sign,因此如果扫描的是最后一位,就需要和遇到符号的情况一起处理;因此如果遇到符号或者扫描到最后一位,就需要进行总结计算,把num和sign的结果放到stack当中;扫描完毕后,从stack中一个一个取出结果,相加即可,因为在之前遇到符号的时候,总是乘1或-1,或者如果有*或/的情况就会已经运算完毕,因此最后简单相加即可
385. Mini Parser. 这个题目本质上讲还是扫描String然后对不同情况下的字符进行分类讨论,而如果遇到括号一类的特殊字符,就需要往下走或向上返,并用一个stack来进行模拟;需要维护一个stack来存储往下走时上一层的NestedInteger,维护一个cur来保存当前层的NestedInteger,每当一层扫描完毕之后,当前的cur就应该加入到上一层的NestedInteger、也就是需要从stack中poll出来,并且返回上一层、也就是需要更新cur回上一层,因此这个题目和decode string以及basic calculator带括号的很相似;当遇到左括号的时候,说明要往下走一层,因此表示当前层的cur就需要被添加到stack当中去,然后cur归零准备下一层;当遇到右括号的时候,说明当前层的一个integer扫描完毕,需要被添加到当前层的cur当中,当谈也意味着这整个一层都扫描完毕了,要回归上一层,因此就从stack中poll出上一层的NestedInteger,然后把这一层的cur整体添加到上一层的NestedInteger当中,然后由于往上返了回到了上一层,cur记录的也就应该是变成上一层的了;当遇到逗号的时候,前面要么是右括号要么是数字,右括号的情况刚刚已经讨论过了,如果是数字的话,就简单给当前层的cur添加一个数字即可;这里注意如何扫描数字,使用的不再是num = num * 10 + c - '0'了,而是限定了一个left,left只是指向特殊符号的后面,然后和遍历的right进行圈定字符串而已,是另一种方式
|
|