剑指Offer第八章面试题(Java版)

面试题51:数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

public class Solution {
    /**
     *
     * @param numbers       an array of integers
     * @param length        the length of array numbers
     * @param duplication   这里要特别注意~返回任意重复的一个,赋值duplication[0]
     * @return
     */
    public boolean duplicate(int numbers[],int length,int [] duplication) {

        if(numbers==null||numbers.length==0){
            return false;
        }

        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i]<0 || numbers[i]>=numbers.length) {
                return false;
            }
        }

        for (int i = 0; i < numbers.length; i++) {
            while (numbers[i]!=i) {
                if (numbers[i] != numbers[numbers[i]]) {
                    int temp = numbers[i];
                    numbers[i] = numbers[temp];
                    numbers[temp] = temp;
                }else {
                    duplication[0] = numbers[i];
                    return true;
                }
            }
        }
        return false;
    }
}

面试题52:构建乘积数组

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    /**
     * c[i] = a[0]*a[1]*a[2]*...*a[i-1] ==  c[i]=c[i-1]*a[i-1]
     * d[i] = a[i+1]*a[i+1]*...*a[n-1]  ==  d[i]=d[i+1]*a[i+1]
     * @param A
     * @return
     */
    public int[] multiply(int[] A) {

        if (A==null||A.length<1) {
            return null;
        }

        int[] B = new int[A.length];

        //初始化c[0]=1
        B[0] = 1;
        for (int i = 1; i < A.length; i++) {
            //相当于c[i] = c[i-1]*a[i-1]
            B[i] = B[i-1]*A[i-1];
        }

        //初始化d[a.length-1]=1
        int temp = 1;

        //最后一项
        B[A.length-1] =B[A.length-1] * temp;

        for (int i = A.length-2; i >= 0 ; i--) {
            //d[i]=d[i+1]*a[i+1]
            temp *= A[i+1];
            //b = c*d
            B[i] *= temp;
        }
        return B;
    }
}

面试题53正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

public class Solution {

    public boolean match(char[] str, char[] pattern)
    {
        if (str==null||pattern==null) {
            return false;
        }
        if (str.length==0&&pattern.length==0) {
            return true;
        }
        return matchCore(str,0,pattern,0);  
    }


    public boolean matchCore(char[] str,int m,char[] pattern,int n){
        //主串和模式串都到末尾了
        if (m==str.length&&n==pattern.length) {
            return true;
        }

        //主串还有,模式串没有了
        if (m!=str.length&&n==pattern.length) {
            return false;
        }

        if (n+1<pattern.length&&pattern[n+1]=='*') {//查看第二个字符是否是'*'

            //主串与模式串匹配
            if (m<str.length && (pattern[n]=='.' || pattern[n] == str[m])) {
                //abc  ab*d
                return matchCore(str, m+1, pattern, n+2)||  //move on the next state    c与d比较
                        matchCore(str, m+1, pattern, n)||   //stay on the current state c与b比较
                        matchCore(str, m, pattern, n+2);    //ignore a '*'      b与d比较
            }else {//主串与模式串不匹配
                //ignore a '*'    b与d比较
                return matchCore(str, m, pattern, n+2);
            }
        }

        if (m<str.length&&str[m]==pattern[n]||pattern[n]=='.') {
            return matchCore(str, m+1, pattern, n+1);
        }

        return false;
    }
}
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        boolean flag =  Pattern.matches(new String(pattern),new String(str)) ;
        return flag;
    }
}

面试题54:表示数值的字符串

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

