一天十道算法题(day3)

第一题

给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模。
【注意:子序列和子串的区别】

public  class Main {//主类
    public static void main(String args[])throws Exception{
       int [] arr = {1,3,2};
       System.out.println(f(arr,0,arr.length-1));
       System.out.println("the answer is:");
       System.out.println(getDivthree(arr,arr.length));
    }
    //子串的解法
     public static int f(int[] arr,int i,int j){
        if(i==j){
            if(arr[i]%3==0) return 1;
            else return 0;
        }
       /* if(Math.abs(i-j)==1)
        {
            if((arr[i]+arr[j])%3==0)
                return 1;
        }*/
        if(i>j)
            return 0;
        int sum=0;
        for(int k=i;k<=j;k++){
         sum=sum+arr[k];
        }
        if(sum%3==0)
        {return f(arr,i+1,j)+f(arr,i,j-1)-f(arr,i+1,j-1)+1;}
        else {return f(arr,i+1,j)+f(arr,i,j-1)-f(arr,i+1,j-1);}
     }
     //子序列的解法
 public static int getDivthree(int[] arr,int len){
        if(len == 0)
            return 0;
        int[][] temp = new int[len][3];
        //其余自动默认为0
        //将余数对应项置1
        for(int i=0;i<len;i++)
            temp[i][arr[i]%3] = 1;
        for(int i=1;i<len;i++){
            int m = arr[i]%3;
            for(int j=0;j<3;j++){
                temp[i][j] += temp[i-1][j]+temp[i-1][(j+3-m)%3];
            }
        }
        return temp[len-1][0];

 }
}

思路:

  1. 一开始只是把注意力集中在如何寻找子序列上,完全忘了%3这个条件
  2. 可以按照%3的余数不同进行分类每一位判断余数是0/1/2,由于%3的特殊性,每一位的加和整除3即可整除3.所以就把问题转化成实际上就是利用余数的特点:比如余数是1和2的加起来一定整除3
    那么就可以判断以每一位结尾的数的组合中%0,1,2 的数目
  3. 数组dp[cur][left]:cur代表当前位数,left代表当前的数的余数
  4. 根据当前数的情况分为三种
1.if(arr[cur]%3==0)//如果当前位整除3
dp[cur][0]=dp[cur-1]+1;
dp[cur][1]=dp[cur-1][1];
dp[cur][2]=dp[cur-1][2];
2.if(arr[cur]%3==1)//如果当前位除3余1
dp[cur][0]=dp[cur-1][0]+dp[cur-1][2];
dp[cur][1]=dp[cur-1][1]+1;
dp[cur][2]=dp[cur-1][2]+dp[cur-1][1];
3.if(arr[cur]%3==2)//如果当前位除3余2
dp[cur][0]=dp[cur-1][0]+dp[cur-1][1];
dp[cur][1]=dp[cur-1][1]+dp[cur-1][2];
dp[cur][2]=dp[cur-1][2]+1;

规律:
1.当前位置的余数值直接%3得到的位置的值+1
2.另一些的left位应该是和余数相加得1的位置,这个表示注意j+3-m,加上除数3是为了防止负数的产生
3.在开始的时候使用for(int i=0;i<len;i++) temp[i][arr[i]%3] = 1;来提前将每一个需要当前位+1的都提前赋值完成

第二题

机器人到达指定位置的方法数
在一条线上1~N个位置,机器人only向左和向右走,给出起始位置M,终止位置P,一共可以走的步数K,计算共有多少种走法。
暴力递归:

public  class Main {//主类
    public static void main(String args[])throws Exception{
       System.out.println("The answer is :");
       System.out.println(f(5,2,3,3));
    }
     public static int f(int N,int cur,int res,int P){
        if(res == 0)  return 0;
        if(res == 1)
        {
            if(Math.abs(cur-P) == 1)
                return 1;
        }
        if(cur == 1)  return f(N,2,res-1,P);
        if(cur == N)  return f(N,N-1,res-1,P);
        return f(N,cur-1,res-1,P)+f(N,cur+1,res-1,P);
    }
}
唉,也没有人家写的逻辑性更强,思路更清晰:
人家的开始条件判断是这样的:
if( res == 0)
return P == cur ? 1:0;
//res为0的位置就是最后的位置
//如果最后的位置是P,则说明这个方法是正确的,可行,所以返回1
//如果最后的位置不是P,这个方法不可行,返回0

