剑指Offer算法题及答案Java完整版(二)

16、请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径,路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

package cn.ctgu.offer;
/*
 * 题目:
 * 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
 * 路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
 * 如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。
 * 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径
 * 但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
 * 
 * 思路:
 * 1、采用回溯法
 * 2、将matrix字符串模拟映射为一个字符矩阵(但并不实际创建一个矩阵)
 * 3、取一个boolean[matrix.length]标记某个字符是否已经被访问过
 * 3、如果没找到结果,需要将对应的boolean标记值置回false,返回上一层进行其他分路的查找
 * 
 * */
public class HashStrPath {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        boolean[] visited=new boolean[matrix.length];
        for(int i=0;i<rows;i++) {
            for(int j=0;j<cols;j++) {
                if(searchFromHere(matrix,rows,cols,i,j,0,str,visited))
                    return true;
            }
        }
        return false;

    }

    private boolean searchFromHere(char[] matrix, int rows, int cols, int r, int c, int index, char[] str,
            boolean[] visited) {
        //matrix[r*cols+c]!=str[index]这是判断位置(c,r)是否为字符串所在位置
        if(r<0 || r>=rows || c<0 ||c>=cols || matrix[r*cols+c]!=str[index] || visited[r * cols + c])
            return false;
        if(index==str.length-1)
            return true;
        visited[r*cols+c]=true;
        if (searchFromHere(matrix,rows,cols,r - 1,c,index + 1,str,visited) ||
                    searchFromHere(matrix,rows,cols,r,c -1,index + 1,str,visited) ||
                    searchFromHere(matrix,rows,cols,r + 1,c,index + 1,str,visited) ||
                    searchFromHere(matrix,rows,cols,r,c + 1,index + 1,str,visited))
                return true;
        visited[r*cols+c]=false;
        return false;
    }
}

17、给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

package cn.ctgu.offer;
/*
 * 给定一个double类型的浮点数base和int类型的整数exponent。
 * 求base的exponent次方。
 * 
 * 
 * */
public class IntegerPower {
    public double Power(double base, int exponent) {

        return Math.pow(base, exponent);
      }
    /*手写
     * 
     * 1.全面考察指数的正负、底数是否为零等情况。
     * 2.写出指数的二进制表达,例如13表达为二进制1101。
     * 3.举例:10^1101 = 10^0001*10^0100*10^1000。
     * 4.通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
     * 
     * */
    public double Power2(double base, int n) {
        double res = 1,curr = base;
        int exponent;
        if(n>0){
            exponent = n;
        }else if(n<0){
            if(base==0)
                throw new RuntimeException("分母不能为0"); 
            exponent = -n;
        }else{// n==0
            return 1;// 0的0次方
        }
        while(exponent!=0){
            if((exponent&1)==1)
                res*=curr;
            curr*=curr;// 翻倍
            exponent>>=1;// 右移一位
        }
        return n>=0?res:(1/res);       
    }
    public static void main(String[]args) {
        IntegerPower num=new IntegerPower();
        System.out.println(num.Power2(12.34d, -4));
    }
}

18、LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。

package cn.ctgu.offer;

import java.util.Arrays;

/*
 * 题目:
 * LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...
 * 他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!
 * “红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了
 * 他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。
 * 上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。
 * 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。
 * 
 * 
 * 思路:
 * 1、当牌不等于5张的时候返回false
 * 2、对排进行排序(方便统计王(0)的数量以及比较是否有相同的牌,前后比较即可)
 * 3、判断第一张非0的牌和最后一张非0的牌的差是否超过4,如果超过4则不可能是顺子
 * 
 * */