public class Solution {
    public boolean isNumeric(char[] str) {
        if (str==null) {
            return false;
        }
        //保存下标
        int[] index = new int[1];
        index[0] = 0;

        if (str[index[0]]=='+'||str[index[0]]=='-') {
            index[0]++;
        }

        //判断是否结束了
        if (index[0]==str.length) {
            return false;
        }

        boolean flag = true;//先假设为真

        while (str.length!=index[0]&&str[index[0]]>='0'&&str[index[0]]<='9') {
            index[0]++;
        }

        if (str.length != index[0]) {//表示数组还未结束
            if (str[index[0]]=='.') {//for floats
                ++index[0];

                while (str.length!=index[0]&&str[index[0]]>='0'&&str[index[0]]<='9') {
                    index[0]++;
                }
                if (str.length==index[0]) {
                    return true;
                }

                if (str[index[0]]=='e'||str[index[0]]=='E') {
                    flag = isExponential(str, index);
                }
            }else if (str[index[0]]=='e'||str[index[0]]=='E') {
                flag = isExponential(str, index);
            }else {
                flag = false;
            }
        }
        return flag && (str.length == index[0]);
    }

    public boolean isExponential(char[] str,int[] index){

        index[0]++;

        if (str.length==index[0]) {
            return false;
        }

        if (str[index[0]]=='+'||str[index[0]]=='-') {
            index[0]++;
        }

        if (str.length==index[0]) {
            return false;
        }

        while (str.length!=index[0]&&str[index[0]]>='0'&&str[index[0]]<='9') {
            index[0]++;
        }

        return index[0]==str.length?true:false;
    }
}

面试题55:字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。

public class Solution {
    int[] chs = new int[256];
    int index;

    public Solution(){
        //初始化状态
        for (int i = 0; i < chs.length; i++) {
            chs[i] = -1;
        }
        index = 0;
    }

    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if (chs[ch]==-1) {//表示第一次
            chs[ch] = index;//存储该值的下标
        }else if (chs[ch]>=0) {//表示已经存储过值的下表了
            chs[ch] = -2;//表示已经不止一次出现了。
        }
        index++;
    }

    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        char ch='#';
        int minIndex = Integer.MAX_VALUE;
        for (int i = 0; i < 256; i++) {
            //chs[i]>=0表示该字符只存在一次
            if (chs[i]>=0&&chs[i]<minIndex) {
                ch = (char)i;
                minIndex = chs[i];
            }
        }
        return ch;
    }
}

面试题56:链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    static int loopNum=0;//确定环中节点数

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode meetingNode = MeetingNode(pHead);
        if (meetingNode==null) {
            return null;
        }

        ListNode enterNode = pHead;

        while (enterNode!=meetingNode) {
            meetingNode = meetingNode.next;
            enterNode = enterNode.next;
        }

        return enterNode;
    }


    //找到快慢链表的相交点
    public ListNode MeetingNode(ListNode pHead){

        if (pHead==null) {
            return null;
        }

        ListNode slow = pHead;
        ListNode fast = pHead;

        //快慢链表先各自移动一步
        slow = slow.next;
        if(slow==null){
            return null;
        }
        fast = slow.next;
        loopNum++;

        while (slow!=null&&fast!=null) {
            if (fast==slow) {//表示快节点与慢节点相遇,说明快节点不慢节点多走一圈
                return fast;
            }
            slow = slow.next;
            fast = fast.next;
            if (fast!=null) {
                fast = fast.next;
            }
            loopNum++;
        }

        return null;
    }
}

面试题57:删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead==null){
            return null;
        }

        ListNode preNode = null;//前一个节点
        ListNode currNode = pHead;//当前节点

        while(currNode != null){
            ListNode nextNode = currNode.next;//下一个节点
            boolean needDelete = false;

            //表明需要删除
            if (nextNode != null && nextNode.val == currNode.val) {
                needDelete = true;
            }

            if (!needDelete) {//表示下一个节点为空或 当前节点与下一个节点的值相等
                preNode = currNode;
                currNode = currNode.next;
            }else {//需要删除
                int value = currNode.val;//暂存重复节点的值

                ListNode delNode = currNode;

                while (delNode != null && delNode.val == value) {
                    nextNode = delNode.next;

                    delNode = null;

                    delNode = nextNode;
                }

                if (preNode==null) {//判断删除的是否是头结点
                    pHead = nextNode;
                }else {
                    preNode.next = nextNode;
                }
                currNode = nextNode;
            }
        }

        return pHead;
    }
}