优化方法:
解决一个问题,如果没有想到显而易见的求解策略(比如数学公式、贪心算法等),那么就想如何通过尝试的方式找到答案,然后先写出尝试的函数再去想如何优化。
暴力递归优化成动态规划时,分析整个递归过程是不是无后效性的。即一个递归状态的返回值与怎么到达这个状态的路径无关。
相当于树的剪枝过程(哇,突然想到了Alpha-beta剪枝算法,虽然也写不出来)
套路:
【前提是无后效性】

  1. 找到什么可变参数可以代表一个递归状态,哪些参数一旦确定,返回值就确定了
  2. 把可变参数的所有组合映射成一张表,一个可变参数就是一维dp数组,两个可变参数就是2维dp数组
  3. 最终答案是where
  4. 根据递归的base case确定整个表最简单、不需要依赖其他位置的那些位置填好值。
  5. 普通位置的递归部分转换成这个当前的位置是受哪几个它邻近位置的数值影响的
  public static int f1(int N,int cur,int res,int P) {
        if (res == 0) return 0;
        int[][] dp = new int[res+1][N];
        for (int i = 0; i < N; i++)
            if (i == P-1) {
                dp[0][i] = 1;
            }
        for(int i = 1;i<=res;i++){
           for(int j=0;j<N;j++)
           {
               if(j==0)
               {dp[i][j]= dp[i-1][1];}
               else if(j==N-1)
               {dp[i][j] = dp[i-1][N-2];}
               else {
                   dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1];}
           }
        }
         return dp[res][cur-1];
    }

空间压缩:

public static int f2(int N,int cur,int res,int P){
        if(res == 0) return 0;
        int[] dp= new int[N+1];
        dp[P]=1;
        for(int i=1;i<=res;i++)
        {
            int temp = dp[1];
            dp[1] = dp[2];
            for(int j=2;j<N;j++){
                 dp[j] = temp + dp[j+1];
                 temp = dp[j];
            }
            dp[N] = temp;
        }
        return dp[cur];
    }

这里面for循环没用书里的if条件判断,觉得反正每次都是从1到N在开始和结束的时候在里层for循环控制一下开始和结束就行,要不每次for循环还得if判断一下。
还有这里的函数的参数无效的判断都没写,得加上啊,唉,懒得写,啥时候能有个头啊

第三题

最长递增子序列

public  class Main {//主类
    public static void main(String args[])throws Exception{
       int [] arr = {2,1,5,3,6,4,8,9,7};
       int [] dp = getdp(arr);
       for(int i=0;i<arr.length;i++)
       System.out.println("the answer is :"+dp[i]);
       //我觉得应该先找dp数组中最大的那个,然后选择输出
        //在对应向前面的所有位置找第二大的位置选择输出
        //在有重复数字的时候选择第一个比如【1,2,3,3】就应该选择第一个3的位置输出,而不是第二个
        //上面的思维是有问题的
        //应该是从这个位置开始,向前寻找arr[j]<arr[i]&&dp[j]=dp[i]-1的位置
        int[] path = new int[dp.length];
        path=getpath(dp,arr);
        for(int i=0;i<dp.length;i++)
        {
            if(path[i]!=0)
                System.out.print(path[i]+" ");
        }
    }
    public static int[] getpath(int[] dp,int[] arr){
        int[] path = new int[dp.length];
        //先找到dp中最大的元素
        int index = 0;
        int max = dp[0];

        for(int i=0;i<dp.length;i++){
            if(max<dp[i])
            {
                max = dp[i];
                index = i;
            }
        }
        path[index]= arr[index];
        //将dp数组中最大值的位置选出
        for(int i=index-1;i>=0;i--){
                if(dp[i]==dp[index]-1&&arr[i]<arr[index]) {
                    path[i] = arr[i];
                    index = i;
                }
            }

        return path;
    }
    public static int[] getdp(int[] arr){
        int[] dp= new int[arr.length+1];
        for(int i=0;i<arr.length;i++){
            dp[i] = 1;//每一个dp的位置到最后如果要是和前面不匹配都是1
            //从第一个位置开始给arr的每个位置的最长的递增子序列赋值
            for(int j=0;j<i;j++){//然后从0-i-1的每一个位置都检查一遍
                //但是这里不会了,怎么判断呢?
                //跟谁判断呢?
                if(arr[i]>arr[j])
                {dp[i] = dp[i]>(dp[j]+1)?dp[i]:(dp[j]+1);}
           //知道一开始为什么返回的数值不对了,因为最长递增子序列的结束的最终位置可能在数组的任何一个位置
            }
        }
        return dp;
    }
}