public class IsContinu {
    public boolean isContinuous(int [] numbers) {
        if(numbers.length!=5) {
            return false;
        }
        //排序
        Arrays.sort(numbers);
        //统计王的个数
        int res=0;
        for(int i=0;i<numbers.length;i++) {
            if(numbers[i]==0) {
                res=res+1;
                continue;
            }
            //当王的数量小于等于3张的时候才需要判断,等于4张的时候一定是顺子
            //判断第一张非0的牌和最后一张非0的牌的差值吃否超过4
            //判断前后两张牌是否相等,相等则不可能是顺子
            //此时的numbers[i]为第一个不为0的数,因为前面将为0的数据都遍历完了(continue的作用是跳出本轮循环,继续下一轮,所以0没有遍历完之前不会执行下面的语句)
            if(res!=4&&(numbers[numbers.length-1]-numbers[i]>4||numbers[i]==numbers[i+1])) {
                return false;
            }else {
                return true;
            }
        }
        return true;
    }
}

19、请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。

package cn.ctgu.offer;
/*
 * 题目:
 * 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
 * 例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。
 * 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
 * 
 * 
 * 思路:
 * 1、先扫描字符是否是以+、-开头,如果是则判断下一个字符是否为数字,只有数字才能通过,否则该字符串不表示数值;
 *   如果不是+、-,则判断它是否是数字
 * 2、如果是数字则进行下一个字符判断,判断它是否为数字,如果不是则进行"."判断和"E、e"判断,反正第二个字符只能为数字或者"E、e"(第一个字符如果为'+、-'则第二个字符只能为数字)
 *    如果第一个字符为数字,则第二个字符可以为('-、E、e、.')
 * 
 * 
 * */
public class IsNumber {
    private int index=0;
    public boolean isNumberic(char[] str) {
        if(str.length<1)
            return false;
        boolean flag=scanInteger(str);

        if(index<str.length && str[index]=='.') {
            index++;
            flag=scanUnsignedInteger(str)||flag;//字符如果不为数字则返回false
        }
        if(index<str.length && (str[index]=='E'||str[index]=='e')) {
            index++;
            flag=flag && scanInteger(str);
        }
        return flag && index==str.length;
    }
    //判断字符是否是以+或-号开头
    private boolean scanInteger(char[] str) {
        if(index<str.length &&(str[index]=='+'||str[index]=='-'))
            index++;
        //如果不是+、-就判断是否为数字
        return scanUnsignedInteger(str);
    }
    private boolean scanUnsignedInteger(char[] str) {
        int start=index;
        while(index<str.length && str[index]>='0'&& str[index]<='9')
            index++;
        return start<index;//是否存在整数
    }
}

20、输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。说明:二叉搜索树的根节点大于左子树,右节点大于根节点

package cn.ctgu.offer;
/*
 * 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。
 * 假设输入的数组的任意两个数字都互不相同。
 * 说明:二叉搜索树的根节点大于左子树,右节点大于根节点
 * 
 * 思路:
 * 1、采用递归
 * 2、去掉根节点,也就是数组的最后一个元素,小于最后一个节点的为左子树,大于根节点的为右子树
 * 3、如果左子树和右子树都满足左节点小于根节点、右节点大于根节点则为true,否则为true
 * 
 * 
 * */
public class JudgeBST {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence.length==0) {
            return false;
        }
        return IsBst(sequence,0,sequence.length-1);
    }
    public boolean IsBst(int[]sequence,int start,int end ) {
        if(end<=start) {//当只有一个元素时,则为真
            return true;
        }
        int i=start;
        for(;i<end;i++) {
            if(sequence[i]>sequence[end]) {//当找到某个节点大于根节点,则从该元素开始直到end-1(倒数第二个元素),都为左子树
                break;
            }
        }
        for(int j=i;j<end;j++) {    //如果右子树中存在小于根节点的元素,则返回false,即该数组不是二叉搜索树的后序遍历
            if(sequence[j]<sequence[end]) {
                return false;
            }
        }
        return IsBst(sequence,start,i-1) && IsBst(sequence,i,end-1);
    }

}

21、一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法