面试题58:二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    /**
     * 1、当前节点有右子节点,那么它的下一节点就是右子节点的最左子节点
     * 2、如果当前节点无右子节点,但他是父节点的左子节点,那么它的下一节点就是父节点
     * 3、如果当前节点无右子节点,但他是父节点的右子节点,那么它的下一节点就是沿着父节点
     * 的指针一直往上遍历,直到找到一个它的父节点是左子节点的节点,该节点的父节点就是下一个节点。
     */
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if (pNode==null) {
            return null;
        }

        TreeLinkNode pNext = null;

        if (pNode.right!=null) {
            TreeLinkNode pRight = pNode.right;
            while (pRight.left!=null) {
                pRight = pRight.left;
            }
            pNext = pRight;
        }else if(pNode.next!=null){//无右子节点,有父节点
            TreeLinkNode pCurrent = pNode;
            TreeLinkNode pParent = pNode.next;

            //如果当前节点是父节点的右节点,迭代找到当前节点是父节点的左子节点。
            while (pParent!=null && pCurrent == pParent.right) {
                pCurrent = pParent;
                pParent = pParent.next;
            }

            pNext = pParent;
        }
        return pNext;
    }
}

面试题59:对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        return isSymmetricalCore( pRoot, pRoot);
    }

    /**
     * @param pRoot1  根左右
     * @param pRoot2  根右左
     */
    public boolean isSymmetricalCore(TreeNode pRoot1,TreeNode pRoot2){
        if (pRoot1==null&&pRoot2==null) {
            return true;
        }
        if (pRoot1==null||pRoot2==null) {
            return false;
        }
        if (pRoot1.val!=pRoot2.val) {
            return false;
        }
        return isSymmetricalCore(pRoot1.left, pRoot2.right)&&
                isSymmetricalCore(pRoot1.right, pRoot2.left);
    }
}

面试题60:把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {

        Queue<TreeNode> queue = new ArrayDeque<>();

        //存储多行的数据
        ArrayList<ArrayList<Integer>> arrayLists = new ArrayList<>();

        //存储每一行的数据
        ArrayList<Integer> arrayList = new ArrayList<>();

        if (pRoot==null) {
            return arrayLists;
        }

        TreeNode tempNode = pRoot;

        queue.add(tempNode);
        int level = 0;
        int printNum = 1;

        while (!queue.isEmpty()) {
            tempNode = queue.poll();

            arrayList.add(tempNode.val);
            --printNum;

            if (tempNode.left!=null) {
                queue.add(tempNode.left);
                level++;
            }
            if (tempNode.right!=null) {
                queue.add(tempNode.right);
                level++;
            }

            if (printNum==0) {
                arrayLists.add(arrayList);

                //arrayList.clear();//不能清空,清空了arrayLists里面元素也没有了
                arrayList = new ArrayList<>();
                printNum = level;
                level = 0;
            }

        }

        return arrayLists;
    }
}

面试题61:按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {

        //定义双向队列
        Deque<TreeNode> deque = new ArrayDeque<>();

        //存储多行的数据
        ArrayList<ArrayList<Integer>> arrayLists = new ArrayList<>();

        //存储每一行的数据
        ArrayList<Integer> arrayList = new ArrayList<>();

        if (pRoot==null) {
            return arrayLists;
        }
        //判断奇数层还是偶数层
        boolean flag = true; //初始化为奇数层

        TreeNode tempNode = pRoot;

        deque.addLast(tempNode);
        int levelnum = 0;//当前层的数目
        int printNum = 1;
        while (!deque.isEmpty()) {

            if (flag) {//奇数层
                tempNode = deque.pollFirst();//从前面出去
                arrayList.add(tempNode.val);
                printNum--;
                if (tempNode.left!=null) {
                    deque.addLast(tempNode.left);//添加到队列后面
                    levelnum++;
                }

                if (tempNode.right!=null) {
                    deque.addLast(tempNode.right);//添加到队列后面
                    levelnum++;
                }

            }else {//偶数层
                tempNode = deque.pollLast();//从后面出去
                arrayList.add(tempNode.val);
                printNum--;

                if (tempNode.right!=null) {
                    deque.addFirst(tempNode.right);//添加到队列前面
                    levelnum++;
                }

                if (tempNode.left!=null) {
                    deque.addFirst(tempNode.left);//添加到队列前面
                    levelnum++;
                }
            }

            if (printNum==0) {
                arrayLists.add(arrayList);
                arrayList = new ArrayList<>();
                printNum = levelnum;
                levelnum = 0;
                flag = !flag;
            }

        }
        return arrayLists;
    }
}

