The String |

纠结了半天先string 还是先 linked list。。。还是决定先string 了。 java使用时间比较短,以前极度喜欢python,在处理string上更不用说了。 但是为了面试需要,忍痛割爱。。。而去python3 的推广也不顺利,前景没有以前那么好了,还是要熟练java的啊! string的题目有40几道,看难度集中在18 - 27 属于中等偏难题目。 加油 ! Fight on!

Integer to Roman : **

题目不能理解,但是很难想出来。 就当熟悉罗马计数了。 这俩个题都用到了switch 

罗马数字的关键在于 1 , 5 ,10 。  任何一位上的数,都按照一致的规则有该位对应的1 , 5,10 得来。 

题目挺有意思,我个人比较喜欢这个题目。方法不用说 来自大神 code ganker

//Integer to Roman
public class Solution {
    public String intToRoman(int num) {
        int[] digits = new int[4];
        int scale = 1000;
        for(int i=0;i<4;i++){
            digits[i] = num/scale;
            num = num%scale;
            scale = scale/10;
        }
        StringBuilder sb = new StringBuilder();
        sb.append( converter(digits[0] ,'M', ' ',' '));
        sb.append( converter(digits[1] ,'C', 'D','M'));
        sb.append( converter(digits[2] ,'X', 'L','C'));
        sb.append( converter(digits[3] ,'I', 'V','X'));
        return sb.toString();
    }
    
    public String converter(int digit, char one, char five, char ten){
        StringBuilder res = new StringBuilder();
        
        switch(digit){
            case 9:
                res.append(one);
                res.append(ten);
                break;
            case 8:
            case 7:
            case 6:
            case 5:
                res.append(five);
                for(int i= 6;i<=digit;i++){
                    res.append(one);
                }
                break;
            case 4:
                res.append(one);
                res.append(five);
                break;
            case 3:
            case 2:
            case 1:
                for(int i=1;i<=digit;i++){
                    res.append(one);
                }
                break;
            default:
                break;
    }
     return res.toString();   
    }
}

//Roman to Integer

public class Solution {
    public int romanToInt(String s) {
        int res = 0;
        char[] sc = s.toCharArray();
        for(int i=0; i
   
   
    
    0 && ctn(sc[i]) > ctn(sc[i-1])){
                res += (ctn(sc[i]) - 2*ctn(sc[i-1]) );
            }else{
                res += ctn(sc[i]);
            }
        }
        return res;
    }
    
    public int ctn(char c){
        switch(c){
            case 'I' : return 1;
            case 'V' : return 5;
            case 'X' : return 10;
            case 'L' : return 50;
            case 'C' : return 100;
            case 'D' : return 500;
            case 'M' : return 1000;
            default : return 0;
        }
    }
}
   
   


Generate Parentheses : *

这个题目并不难,为数不多的我既能有想法又能实现的。。。

但我在实现时候心血来潮(见代码注释), 传int 参数没有在参数位置 +1 , -1 而是在调用方程前处理的。 这牵扯出来一个严肃的问题   : " 维护现场 "

通常对于 int 或 string DFS中传参是不需要维护的, 前提必须是在参数位置上做改变,否则一样是需要维护的! 注意代码中维护temp string的方法,当然有很多方法,这里是为了强调维护现场,刻意不改变temp指针的内容。

 
public class Solution {
    public List
   
   
    
     generateParenthesis(int n) {
        List
    
    
     
      res = new ArrayList
     
     
      
      ();
        helper(res, "", 0, n, n);
        return res;
    }
    public void helper(List
      
      
       
        res, String temp, int c_l , int l_left, int r_left){
        if(l_left == 0 && r_left == 0){
            res.add(temp);
            return;
        }
        String new_temp;
        if(l_left > 0){
            new_temp = temp + "(";
            //c_l ++;
            //l_left --;
            helper(res,new_temp,c_l+1,l_left-1,r_left);
            //c_l --;
            //l_left ++;
        }
        if(r_left > 0 && c_l > 0){
            new_temp = temp + ")";
            helper(res,new_temp,c_l-1,l_left,r_left-1);
        }
    }
}
      
      
     
     
    
    
   
   

Distinct Subsequences : *** *

brain fuck.... 这道题平心而论,不看答案太难了。看答案我都要理解半天。 第一想法是brute force 用 backtracking。 其实这里就已经暗示DP了