package cn.ctgu.offer;
/*
 * 一只青蛙一次可以跳上1级台阶,也可以跳上2级。
 * 求该青蛙跳上一个n级的台阶总共有多少种跳法
 * 
 * 思路:当前台阶的跳法总数=当前台阶后退一阶的台阶的跳法总数+当前台阶后退二阶的台阶的跳法总数
 * 
 * 
 * 使用动态规划来求解该问题,动态规划适合求解最优解问题。
 * 1、先构造出最优子结构
 * 2、建立递归关系
 * 3、计算最优值
 * 4、求解最优解
 * 
 * */
public class JumpFloor {
    public int JumpFloors(int target) {
        if(target==1) {
            return 1;
        }
        if(target==2) {
            return 2;
        }
        int one=1;//当前台阶后退二阶的台阶的跳法总数(初始值当前台阶是第3阶)
        int two=2;//当前台阶后退一阶的台阶的跳法总数(初始值当前台阶是第3阶)
        int result=0;// 当前台阶的跳法总数
        for(int i=2;i<target;i++) {
            result=one+two;
            one=two;//后退一阶在下一次迭代变为后退两阶
            two=result;//当前台阶在下一次迭代变为后退一阶
        }
        return result;
    }
    public static void main(String[]args) {
        JumpFloor dy=new JumpFloor();
        System.out.println(dy.JumpFloors(3));
    }

}

22、一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

package cn.ctgu.offer;
/*
 *一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
 *求该青蛙跳上一个n级的台阶总共有多少种跳法。
 *
 * 思路:设跳上第n阶的跳法为f(n)
 * 即 f(n)=f(n-1)+f(n-2)+f(n-3)+...+f(1)+1
 * 
 * 1就是直接跳上第n阶楼梯的跳法
 * 
 * */
public class JumpFloor2 {
    public int JumpFloor(int target) {
        int[]ways=new int[target+1];
        ways[0]=1;
        ways[1]=1;//跳上一级阶梯有一种跳法
        if(target==0) {
            return 0;
        }
        else {
            for(int i=2;i<=target;i++) {
                ways[i]=0;//相当于那个1,也就是直接跳上第n阶楼梯的跳法
            for(int j=0;j<i;j++) {
                ways[i]=ways[i]+ways[j];
            }
        }
        return ways[target];
    }
}
    public static void main(String[]args) {
        JumpFloor2 dy=new JumpFloor2();
        System.out.println(dy.JumpFloor(5));
    }

}

23、随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中。从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友。可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

package cn.ctgu.offer;

import java.util.LinkedList;

/*
 * 题目:
 * 随机指定一个数m,让编号为0的小朋友开始报数。
 * 每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中。
 * 从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友。
 * 可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。
 * 请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
 * 
 * 
 * 思路:
 * 1、将所有的数封装成一个LinkedList
 * 2、每次删除的都是第m-1个元素,它的索引可以通过公式:index=(index+m-1)%(环的长度)得到
 * 3、index是指开始那个元素的索引,比如,因为每次报数都是从0开始,m为2的话删除的必定为1(m=2,2-1=1)
 * 4、将原始索引为1的删除了的话,下一个开始的元素报0的数为原始索引为2的元素(由于是链表,则删除了索引为1的元素
 *    后面的元素自然前移,即原来索引为2的元素自然为1,也就是被删除的原索引本身)
 * 
 * */
public class LastRemain {
    public int LastRemaining_Solution(int n, int m) {
        LinkedList<Integer>list=new LinkedList<Integer>();
        //将所有的数封装到LinkedList中
        for(int i=0;i<n;i++) {
            list.add(i);
        }
        //删除元素
        int index=0;
        while(list.size()>1) {
            index=(index+m-1)%list.size();
            list.remove(index);
        }
        return list.size()==1?list.get(0):-1;
    }
}

24、例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。

package cn.ctgu.offer;
/*
 * 题目:
 * 例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。
 * 
 * 思路:
 * 1、将字符串转成字符串数组
 * 2、左移k位就把前k位取出来接在原数组的后面
 * 
 * 
 * */