面试题62:序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    StringBuilder stringBuilder = new StringBuilder();
    int index = -1;
    public String Serialize(TreeNode root) {
        if (root==null) {
            stringBuilder.append("$,");
            return stringBuilder.toString();
        }
        stringBuilder.append(root.val+",");
        Serialize(root.left);
        Serialize(root.right);

        return stringBuilder.toString();
    }

    public TreeNode Deserialize(String str)
    {
        String[] strs = str.split(",");

        return Deserialize(strs);
    }

    public TreeNode Deserialize(String[] str){
        index++;
        if (index >= str.length) {
            return null;
        }
        TreeNode root = null;

        if (!str[index].equals("$")) {
            root = new TreeNode(Integer.parseInt(str[index]));

            root.left = Deserialize(str);
            root.right = Deserialize(str);
        }
        return root;
    }
}

面试题63:二叉搜索树的第k个结点

给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    int curr = 0;
    TreeNode resultNode = null;//存储返回值

    TreeNode  KthNode(TreeNode pRoot, int k)
    {
        if (pRoot==null||k<1) {
            return null;
        }

        TreeNode tempNode = pRoot;

        KthNodeCore(tempNode,k,false);

        return resultNode;
    }

    /**
     * @param pRoot
     * @param k     表示第k个节点
     * @param flag  判断是否找到
     */
    public void KthNodeCore(TreeNode pRoot, int k,boolean flag){
        if (!flag&&pRoot.left!=null) {//遍历左节点
            KthNodeCore(pRoot.left, k,flag);
        }
        curr++;
        if (curr==k) {
            flag = true;
            resultNode = pRoot;
            return;
        }else if (curr>k) {
            return;
        }

        if (!flag&&pRoot.right!=null) {//遍历右节点
            KthNodeCore(pRoot.right, k,flag);
        }
    }

}

面试题64:数据流中的中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {

    public Comparator<Integer> revCmp = new Comparator<Integer>()
            {
                @Override
                public int compare(Integer left, Integer right) {
                     return right.compareTo(left);
                }
            };
    //数值表示容量
    public PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(20);
    public PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(20, revCmp);

    /**
     * 保证数据平均分配到两个堆中,因此两个堆中的数目之差不能超过1。
     * 为了实现平均分配,将总数中的偶数插入到最小堆中,将总数中的奇数插入到最大堆中。
     */
    public void Insert(Integer num) {
        if (((minHeap.size()+maxHeap.size())&1)==0) {//偶数   插入到最小堆
            //如果该值比最大堆的最大值小
            if (maxHeap.size()>0 && num<maxHeap.peek()) {
                //将该值放入最大堆
                maxHeap.add(num);
                //将最大堆的最大值弹出赋值给num
                num = maxHeap.poll();

            }
            //增加该值到最小堆
            minHeap.add(num);

        }else {//奇数 插入到最大堆
            //如果该值比最小堆的最小值大
            if(minHeap.size()>0&&num>minHeap.peek()){
                minHeap.add(num);
                num = minHeap.poll();
            }
            maxHeap.add(num);
        }
    }

    public Double GetMedian() {
        int numSize = minHeap.size()+maxHeap.size();
        if (numSize == 0) {
            return 0.0;
        }

        double midnum = 0.0;
        if ((numSize&1)==1) {
            midnum = minHeap.peek()*1.0;
        }else {
            midnum = (minHeap.peek()+maxHeap.peek())/2.0;
        }
        return midnum;
    }
}