public class Solution {
    public int numDistinct(String s, String t) {
        if(s == null || t == null)
            return 0;
        int[][] dp = new int[s.length()+1][t.length()+1];
        for(int i=0;i
   
   

Edit Distance : ****

这道题目是经典中的经典,论难度不输上一道。

世间万事万物表象千差万别,内在往往有千丝万缕的联系。做算法题,最重要的是俩条 1. 角度  2.联系。角度是外,联系是内,找对了角度才能发现内在联系。 

年初刚刚接触算法题目的时候,觉得recursion好难想啊,又觉得好酷。 当时决定利用暑假写一篇recursion的超级汇总。 也是在那时候决定写一篇dp的汇总。

这个题目结合上一道题目一起我思考了很多,你说dp难在哪? 难在找关系,找一个递推关系,这个关系为毛难找,因为每一个题情景不同,表象纷杂,往往乱人眼目,搞的找不着北。 分析上一题目的时候总结一点,dp的递推关系可以通过recursion来启发,因为上一题目recursion的方法来的更直接。可是这个题,recursion直接毫无想法。想来想去,dp的地推关系也不着边际,有一些似对非对,也不完整。

俩个字符串 matching,subsequence之类的题目,是dp的经典背景,具体问题千差万别,说到家都是二维dp。

抛开具体题目不说,一个二维dp能有几种可能但递推?

| | A|B | |

| | C|T | |

| |    |   | |

1. 既然是递推,肯定推导自之前但信息,那么在二维矩阵里的一个entry,他有多少之前的信息?

T是我们当前要处理的,拥有的是所有T之前的信息。也既是以T为右下角,的左上角矩阵的信息。

2. 既然是递推,肯定是一步一步的推,环环相扣。也就是说推T只要用到T上一环的信息,那就是上一行,上一列,然后能够一步内推到T的。

综上,T只会推导自 A B C 之一,之二,或之三。

Distinct Subsequence 用的是A B

Edit Distance 用的是A B C

这样规律就很明显了,拿到任何一个情景,我们去套入,看看A B C对应什么情景? 是不是在具体题目下make sense? 如果是,那就是,如果不是,就是不是了。

关于如何make sense,这就是表象决定的问题了。同样关于递推关系具体是什么?是求和? 求最小值?这些也是表象决定的问题。


在这俩道题目里还揭示了另一个有价值的通性,T的递推关系不是唯一的,是有判断条件的。拿此题为例,当word[i-1] == word[j-1]时候 dp[i][j] == dp[i-1][j-1];

当不等于到时候,则是另一种递推。这看起来是把问题复杂化了。变得更难概括,但是还是有些规律可循,比如这俩道题,判断但条件都是决定dp[i-1][j-1] 是不是跟dp[i][j]之间有独特的联系。

这种判断条件本身也是表象问题,来自于具体情景分析。但是,不管你怎么判断,推导T就是离不开A B C。 这个判断条件也应该是关于 A T , B T, 或者 CT的

在我这第二轮刷题刷完所有dp之后,会整理一个dp之章。望学有所思,学有所获,学有所成。


public class Solution {
    public int minDistance(String word1, String word2) {
        if(word1 == null && word2 == null)
            return 0;
        if(word1 == null)
            return word2.length();
        if(word2 == null)
            return word1.length();
            
        int[][] dp = new int[word1.length()+1][word2.length()+1];
        for(int i=0;i
    
    

Count and Say : **

这个题不难想,考的是实现。我写了好久才弄对。犯的一个大错误,是在计数重复的时候套用了去重的模版,if(i > 0 && nums[i] == nums[i-1]) ... 这个判断应该是加入第一个后,skip以后所有重复的。 这跟这个题有很大区别,比如 222 这读成 32, 如果按照去重模版,会先加入一个2的,就读成了 1222。 显然这里不是去重,而是计重(计数重复),计数完了再放入。就读成32了。 我的实现用了if里面套while,其实if + continue 也可以。但是关键是 不要跟之前比,要跟之后比,啥时候跟之后不一样了,再去读它。这样坐标的变化也是吻合的,如果按照之前比,其实坐标上会出现edge case,这些都是方法不正确对暗示。

循环中处理重复是一个很基础大技巧,务必掌握。

另外在实现中如果感到问题edge case过多,或者坐标处理上存在一些异常个例(比如头尾需要单独处理之类) 就要马上停止,重新思考,不能盲目的去处理个例,这是浪费时间的。

public class Solution {
    public String countAndSay(int n) {
        char[] seq = {'1'};
        while( n > 1){
            StringBuilder temp = new StringBuilder();
            for(int i=0;i
     
     
      
       1){
            StringBuilder temp = new StringBuilder();
            int count = 1;
            for(int i=0;i
      
      
     
     


Implement strStr()  

这个题目也不难,有一点比较容易犯错,这里强调一下,在原始的haystack中,每一个点都可能成为needle的起点。在第一次做的时候,先从某点扫,发现差异之后,没有回到原始起点的下一点,而是接着扫了,这就导致很多点漏扫。

public class Solution {
    public int strStr(String haystack, String needle) {
        if(haystack == null || needle == null)
            return -1;
        if(needle.length() == 0)
            return 0;
        for(int i=0;i
      
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值