public class LeftRotateStr {
     public String LeftRotateString(String str,int n) {
         int len=str.length();
         if(len==0) {
             return "";
         }
         if(n>len) {
             n=n-len;
         }
         char[]strArray=str.toCharArray();
         char[]newArray=new char[len];
         for(int i=n;i<len;i++) {
             newArray[i-n]=strArray[i];
         }
         for(int j=0;j<n;j++) {
             newArray[len-n+j]=strArray[j];
         }
         return String.valueOf(newArray);
     }
     public static void main(String[]args) {
         LeftRotateStr solution=new LeftRotateStr();
         String s="abcXYZdef";
         String str=solution.LeftRotateString(s, 3);
         System.out.println(str);
     }
}

25、在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

/*两种思路
一种是:
把每一行看成有序递增的数组,
利用二分查找,
通过遍历每一行得到答案,
时间复杂度是nlogn
*/
public class Solution {
    public boolean Find(int [][] array,int target) {

        for(int i=0;i<array.length;i++){
            int low=0;
            int high=array[i].length-1;
            while(low<=high){
                int mid=(low+high)/2;
                if(target>array[i][mid])
                    low=mid+1;
                else if(target<array[i][mid])
                    high=mid-1;
                else
                    return true;
            }
        }
        return false;

    }
}
 /*
另外一种思路是:
利用二维数组由上到下,由左到右递增的规律,
那么选取右上角或者左下角的元素a[row][col]与target进行比较,
当target小于元素a[row][col]时,那么target必定在元素a所在行的左边,
即col--;
当target大于元素a[row][col]时,那么target必定在元素a所在列的下边,
即row++;
*/
public class Solution {
    public boolean Find(int [][] array,int target) {
        int row=0;
        int col=array[0].length-1;
        while(row<=array.length-1&&col>=0){
            if(target==array[row][col])
                return true;
            else if(target>array[row][col])
                row++;
            else
                col--;
        }
        return false;

    }
}



26、给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1},{2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

package cn.ctgu.offer;

import java.util.ArrayList;

/*
 * 题目:
 * 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
 * 例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3
 * 那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 
 * 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:
 *  {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1},
 *  {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
 * 
 * 思路:
 * 1、每隔一个窗口长度找出最大的值
 * 2、将最大的值添加进列表
 * */
public class MaxInWindow {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer>list=new ArrayList<Integer>();
        if(size>num.length||size==0)
            return list;
        for(int i=0;i<=num.length-size;i++) {
            int max=num[i];
            for(int j=i+1;j<i+size;j++) {
                if(num[j]>max) {
                    max=num[j];
                }
            }
            list.add(max);
        }
        return list;
    }
}

27、归并排序算法

package cn.ctgu.offer;

import java.util.Arrays;

/*
 * 归并排序
 * 
 * */
public class MergeSort {
    public static void sort(int []arr) {
        //排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        int[] temp=new int[arr.length];
        sort(arr,0,arr.length-1,temp);
    }

    private static void sort(int[] arr, int left, int right, int[] temp) {
        if(left<right) {
            int mid=(left+right)/2;
            //左边归并排序,使得左子序列有序
            sort(arr,left,mid,temp);
            //右边归并排序,使得右子序列有序
            sort(arr,mid+1,right,temp);
            //将两个有序子数组合并操作
            merge(arr,left,mid,right,temp);
        }

    }

    private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        //左序列指针
        int i=left;
        //右序列指针
        int j=mid+1;
        //临时数组指针
        int t=0;
        while(i<=mid && j<right) {
            if(arr[i]<=arr[j]) {
                temp[t]=arr[i];
                t++;
                i++;
            }else{
                temp[t]=arr[j];
                t++;
                j++;
            }
        }
        while(i<=mid) {//将左边剩余元素填充进temp中
            temp[t]=arr[i];
            t++;
            i++;
        }
        while(j<=right) {//将右序列剩余元素填充进temp中
            temp[t]=arr[j];
            t++;
            j++;
        }
        t=0;
        //将temp中的元素全部拷贝到原数组中
        while(left<=right) {
            arr[left]=temp[t];
            left++;
            t++;
        }

    }
     public static void main(String []args){
            int []arr = {9,8,7,6,5,4,3,2,1};
            sort(arr);
            System.out.println(Arrays.toString(arr));
        }
}