时间复杂度N^2
优化:利用二分查找进行优化

public  class Main {//主类
    public static void main(String args[])throws Exception{
       int [] arr = {2,1,5,3,6,4,8,9,7};
       int [] path = getpath(arr);
       for(int i=0;i<path.length;i++)
       {
           if(path[i]!=0)
               System.out.print(path[i]+" ");
       }
    }
    public static int[] getpath(int[] arr){
        int[] dp= new int[arr.length];
        int[] ends= new int[arr.length];//有效区的函数指针
        int right =0;//用来指示函数有效区的最右边界,从0-right
        //初始化部分
        dp[0]=1;
        ends[0]=arr[0];
        for(int i=1;i<arr.length;i++){
            int index =  binarySearch(ends,right,arr[i]);
            System.out.println("index的值为:"+index);
            if( index == right )//说明在end数组中没有比当前数大的那个数
            {
                dp[i]=dp[i-1]+1;
                ends[right++]=arr[i];
            }
            else{//在ends数组中存在比当前位置的数大的数,当前数的最大子序列数目就是前一个的
                //但是ends数组中的最左边的要改成当前的数
                dp[i]=dp[i-1];
                ends[index]=arr[i];
            }
            //存在的一个问题是:如果已经到dp最大的位置,他还是会计算后面的数值并更新ends数组
            //如何处理这个问题?
            System.out.println("这是第"+i+"次循环的ends数组");
            for(int j=0;j<ends.length;j++)
                System.out.print(ends[j]+" ");
            System.out.println();
        }
        return ends;
    }
    //二分查找第一个不小于target的数据
    //其实利用二分查找选择不大于、不小于、大于、小于和第一个、最后一个的搭配主要是在下标的调整
    public static int binarySearch(int[] arr,int len,int target){
        int left =0;
        int right = len;
        while(left<right){
            int mid = left +(right-left)/2;
            if(arr[mid]<target)
                left= mid+1;
            else
                right=mid;
        }
        return right;
    }
    //查找第一个大于target的数据
    public static int binarySearch1(int[] arr,int target){
        int left = 0;
        int right = arr.length-1;
        while (left<=right){
            int middle = left+(right-left)/2;
            if(arr[middle]<=target)
                left = middle+1;
            else
                right = middle;//注意哦,这里不能是middle-1啦
            //因为arr[middle]就有可能是那个第一个大于target的数!
        }
        return right;
    }


}

这个问题还没有解决
虽然可以直接在求解dp数组的时候使用,然后还是继续用dp数组求解,但不想那样写。
这个问题也可以用二维的ends数组解决,每行对应着要查找的每个数为结尾的最长序列,然后查找dp数组的最大位置返回下标找到对应的序列,需要查询多个结果的时候可以。
但是这个题可不可以不那样写呢?怎么找到最终的判断标准呢?

第四题

信封嵌套问题