面试题65:滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        //双向队列用于存放可能是滑动窗口最大值的下标
        Deque<Integer> deque = new ArrayDeque<>();

        //用于存放滑动窗口的最大值
        ArrayList<Integer> arrayList = new ArrayList<>();

        if (num.length>=size&&size>=1) {
            for (int i = 0; i < size; i++) {
                //队列不为空,并且新数据是否大于队列尾的数据,大于则移除队列尾的数据
                while (!deque.isEmpty()&&num[i]>num[deque.peekLast()]) {
                    deque.pollLast();
                }//注意:while循环,这里可能移除队列里面的多个值
                deque.addLast(i);//加入队列尾
            }

            for (int i = size; i < num.length; i++) {
                arrayList.add(num[deque.peekFirst()]);//加入最大值

                while(!deque.isEmpty()&&num[i]>num[deque.peekLast()]){
                    deque.pollLast();
                }

                //如果滑动窗口已经不包括这个数字了,从队列中移除。
                if (!deque.isEmpty()&&deque.peekFirst()<=(int)i-size) {
                    deque.pollFirst();
                }
                deque.addLast(i);

            }
            arrayList.add(num[deque.peekFirst()]);
        }
        return arrayList; 
    } 
}

面试题66:矩阵中的路径

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

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {

        if(matrix == null || matrix.length==0 || rows<1 ||
                cols<1 || str == null || str.length==0){//输入不合法
            return false;
        }

        boolean[][] visited = new boolean[rows][cols];
        //初始化为false
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                visited[i][j] = false;
            }
        }

        int[] pathlength = new int[1];
        pathlength[0] = 0;//保存当前字符串的下标
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if (hasPathCore(matrix, rows, cols, row, col, str, pathlength, visited)){
                    return true;
                }
            }
        }

        return false;
    }

    public static boolean hasPathCore(char[] matrix, int rows, int cols,
            int row,int col,char[] str,int[] pathlength,boolean[][] visited){

        if (pathlength[0]==str.length) {
            return true;
        }

        boolean hasPath = false;

        if (row>=0 && row<rows && col>=0 && col<cols &&
                matrix[row*cols+col]==str[pathlength[0]]&&!visited[row][col]) {
            ++pathlength[0];
            visited[row][col] = true;
            //分别递归当前元素的上下左右
            hasPath = hasPathCore(matrix, rows,cols,row-1,col,str,pathlength,visited)||
                    hasPathCore(matrix, rows,cols,row+1,col,str,pathlength,visited)||
                    hasPathCore(matrix, rows,cols,row,col-1,str,pathlength,visited)||
                    hasPathCore(matrix, rows,cols,row,col+1,str,pathlength,visited);

            if (!hasPath) {//如果当前点的上下左右 都无下一个元素,则退回
                --pathlength[0];
                visited[row][col] = false;
            }
        }

        return hasPath;
    }

}

面试题67:机器人的运动范围

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

public class Solution {
    /**
     * @param threshold 阀值
     * @param rows
     * @param cols
     * @return 返回能到达多少个格子
     */
    public int movingCount(int threshold, int rows, int cols)
    {
        boolean[][] visited = new boolean[rows][cols];//默认为false
        return movingCountCore(threshold,rows,cols,0,0,visited);
    }

    public int movingCountCore(int threshold, int rows, int cols,
            int row,int col,boolean[][] visited){

        //检测是否越界
        if(row<0 || row>=rows || col<0 || col>=cols){
            return 0;
        }

        if(visited[row][col]){//查看是否被访问过
            return 0;
        }
        //检测是否超过阀值
        if(getDigitSum(row,col,threshold)) {
            return 0;
        }

        visited[row][col] = true;

        return 1+movingCountCore(threshold,rows,cols,row-1,col,visited)+
                movingCountCore(threshold,rows,cols,row+1,col,visited)+
                movingCountCore(threshold,rows,cols,row,col-1,visited)+
                movingCountCore(threshold,rows,cols,row,col+1,visited);
    }


    public boolean getDigitSum(int row,int col,int threshold){
        int sum = 0;
        while (row>0) {
            sum += (row%10);
            row /= 10;
        }
        while (col>0) {
            sum += (col%10);
            col /= 10;
        }
        return sum>threshold?true:false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃果冻不吐果冻皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值