28、输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

package cn.ctgu.offer;
/*
 * 题目:
 * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
 * 例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
 * 
 * 思路:
 * 两两比较,自定义一个比较大小的函数
 * 比较两个字符串s1, s2大小的时候,先将它们拼接起来
 * 比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面
 * 所以按这个规则,s2就应该排在s1前面。
 * 
 * */
public class MinArrayNumber {
     public String PrintMinNumber(int [] numbers) {
            String str="";
            for(int i=0;i<numbers.length;i++) {
                for(int j=i+1;j<numbers.length;j++) {
                    int a=Integer.valueOf(numbers[i]+""+numbers[j]);
                    int b=Integer.valueOf(numbers[j]+""+numbers[i]);
                    if(a>b) {
                        int t=numbers[i];
                        numbers[i]=numbers[j];
                        numbers[j]=t;
                    }
                }
            }
            for(int i=0;i<numbers.length;i++) {
                str+=String.valueOf(numbers[i]);
            }
            return str;
     }
     public static void main(String[]args) {
         MinArrayNumber solution=new MinArrayNumber();
         int[] num= {3,32,321};
         String str=solution.PrintMinNumber(num);
         System.out.println(str);
     }
}

29、定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

package cn.ctgu.offer;
import java.util.Iterator;
import java.util.Stack;
/*
 * 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
 * 
 * 
 * 
 * 
 * */
public class MinStack {
    Stack<Integer> stack=new Stack<Integer>();
    public void push(int node) {
        stack.push(node);
    }

    public void pop() {
        stack.pop();
    }

    public int top() {
        return stack.peek(); //栈顶元素(也就是最后一个元素)
    }

    public int min() {
        int min = stack.peek();
        int tmp=0;
        Iterator<Integer> iterator = stack.iterator();
        while (iterator.hasNext()){
            tmp = iterator.next();
            if (min>tmp){
                min = tmp;
            }
        }
        return min;
    }
}

30、地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

package cn.ctgu.offer;
/*
 * 题目:
 * 地上有一个m行和n列的方格。
 * 一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格
 * 但是不能进入行坐标和列坐标的数位之和大于k的格子。
 * 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
 * 但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
 * 
 * 思路:
 * 1、回溯法
 * 2、从(0,0)开始走,每成功走一步标记当前位置为true,然后从当前位置往四个方向探索
 *   返回1+4个方向的探索值之和
 * 3、探索时,判断当前结点是否可达的标准为:
 *      1)当前结点在矩阵内
 *      2)当前结点未被访问过
 *      3)当前结点满足limit限制
 * 
 * */
public class MoveCount {
    public int movingCount(int threshold, int rows, int cols) {
        boolean[][]visited=new boolean[rows][cols];
        return countingSteps(threshold,rows,cols,0,0,visited);
    }

    private int countingSteps(int limit, int rows, int cols, int r, int c, boolean[][] visited) {

        if(r<0||r>=rows||c<0||c>=cols||visited[r][c]||bitSum(r)+bitSum(c)>limit)
            return 0;
        visited[r][c]=true;

        return countingSteps(limit,rows,cols,r - 1,c,visited)
                            + countingSteps(limit,rows,cols,r,c - 1,visited)
                            + countingSteps(limit,rows,cols,r + 1,c,visited)
                            + countingSteps(limit,rows,cols,r,c + 1,visited)
                            + 1;
    }

    private int bitSum(int t) {
        int count=0;
        while(t!=0) {
            count=count+t%10;
            t=t/10;
        }
        return count;
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值