public  class Main {//主类
    public static void main(String args[])throws Exception{
      int[][] arr ={{3,4},{2,3},{4,5},{1,3},{2,2},{3,6},{1,2},{3,2},{2,4}};
      int[] dp = getmethod(arr);
      for(int i=0;i<dp.length;i++)
          System.out.print(dp[i]+" ");

    }
  public static int[] getmethod(int[][] arr){
        //每行的0和1都是一对信封的长和宽
        //和前一题一样只不过是要把整个长和宽看成是一个整体要比较的元素
      int [] dp = new int[arr.length];//每行设置一个元素的位置
      //dp数组表示到第i个信封的时候,最多嵌套多少层
      dp[0]=1;//第一个信封只能嵌套一个
      for(int i=1;i<arr.length;i++){
          dp[i]=1;
          for(int j=1;j<i;j++){
              if((arr[i][0]>arr[j][0]&&arr[i][1]>arr[j][1])||(arr[i][0]<arr[j][0]&&arr[i][1]<arr[j][1]))
              {
                  dp[i]=dp[j-1]+1>dp[i]? dp[j-1]+1:dp[i];
              }
              //这里的处理是有问题的,因为信封也可以反过来装,所以要加一个反向的
          }
      }
      return dp;
  }

还有一个思路:将信封先按照长度或者宽度进行排序。
比如按照长度进行排序,那么二者之间能否比较就只看宽度就可以了。
【忽略长度数组,只看宽度数组,这个数组的最长递增子序列的长度是多少即可】
有两种情况,如果当前的长度相等,不需判断,不可以装;
如果当前长度不相等,判断前面的和当前宽度,如果宽度相等,则肯定可以装入。
但是有些麻烦,不过这个思维的

第五题

最长公共子序列

public  class Main {//主类
    public static void main(String args[])throws Exception{
    String str1 ="1A2C3D4B56";
    String str2 ="B1D23CA45B6A";
    char[] ch1 = str1.toCharArray();
    char[] ch2 = str2.toCharArray();
    int[][] dp= getpath(ch1,ch2);
    System.out.println(dp[ch1.length-1][ch2.length-1]);

    }
    public static int[][] getpath(char[] ch1,char[] ch2){
        int[][] dp = new int[ch1.length][ch2.length];
        //dp数组表示第一个序列从i往前和第二个序列从j往前的最长子序列个数
        //dp数组初始化
        //开始的时候这里的条件有问题呢
        //dp数组的初始化要判断它和开始的每个方向上确定的第0个位置开始的是否相等才能赋值1或者0
        if(ch1[0]==ch2[0])
            dp[0][0]=1;
        for(int i=0;i<ch1.length;i++)
            dp[i][0]=Math.max(ch1[i]==ch2[0]? 1:0,dp[i][0]);
        for(int i=0;i<ch2.length;i++)
            dp[0][i]=Math.max(ch2[i]==ch1[0]? 1:0,dp[0][i]);
        for(int i=1;i<ch1.length;i++)
            for(int j=1;j<ch2.length;j++)
            {

                if(ch1[i]==ch2[j])
                    dp[i][j]=Math.max(dp[i-1][j-1]+1,dp[i][j]);
                else{
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        return dp;

    }
  }


只求出了最长公共子序列的长度,返回具体序列还没写

第六题

最长公共子串

public  class Main {//主类
    public static void main(String args[])throws Exception{
        String str1 = "1AB2345CD";
        String str2 = "12345EF";
        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();
        char[] answer = get(ch1,ch2);
       for (int i=0;i<answer.length;i++)
           System.out.print(answer[i]+" ");

    }
    public static char[] get(char[] ch1,char[] ch2){
        int[][] dp = new int[ch1.length][ch2.length];
        char[] answer= new char[Math.max(ch1.length,ch2.length)];
        int index=0;
        for(int i=0;i<ch2.length;i++)
            dp[0][i]=Math.max(dp[0][i],ch1[0]==ch2[i]? 1:0);
        for(int i=0;i<ch1.length;i++)
            dp[i][0]=Math.max(dp[i][0],ch1[i]==ch2[0]? 1:0);
        if(ch1[0]==ch2[0])
        {dp[0][0]=1;answer[index]=ch1[0];}
        for(int i=1;i<ch1.length;i++)
            for(int j=1;j<ch2.length;j++){
                if(ch1[i]==ch2[j]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    answer[index++]=ch1[i];
                }
                else
                {
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        return answer;

    }

  }

第七题

子数组异或0的最多划分
数组异或和的定义:把数组中所有的数异或起来得到的值。
给定一个整型数组arr,其中可能有正、有负、有零。可以随意把整个数组切成若干个不相容的子数组,求异或和为0的子数组最多多少个?
分析:
dp数组代表的意义是到数组当前的位置最多有多少个异或和为0的子数组划分。
假设前面的数组dp[i-1]的最优划分已经知道了,现在要求dp[i]有两种情况:

  1. 最后一组划分异或和不是0
  2. 最后一组划分异或和是0
    如果最后一组划分的异或和不是0,最多的就是dp[i-1];
    如果最后一组划分的异或和为0,则要判断最后一组异或和为零的子数组的起始位置在哪。
    假设起始位置为k,则当前的dp[i]=dp[k-1]+1;
    最后比较dp[i-1]和dp[k-1]+1的大小,选择大的那个
    关键是求解k的位置,主要是记录从左往右数

public  class Main {//主类
    public static void main(String args[])throws Exception{
       int[] arr = {3,2,1,9,0,7,0,2,1,3};
       System.out.println("the answer is:"+divide(arr));

    }
 public static int divide(int[] arr){
        if(arr == null&& arr.length==0)
            return 0;
        int[] dp= new int[arr.length];
        int ero=0;//每一步的当前异或值
        HashMap<Integer,Integer> map=new HashMap<>();
        //hashmap的key代表当前异或值,当value为-1的时候代表没有进入数组
        //因为是要用当前的异或值去寻找与当前ero值相等的k的位置
       //所以返回的值应该是位置,也就是key是ero,value是ero对应的位置
        map.put(0,-1);//尚未进入
        //第一个位置的赋值
        dp[0] = arr[0]==0? 1:0;
        map.put(arr[0],0);
        //从第二个位置开始赋值
        for(int i=1;i<arr.length;i++){
            ero^=arr[i];
                if(map.containsKey(ero)){
                    //每次都在hashmap中寻找是否含有当前的值
                    //如果含有,则寻找这个值对应的那个数的位置,hashmap有唯一性?后面的会把前面的冲掉?
                    //用二维数组代替hashmap行吗?
                int preindex = map.get(ero);
                dp[i] = preindex==-1? 1 : dp[preindex]+1;
                //这里要有一个hashmap返回值的判断
                    // 因为如果要是返回的是-1,就说明包括当前的dp[i]整体是一个为0的子数组
           }
                dp[i]=Math.max(dp[i-1],dp[i]);//每次dp的值要进行前一个和上面可能求出的进行比较
                map.put(ero,i);//别忘了,每次计算都要把hashmap的结果写入hashmap
        }
        return dp[arr.length-1];
    }

  }

第八题

字符串的交错组成
给定三个字符串str1,str2和aim,如果aim包含且仅包含str1和str2的字符,且都是按照原来的顺序排列,不改变其原来的排列顺序。判断aim是否是str1和str2的交错组成。
这里面包含条件是str1和str2各自的元素是不一样,组成的aim必须是str1.length+str2.length
分析:
dp[i][j]代表当前的str1字符串前i个和str2字符串的前j个是否在aim中,所以这个dp数组是个boolean类型的数组

  1. 这里第一行和第一列首先初始化,就是直接的每个位置一对一比较然后相等赋值true
  2. 然后就是其他地方的遍历,当str1的i-1可以放进去,dp[i][j]可以为true,当str2的j-1可以放进去,dp[i][j]也可以为true,其余的情况为false

第九题

龙与地下城问题
也就是返回(绝对值)最小路径和的问题

public  class Main {//主类
    public static void main(String args[])throws Exception{
    int[][] map={{-2,-3,3},{-5,-10,1},{0,30,-5}};
     System.out.println(getvalue1(map));
    }
    /*
    骑士只能选择往右或者往下走,走到最终的位置dp[m-1][n-1]即为重点
    本题需要返回最小的血量,所以要从最后一个位置往前计算所需要的
     那么dp[i][j]和前面的数是什么关系呢?
     当前点的数先加到数组中

     */
    /*
     这种解法有问题,实际上思维受到了两个边界的限制
     然后就忽略了[0][i]和[i][0]两个边界的问题
     */
public static int getvalue(int[][]map){
    if(map==null||map.length==0||map[0].length==0||map[0]==null)
        return 1;
        int[][]dp = map;
        int row = map.length-1;
        int column = map[0].length-1;
        dp[row][column]=map[row][column];//最后的位置直接赋值
    for(int i=row;i>0;i--){
            for(int j=column;j>0;j--){
               dp[i][j]=Math.min(map[i-1][j]+dp[i][j],map[i][j-1]+dp[i][j]);
            }
        }
   return dp[1][1];
}
public static int getvalue1(int[][] map){
    if(map==null||map.length==0||map[0].length==0||map[0]==null)
        return 1;
    int[][]dp = map;
    int row = map.length-1;
    int column = map[0].length-1;
    //dp[row][column]=map[row][column];最后的位置直接赋值
    //之前的赋值是有问题的,因为没有考虑到,如果最后一个位置的值是正数的话
    //其实直接将置1才是最小的值
    //最小要保证骑士血值为1
    dp[row][column]= map[row][column]>0? 1:-map[row][column]+1;
    int right =0;
    int down = 0;
    for(int i=row-1;i>=0;i--){
        dp[i][column]=Math.max(dp[i+1][column]-map[i][column],1);
        for(int j=column-1;j>=0;j--){
            right=Math.max(dp[i+1][j]-map[i][j],1);
            down= Math.max(dp[i][j+1]-map[i][j],1);
            dp[i][j]=Math.min(right,down);
        }
    }
    return dp[0][0];
}

}


第十题

数字字符串转换成字母组合的种数

public  class Main {//主类
    public static void main(String args[])throws Exception{
    String str = "1111";
    System.out.println("the answer is:"+num1(str));
    }
    /*
     26个字母每个字母对应的数字就是该字母的代表数字
     也就是只有两位或者1位的才可以
     求一个字符串有多少种转换结果
     "01"没有对应字母,不可转换
     */
   public static int convert(String str){
       //初始条件判断
       if(str.length()==0)
           return 0;
       if(str.charAt(0)=='0')
           return 0;
        //主体
       int[]dp = new int[str.length()];
       dp[0]=1;
       if(str.charAt(1)=='0')
       {
           dp[1]=1;
       }
       else dp[1]=2;
       if(str.charAt(2)!='0')
           dp[2]=dp[1]+1;
       else{
           if(str.charAt(1)=='1'||str.charAt(1)=='2')
               dp[2]=Math.max(2,dp[1]+1);
           else{
               return 0;
           }
       }
       //记录到当前位置的转化结果判断
       for(int i=2;i<str.length();i++){
           if(str.charAt(i)!='0'&&str.charAt(i)<='6')
           {
               if(str.charAt(i-1)=='1'||str.charAt(i-1)=='2')
                   dp[i]=Math.max(dp[i-1]+1,dp[i-2]+1);
           }
           if(str.charAt(i)=='0')
           {
               if(str.charAt(i-1)!='1'||str.charAt(i-1)!='2')
                   return 0;
               //0只能和前面的组队否则就是错误
               //如果和前面的组队有两种情况:+1/前面的本来组好队了,拆出来一个 +0/前面的没组队
               //判断一下前面的组没组好
               if(dp[i-1]==dp[i-2])//组好队了
                   dp[i]=dp[i-1]+1;
               else
                   dp[i]=dp[i-1];
           }

           if(str.charAt(i)>'6')
               dp[i]=dp[i-1]+1;
       }
       return dp[str.length()-1];
   }
   /*
   这个p(i)表示的是str[0-i-1]已经转换完毕,而str[i-N-1]尚未合法转换的转换种数
   如果i=N-1证明整体已经转换完毕,p(i)=1
   否则p(i)的值为后面剩下的序列的转换个数
   1.如果i==N直接返回1
   2.如果不满足1,当前的i处字母为0,则不合法,直接返回0
   3.如果不满足1and2,那么str[i]=1~9,可以直接转换,p(i)的值一定包含p(i+1)的值,p(i)=p(i+1);
   4.如果不满足1and2,那么str[i]=1~9,又有str[i]str[i+1]是10~26,那么p(i)一定包含p(i+2)的值,p(i)+=p(i+2);是在3的基础上的
    */
   public static int num1(String str){
       if(str == null||str.equals(""))
           return 0;
       char[] chs = str.toCharArray();
       return process(chs,0);
   }
   public static int process(char[] chs,int i){
       if(i == chs.length)
           return 1;
       if(chs[i]=='0')
             return 0;
       int res = process(chs,i+1);
       if((i+1<chs.length)&&((chs[i]-'0')*10+chs[i+1]-'0')<27){
        res+=process(chs,i+2);
       }
         return res;
   }
   /*
   这个题不能用类似于斐波那契数列的矩阵乘法降低时间复杂度
   因为这个题的递归表达式是会发生状态转移的
   不像斐波那契数列那样是固定不变的
   如果换成只是由12序列组成的就可以用矩阵乘法优化
    */
   public static int num2(String str){
       if(str == null||str.equals(""))
           return 0;
       //字符串初始条件判断是这样的
       char[] chs = str.toCharArray();
       //首先判断最后一个位置是否是0
       int cur = chs[chs.length-1] == '0'? 0:1;
       int next = 1;
       int tmp = 0;
       for(int i = chs.length-2;i>=0;i--){
           if(chs[i]=='0')
           {
               next = cur;
               cur=0;
           }
           else{
               tmp = cur;
               if((chs[i]-'0')*10+chs[i+1]-'0'<27)
                   cur+=next;
           }
           next = tmp;
       }
       return cur;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值